1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1989 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #include <stdio.h> 41 #include <libintl.h> 42 #include <locale.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <ctype.h> 46 #include <limits.h> 47 #include <wchar.h> 48 49 /* 50 * expand - expand tabs to equivalent spaces 51 */ 52 static int nstops = 0; 53 static int tabstops[100]; 54 static int isClocale; 55 56 static void getstops(const char *); 57 static void usage(void); 58 59 int 60 main(argc, argv) 61 int argc; 62 char *argv[]; 63 { 64 static char ibuf[BUFSIZ]; 65 register int c, column; 66 register int n; 67 register int i, j; 68 char *locale; 69 int flag, tflag = 0; 70 int len; 71 int p_col; 72 wchar_t wc; 73 char *p1, *p2; 74 75 (void) setlocale(LC_ALL, ""); 76 locale = setlocale(LC_CTYPE, NULL); 77 isClocale = (strcmp(locale, "C") == 0); 78 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 79 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 80 #endif 81 (void) textdomain(TEXT_DOMAIN); 82 83 /* 84 * First, look for and extract any "-<number>" args then pass 85 * them to getstops(). 86 */ 87 for (i = 1; i < argc; i++) { 88 if (strcmp(argv[i], "--") == 0) 89 break; 90 91 if (*argv[i] != '-') 92 continue; 93 if (!isdigit(*(argv[i]+1))) 94 continue; 95 96 getstops(argv[i]+1); 97 tflag++; 98 99 /* Pull this arg from list */ 100 for (j = i; j < (argc-1); j++) 101 argv[j] = argv[j+1]; 102 argc--; 103 } 104 105 while ((flag = getopt(argc, argv, "t:")) != EOF) { 106 switch (flag) { 107 case 't': 108 if (tflag) 109 usage(); 110 111 getstops(optarg); 112 break; 113 114 default: 115 usage(); 116 break; 117 } 118 } 119 120 argc -= optind; 121 argv = &argv[optind]; 122 123 do { 124 if (argc > 0) { 125 if (freopen(argv[0], "r", stdin) == NULL) { 126 perror(argv[0]); 127 exit(1); 128 /* NOTREACHED */ 129 } 130 argc--; 131 argv++; 132 } 133 134 column = 0; 135 p1 = p2 = ibuf; 136 for (;;) { 137 if (p1 >= p2) { 138 p1 = ibuf; 139 if ((len = fread(p1, 1, BUFSIZ, stdin)) <= 0) 140 break; 141 p2 = p1 + len; 142 } 143 144 c = *p1++; 145 switch (c) { 146 case '\t': 147 if (nstops == 0) { 148 do { 149 (void) putchar(' '); 150 column++; 151 } while (column & 07); 152 continue; 153 } 154 if (nstops == 1) { 155 do { 156 (void) putchar(' '); 157 column++; 158 } while ( 159 ((column - 1) % tabstops[0]) != 160 (tabstops[0] - 1)); 161 continue; 162 } 163 for (n = 0; n < nstops; n++) 164 if (tabstops[n] > column) 165 break; 166 if (n == nstops) { 167 (void) putchar(' '); 168 column++; 169 continue; 170 } 171 while (column < tabstops[n]) { 172 (void) putchar(' '); 173 column++; 174 } 175 continue; 176 177 case '\b': 178 if (column) 179 column--; 180 (void) putchar('\b'); 181 continue; 182 183 default: 184 if (isClocale) { 185 (void) putchar(c); 186 column++; 187 continue; 188 } 189 190 if (isascii(c)) { 191 (void) putchar(c); 192 column++; 193 continue; 194 } 195 196 p1--; 197 if ((len = (p2 - p1)) < 198 (unsigned int)MB_CUR_MAX) { 199 for (n = 0; n < len; n++) 200 ibuf[n] = *p1++; 201 p1 = ibuf; 202 p2 = p1 + n; 203 if ((len = fread(p2, 1, BUFSIZ - n, 204 stdin)) > 0) 205 p2 += len; 206 } 207 if ((len = (p2 - p1)) > 208 (unsigned int)MB_CUR_MAX) 209 len = (unsigned int)MB_CUR_MAX; 210 211 if ((len = mbtowc(&wc, p1, len)) <= 0) { 212 (void) putchar(c); 213 column++; 214 p1++; 215 continue; 216 } 217 218 if ((p_col = wcwidth(wc)) < 0) 219 p_col = len; 220 p1 += len; 221 (void) putwchar(wc); 222 column += p_col; 223 continue; 224 225 case '\n': 226 (void) putchar(c); 227 column = 0; 228 continue; 229 } 230 } 231 } while (argc > 0); 232 233 return (0); 234 /* NOTREACHED */ 235 } 236 237 static void 238 getstops(const char *cp) 239 { 240 register int i; 241 242 for (;;) { 243 i = 0; 244 while (*cp >= '0' && *cp <= '9') 245 i = i * 10 + *cp++ - '0'; 246 247 if (i <= 0 || i > INT_MAX) { 248 (void) fprintf(stderr, gettext( 249 "expand: invalid tablist\n")); 250 usage(); 251 } 252 253 if (nstops > 0 && i <= tabstops[nstops-1]) { 254 (void) fprintf(stderr, gettext( 255 "expand: tablist must be increasing\n")); 256 usage(); 257 } 258 259 tabstops[nstops++] = i; 260 if (*cp == 0) 261 break; 262 263 if (*cp != ',' && *cp != ' ') { 264 (void) fprintf(stderr, gettext( 265 "expand: invalid tablist\n")); 266 usage(); 267 } 268 cp++; 269 } 270 } 271 272 static void 273 usage(void) 274 { 275 (void) fprintf(stderr, gettext( 276 "usage: expand [-t tablist] [file ...]\n" 277 " expand [-tabstop] [-tab1,tab2,...,tabn] [file ...]\n")); 278 exit(2); 279 /* NOTREACHED */ 280 } 281