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 /* 43 * unexpand - put tabs into a file replacing blanks 44 */ 45 #include <stdio.h> 46 #include <limits.h> 47 #include <stdlib.h> 48 #include <locale.h> 49 #include <libintl.h> 50 #include <wchar.h> 51 52 #define INPUT_SIZ LINE_MAX /* POSIX.2 */ 53 #define MAX_TABS 100 /* maximum number of tabstops */ 54 55 static int nstops = 0; /* total number of tabstops */ 56 static int tabstops[MAX_TABS]; /* the tabstops themselves */ 57 58 static void tabify(wchar_t *, int); 59 static void getstops(const char *); 60 static void usage(void); 61 62 int 63 main(argc, argv) 64 int argc; 65 char *argv[]; 66 { 67 int flag; /* option flag read by getopt() */ 68 int all = 0; /* -a flag */ 69 int status = 0; 70 wchar_t input_buf[INPUT_SIZ+1]; 71 72 (void) setlocale(LC_ALL, ""); 73 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 74 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 75 #endif 76 (void) textdomain(TEXT_DOMAIN); 77 78 while ((flag = getopt(argc, argv, "at:")) != EOF) { 79 switch (flag) { 80 case 'a': 81 all++; 82 break; 83 84 case 't': /* POSIX.2 */ 85 all++; /* -t turns on -a */ 86 getstops(optarg); 87 break; 88 89 default: 90 usage(); 91 break; 92 } 93 } 94 95 argc -= optind; 96 argv = &argv[optind]; 97 98 do { 99 if (argc > 0) { 100 if (freopen(argv[0], "r", stdin) == NULL) { 101 (void) fprintf(stderr, "unexpand: "); 102 perror(argv[0]); 103 status++; 104 } 105 argc--, argv++; 106 } 107 108 while (fgetws(input_buf, INPUT_SIZ, stdin) != NULL) { 109 input_buf[INPUT_SIZ] = 0; 110 tabify(input_buf, all); 111 } 112 } while (argc > 0); 113 114 return (status); 115 /* NOTREACHED */ 116 } 117 118 void 119 tabify(wchar_t *ibuf, int all) 120 { 121 wchar_t *cp; /* current position in ibuf */ 122 int ocol = 0; /* current output column */ 123 int cstop = 0; /* current tabstop */ 124 int spaces = 0; /* spaces to convert to tab */ 125 int p_col; 126 127 cp = ibuf; 128 129 for (;;) { 130 switch (*cp) { 131 case ' ': 132 cp++; 133 134 spaces++; 135 ocol++; 136 137 if (nstops == 0) { /* default tab = 8 */ 138 if ((ocol & 7) != 0) 139 break; 140 } else if (nstops == 1) { /* tab width */ 141 if ((ocol % tabstops[0]) != 0) 142 break; 143 } else { /* explicit tabstops */ 144 while (cstop < nstops && 145 ocol > tabstops[cstop]) 146 cstop++; 147 148 if (cstop >= nstops) { 149 (void) putchar(' '); 150 spaces = 0; 151 break; 152 } 153 154 if (ocol != tabstops[cstop]) 155 break; 156 cstop++; 157 } 158 159 /* 160 * if we get to this point, we must be at a 161 * tab stop. if spaces, then write out a tab. 162 */ 163 if (spaces > 0) { 164 (void) putchar(((spaces > 1) ? '\t' : ' ')); 165 spaces = 0; 166 } 167 168 break; 169 170 case '\b': /* POSIX.2 */ 171 while (spaces-- > 0) 172 (void) putchar(' '); 173 spaces = 0; 174 175 cp++; 176 (void) putchar('\b'); 177 178 if (--ocol < 0) 179 ocol = 0; 180 181 /* just in case */ 182 cstop = 0; 183 break; 184 185 case '\t': 186 cp++; 187 (void) putchar('\t'); 188 189 /* adjust ocol to current tabstop */ 190 if (nstops == 0) { 191 ocol = (ocol + 8) & ~07; 192 } else if (nstops == 1) { 193 ocol += ocol % tabstops[0]; 194 } else { 195 if (cstop < nstops && 196 ocol < tabstops[cstop]) 197 ocol = tabstops[cstop++]; 198 else 199 ocol++; 200 } 201 202 spaces = 0; 203 break; 204 205 default: 206 while (spaces-- > 0) 207 (void) putchar(' '); 208 spaces = 0; 209 210 if (*cp == 0 || *cp == '\n' || all == 0) { 211 /* 212 * either end of input line or -a not set 213 */ 214 while (*cp != 0) 215 (void) putwchar(*cp++); 216 return; 217 } 218 219 (void) putwchar(*cp++); 220 if ((p_col = wcwidth(*cp)) < 0) 221 p_col = 0; 222 ocol += p_col; 223 break; 224 } 225 } 226 } 227 228 static void 229 getstops(const char *cp) 230 { 231 register int i; 232 233 for (;;) { 234 i = 0; 235 while (*cp >= '0' && *cp <= '9') 236 i = i * 10 + *cp++ - '0'; 237 238 if (i <= 0 || i > INT_MAX) { 239 (void) fprintf(stderr, gettext( 240 "unexpand: invalid tablist item\n")); 241 usage(); 242 } 243 244 if (nstops > 0 && i <= tabstops[nstops-1]) { 245 (void) fprintf(stderr, gettext( 246 "unexpand: tablist must be increasing\n")); 247 usage(); 248 } 249 250 if (nstops == MAX_TABS) { 251 (void) fprintf(stderr, gettext( 252 "unexpand: number of tabstops limited to %d\n"), 253 MAX_TABS); 254 usage(); 255 } 256 257 tabstops[nstops++] = i; 258 if (*cp == 0) 259 break; 260 if (*cp != ',' && *cp != ' ') { 261 (void) fprintf(stderr, gettext( 262 "unexpand: invalid tablist separator\n")); 263 usage(); 264 } 265 266 cp++; 267 } 268 } 269 270 static void 271 usage(void) 272 { 273 (void) fprintf(stderr, gettext( 274 "usage: unexpand [-a ] [-t tablist] [file ...]\n")); 275 exit(2); 276 /* NOTREACHED */ 277 } 278