unexpand.c revision 102944
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3487697Smarkm#include <sys/cdefs.h> 3587697Smarkm 3687697Smarkm__FBSDID("$FreeBSD: head/usr.bin/unexpand/unexpand.c 102944 2002-09-04 23:29:10Z dwmalone $"); 3787697Smarkm 381590Srgrimes#ifndef lint 3928456Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1980, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287697Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587697Smarkmstatic const char sccsid[] = "@(#)unexpand.c 8.1 (Berkeley) 6/6/93"; 4628456Scharnier#endif 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * unexpand - put tabs into a file replacing blanks 501590Srgrimes */ 5198251Stjr#include <ctype.h> 5228456Scharnier#include <err.h> 5395304Stjr#include <limits.h> 5498251Stjr#include <locale.h> 551590Srgrimes#include <stdio.h> 5678717Sdd#include <stdlib.h> 5733645Sjb#include <string.h> 5895304Stjr#include <unistd.h> 591590Srgrimes 601590Srgrimesint all; 6195304Stjrint nstops; 6295304Stjrint tabstops[100]; 631590Srgrimes 6495304Stjrstatic void getstops(const char *); 6592922Simpstatic void usage(void); 6695304Stjrstatic void tabify(void); 6728456Scharnier 6828789Scharnierint 69102944Sdwmalonemain(int argc, char *argv[]) 701590Srgrimes{ 7195474Stjr int ch, failed; 7295474Stjr char *filename; 731590Srgrimes 7498251Stjr setlocale(LC_CTYPE, ""); 7598251Stjr 7695304Stjr nstops = 1; 7795304Stjr tabstops[0] = 8; 7895304Stjr while ((ch = getopt(argc, argv, "at:")) != -1) { 7995304Stjr switch (ch) { 8095304Stjr case 'a': /* Un-expand all spaces, not just leading. */ 8195304Stjr all = 1; 8295304Stjr break; 8395304Stjr case 't': /* Specify tab list, implies -a. */ 8495304Stjr getstops(optarg); 8595304Stjr all = 1; 8695304Stjr break; 8795304Stjr default: 8828456Scharnier usage(); 8995304Stjr /*NOTREACHED*/ 9095304Stjr } 911590Srgrimes } 9295304Stjr argc -= optind; 9395304Stjr argv += optind; 9495304Stjr 9595474Stjr failed = 0; 9695474Stjr if (argc == 0) 9795474Stjr tabify(); 9895474Stjr else { 9995474Stjr while ((filename = *argv++) != NULL) { 10095474Stjr if (freopen(filename, "r", stdin) == NULL) { 10195474Stjr warn("%s", filename); 10295474Stjr failed++; 10395474Stjr } else 10495474Stjr tabify(); 1051590Srgrimes } 10695474Stjr } 10795474Stjr exit(failed != 0); 1081590Srgrimes} 1091590Srgrimes 11028456Scharnierstatic void 111102944Sdwmaloneusage(void) 11228456Scharnier{ 11395304Stjr fprintf(stderr, "usage: unexpand [-a] [-t tablist] [file ...]\n"); 11428456Scharnier exit(1); 11528456Scharnier} 11628456Scharnier 11795304Stjrstatic void 118102944Sdwmalonetabify(void) 1191590Srgrimes{ 12095304Stjr int ch, dcol, doneline, limit, n, ocol; 1211590Srgrimes 12295304Stjr limit = nstops == 1 ? INT_MAX : tabstops[nstops - 1] - 1; 1231590Srgrimes 12495304Stjr doneline = ocol = dcol = 0; 12595304Stjr while ((ch = getchar()) != EOF) { 12695474Stjr if (ch == ' ' && !doneline) { 12795304Stjr if (++dcol >= limit) 12895304Stjr doneline = 1; 12995304Stjr continue; 13095304Stjr } else if (ch == '\t') { 13195304Stjr if (nstops == 1) { 13295304Stjr dcol = (1 + dcol / tabstops[0]) * 13395304Stjr tabstops[0]; 13495304Stjr continue; 13595304Stjr } else { 13695304Stjr for (n = 0; tabstops[n] - 1 < dcol && 13795304Stjr n < nstops; n++) 13895304Stjr ; 13995304Stjr if (n < nstops - 1 && tabstops[n] - 1 < limit) { 14095304Stjr dcol = tabstops[n]; 14195304Stjr continue; 14295304Stjr } 14395304Stjr doneline = 1; 14495304Stjr } 14595304Stjr } 1461590Srgrimes 14795304Stjr /* Output maximal number of tabs. */ 14895304Stjr if (nstops == 1) { 14995304Stjr while (((ocol + tabstops[0]) / tabstops[0]) 15095304Stjr <= (dcol / tabstops[0])) { 15195304Stjr if (dcol - ocol < 2) 1521590Srgrimes break; 15395304Stjr putchar('\t'); 15495304Stjr ocol = (1 + ocol / tabstops[0]) * 15595304Stjr tabstops[0]; 1561590Srgrimes } 15795304Stjr } else { 15895304Stjr for (n = 0; tabstops[n] - 1 < ocol && n < nstops; n++) 15995304Stjr ; 16095304Stjr while (ocol < dcol && n < nstops && ocol < limit) { 16195304Stjr putchar('\t'); 16295304Stjr ocol = tabstops[n++]; 1631590Srgrimes } 16495304Stjr } 16595304Stjr 16695304Stjr /* Then spaces. */ 16795304Stjr while (ocol < dcol && ocol < limit) { 16895304Stjr putchar(' '); 16995304Stjr ocol++; 17095304Stjr } 17195304Stjr 17295474Stjr if (ch == '\b') { 17395474Stjr putchar('\b'); 17495474Stjr if (ocol > 0) 17595474Stjr ocol--, dcol--; 17695474Stjr } else if (ch == '\n') { 17795474Stjr putchar('\n'); 17895474Stjr doneline = ocol = dcol = 0; 17995474Stjr } else if (ch != ' ' || dcol > limit) { 18095304Stjr putchar(ch); 18198251Stjr if (isprint(ch)) 18298251Stjr ocol++, dcol++; 1831590Srgrimes } 18495304Stjr 18595304Stjr /* 18695304Stjr * Only processing leading blanks or we've gone past the 18795304Stjr * last tab stop. Emit remainder of this line unchanged. 18895304Stjr */ 18995304Stjr if (!all || dcol >= limit) { 19095304Stjr while ((ch = getchar()) != '\n' && ch != EOF) 19195304Stjr putchar(ch); 19295304Stjr if (ch == '\n') 19395474Stjr putchar('\n'); 19495474Stjr doneline = ocol = dcol = 0; 19595304Stjr } 19695304Stjr } 19795304Stjr} 19895304Stjr 19995304Stjrstatic void 200102944Sdwmalonegetstops(const char *cp) 20195304Stjr{ 20295304Stjr int i; 20395304Stjr 20495304Stjr nstops = 0; 20595304Stjr for (;;) { 20695304Stjr i = 0; 20795304Stjr while (*cp >= '0' && *cp <= '9') 20895304Stjr i = i * 10 + *cp++ - '0'; 20995304Stjr if (i <= 0) 21095304Stjr errx(1, "bad tab stop spec"); 21195304Stjr if (nstops > 0 && i <= tabstops[nstops-1]) 21295304Stjr errx(1, "bad tab stop spec"); 21395304Stjr if (nstops == sizeof(tabstops) / sizeof(*tabstops)) 21495304Stjr errx(1, "too many tab stops"); 21595304Stjr tabstops[nstops++] = i; 21695304Stjr if (*cp == 0) 21795304Stjr break; 21898251Stjr if (*cp != ',' && !isblank((unsigned char)*cp)) 21995304Stjr errx(1, "bad tab stop spec"); 2201590Srgrimes cp++; 2211590Srgrimes } 2221590Srgrimes} 223