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 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <stdio.h> 43 #include <libintl.h> 44 #include <locale.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <ctype.h> 48 #include <limits.h> 49 #include <wchar.h> 50 51 /* 52 * expand - expand tabs to equivalent spaces 53 */ 54 static int nstops = 0; 55 static int tabstops[100]; 56 static int isClocale; 57 58 static void getstops(const char *); 59 static void usage(void); 60 61 int 62 main(argc, argv) 63 int argc; 64 char *argv[]; 65 { 66 static char ibuf[BUFSIZ]; 67 register int c, column; 68 register int n; 69 register int i, j; 70 char *locale; 71 int flag, tflag = 0; 72 int len; 73 int p_col; 74 wchar_t wc; 75 char *p1, *p2; 76 77 (void) setlocale(LC_ALL, ""); 78 locale = setlocale(LC_CTYPE, NULL); 79 isClocale = (strcmp(locale, "C") == 0); 80 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 81 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 82 #endif 83 (void) textdomain(TEXT_DOMAIN); 84 85 /* 86 * First, look for and extract any "-<number>" args then pass 87 * them to getstops(). 88 */ 89 for (i = 1; i < argc; i++) { 90 if (strcmp(argv[i], "--") == 0) 91 break; 92 93 if (*argv[i] != '-') 94 continue; 95 if (!isdigit(*(argv[i]+1))) 96 continue; 97 98 getstops(argv[i]+1); 99 tflag++; 100 101 /* Pull this arg from list */ 102 for (j = i; j < (argc-1); j++) 103 argv[j] = argv[j+1]; 104 argc--; 105 } 106 107 while ((flag = getopt(argc, argv, "t:")) != EOF) { 108 switch (flag) { 109 case 't': 110 if (tflag) 111 usage(); 112 113 getstops(optarg); 114 break; 115 116 default: 117 usage(); 118 break; 119 } 120 } 121 122 argc -= optind; 123 argv = &argv[optind]; 124 125 do { 126 if (argc > 0) { 127 if (freopen(argv[0], "r", stdin) == NULL) { 128 perror(argv[0]); 129 exit(1); 130 /* NOTREACHED */ 131 } 132 argc--; 133 argv++; 134 } 135 136 column = 0; 137 p1 = p2 = ibuf; 138 for (;;) { 139 if (p1 >= p2) { 140 p1 = ibuf; 141 if ((len = fread(p1, 1, BUFSIZ, stdin)) <= 0) 142 break; 143 p2 = p1 + len; 144 } 145 146 c = *p1++; 147 switch (c) { 148 case '\t': 149 if (nstops == 0) { 150 do { 151 (void) putchar(' '); 152 column++; 153 } while (column & 07); 154 continue; 155 } 156 if (nstops == 1) { 157 do { 158 (void) putchar(' '); 159 column++; 160 } while ( 161 ((column - 1) % tabstops[0]) != 162 (tabstops[0] - 1)); 163 continue; 164 } 165 for (n = 0; n < nstops; n++) 166 if (tabstops[n] > column) 167 break; 168 if (n == nstops) { 169 (void) putchar(' '); 170 column++; 171 continue; 172 } 173 while (column < tabstops[n]) { 174 (void) putchar(' '); 175 column++; 176 } 177 continue; 178 179 case '\b': 180 if (column) 181 column--; 182 (void) putchar('\b'); 183 continue; 184 185 default: 186 if (isClocale) { 187 (void) putchar(c); 188 column++; 189 continue; 190 } 191 192 if (isascii(c)) { 193 (void) putchar(c); 194 column++; 195 continue; 196 } 197 198 p1--; 199 if ((len = (p2 - p1)) < 200 (unsigned int)MB_CUR_MAX) { 201 for (n = 0; n < len; n++) 202 ibuf[n] = *p1++; 203 p1 = ibuf; 204 p2 = p1 + n; 205 if ((len = fread(p2, 1, BUFSIZ - n, 206 stdin)) > 0) 207 p2 += len; 208 } 209 if ((len = (p2 - p1)) > 210 (unsigned int)MB_CUR_MAX) 211 len = (unsigned int)MB_CUR_MAX; 212 213 if ((len = mbtowc(&wc, p1, len)) <= 0) { 214 (void) putchar(c); 215 column++; 216 p1++; 217 continue; 218 } 219 220 if ((p_col = wcwidth(wc)) < 0) 221 p_col = len; 222 p1 += len; 223 (void) putwchar(wc); 224 column += p_col; 225 continue; 226 227 case '\n': 228 (void) putchar(c); 229 column = 0; 230 continue; 231 } 232 } 233 } while (argc > 0); 234 235 return (0); 236 /* NOTREACHED */ 237 } 238 239 static void 240 getstops(const char *cp) 241 { 242 register int i; 243 244 for (;;) { 245 i = 0; 246 while (*cp >= '0' && *cp <= '9') 247 i = i * 10 + *cp++ - '0'; 248 249 if (i <= 0 || i > INT_MAX) { 250 (void) fprintf(stderr, gettext( 251 "expand: invalid tablist\n")); 252 usage(); 253 } 254 255 if (nstops > 0 && i <= tabstops[nstops-1]) { 256 (void) fprintf(stderr, gettext( 257 "expand: tablist must be increasing\n")); 258 usage(); 259 } 260 261 tabstops[nstops++] = i; 262 if (*cp == 0) 263 break; 264 265 if (*cp != ',' && *cp != ' ') { 266 (void) fprintf(stderr, gettext( 267 "expand: invalid tablist\n")); 268 usage(); 269 } 270 cp++; 271 } 272 } 273 274 static void 275 usage(void) 276 { 277 (void) fprintf(stderr, gettext( 278 "usage: expand [-t tablist] [file ...]\n" 279 " expand [-tabstop] [-tab1,tab2,...,tabn] [file ...]\n")); 280 exit(2); 281 /* NOTREACHED */ 282 } 283