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