Home | History | Annotate | Line # | Download | only in qsubst
qsubst.c revision 1.6
      1  1.6    agc /*	$NetBSD: qsubst.c,v 1.6 2003/06/23 13:05:51 agc Exp $	*/
      2  1.2  perry 
      3  1.1  perry /*
      4  1.1  perry  * qsubst -- designed for renaming routines existing in a whole bunch
      5  1.1  perry  *  of files.  Needs -ltermcap.
      6  1.1  perry  *
      7  1.1  perry  * Usage:
      8  1.1  perry  *
      9  1.1  perry  * qsubst str1 str2 [ options ]
     10  1.1  perry  *
     11  1.1  perry  * qsubst reads its options (see below) to get a list of files.  For
     12  1.1  perry  *  each file on this list, it then replaces str1 with str2 wherever
     13  1.1  perry  *  possible in that file, depending on user input (see below).  The
     14  1.1  perry  *  result is written back onto the original file.
     15  1.1  perry  *
     16  1.1  perry  * For each possible substitution, the user is prompted with a few
     17  1.1  perry  *  lines before and after the line containing the string to be
     18  1.1  perry  *  substituted.  The string itself is displayed using the terminal's
     19  1.1  perry  *  standout mode, if any.  Then one character is read from the
     20  1.1  perry  *  terminal.  This is then interpreted as follows (this is designed to
     21  1.1  perry  *  be like Emacs' query-replace-string):
     22  1.1  perry  *
     23  1.1  perry  *	space	replace this occurrence and go on to the next one
     24  1.1  perry  *	.	replace this occurrence and don't change any more in
     25  1.1  perry  *		this file (ie, go on to the next file).
     26  1.1  perry  *	,	tentatively replace this occurrence.  The lines as they
     27  1.1  perry  *		would look if the substitution were made are printed
     28  1.1  perry  *		out.  Then another character is read and it is used to
     29  1.1  perry  *		decide the result (possibly undoing the tentative
     30  1.1  perry  *		replacement).
     31  1.1  perry  *	n	don't change this one, but go on to the next one
     32  1.1  perry  *	^G	don't change this one or any others in this file, but
     33  1.1  perry  *		instead go on to the next file.
     34  1.1  perry  *	!	change the rest in this file without asking, then go on
     35  1.1  perry  *		to the next file (at which point qsubst will start
     36  1.1  perry  *		asking again).
     37  1.1  perry  *	?	print out the current filename and ask again.
     38  1.1  perry  *
     39  1.1  perry  * The first two arguments to qsubst are always the string to replace
     40  1.1  perry  *  and the string to replace it with.  The options are as follows:
     41  1.1  perry  *
     42  1.1  perry  *	-w	The search string is considered as a C symbol; it must
     43  1.1  perry  *		be bounded by non-symbol characters.  This option
     44  1.1  perry  *		toggles.  (`w' for `word'.)
     45  1.1  perry  *	-!	Enter ! mode automatically at the beginning of each
     46  1.1  perry  *		file.
     47  1.1  perry  *	-go	Same as -!
     48  1.1  perry  *	-noask	Same as -!
     49  1.1  perry  *	-nogo	Negate -go
     50  1.1  perry  *	-ask	Negate -noask (same as -nogo)
     51  1.1  perry  *	-cN	(N is a number) Give N lines of context above and below
     52  1.1  perry  *		the line with the match when prompting the user.
     53  1.1  perry  *	-CAN	(N is a number) Give N lines of context above the line
     54  1.1  perry  *		with the match when prompting the user.
     55  1.1  perry  *	-CBN	(N is a number) Give N lines of context below the line
     56  1.1  perry  *		with the match when prompting the user.
     57  1.1  perry  *	-f filename
     58  1.1  perry  *		The filename following the -f argument is one of the
     59  1.1  perry  *		files qsubst should perform substitutions in.
     60  1.1  perry  *	-F filename
     61  1.1  perry  *		qsubst should read the named file to get the names of
     62  1.1  perry  *		files to perform substitutions in.  The names should
     63  1.1  perry  *		appear one to a line.
     64  1.1  perry  *
     65  1.1  perry  * The default amount of context is -c2, that is, two lines above and
     66  1.1  perry  *  two lines below the line with the match.
     67  1.1  perry  *
     68  1.1  perry  * Arguments not beginning with a - sign in the options field are
     69  1.1  perry  *  implicitly preceded by -f.  Thus, -f is really needed only when the
     70  1.1  perry  *  file name begins with a - sign.
     71  1.1  perry  *
     72  1.1  perry  * qsubst reads its options in order and processes files as it gets
     73  1.1  perry  *  them.  This means, for example, that a -go will affect only files
     74  1.1  perry  *  from -f or -F options appearing after the -go option.
     75  1.1  perry  *
     76  1.1  perry  * The most context you can get is ten lines each, above and below
     77  1.1  perry  *  (corresponding to -c10).
     78  1.1  perry  *
     79  1.1  perry  * Str1 is limited to 512 characters; there is no limit on the size of
     80  1.1  perry  *  str2.  Neither one may contain a NUL.
     81  1.1  perry  *
     82  1.1  perry  * NULs in the file may cause qsubst to make various mistakes.
     83  1.1  perry  *
     84  1.1  perry  * If any other program modifies the file while qsubst is running, all
     85  1.1  perry  *  bets are off.
     86  1.1  perry  *
     87  1.1  perry  * This program is in the public domain.  Anyone may use it in any way
     88  1.1  perry  *  for any purpose.  Of course, it's also up to you to determine
     89  1.1  perry  *  whether what it does is suitable for you; the above comments may
     90  1.1  perry  *  help, but I can't promise they're accurate.  It's free, and you get
     91  1.1  perry  *  what you pay for.
     92  1.1  perry  *
     93  1.1  perry  * If you find any bugs I would appreciate hearing about them,
     94  1.1  perry  *  especially if you also fix them.
     95  1.1  perry  *
     96  1.1  perry  *					der Mouse
     97  1.1  perry  *
     98  1.1  perry  *			       mouse (at) rodents.montreal.qc.ca
     99  1.1  perry  */
    100  1.6    agc #include <sys/cdefs.h>
    101  1.6    agc 
    102  1.6    agc #ifndef lint
    103  1.6    agc __RCSID("$NetBSD: qsubst.c,v 1.6 2003/06/23 13:05:51 agc Exp $");
    104  1.6    agc #endif
    105  1.1  perry 
    106  1.2  perry #include <sys/file.h>
    107  1.2  perry 
    108  1.1  perry #include <ctype.h>
    109  1.1  perry #include <errno.h>
    110  1.2  perry #include <signal.h>
    111  1.2  perry #include <stdio.h>
    112  1.1  perry #include <stdlib.h>
    113  1.1  perry #include <strings.h>
    114  1.2  perry #include <termcap.h>
    115  1.1  perry #include <termios.h>
    116  1.2  perry #include <unistd.h>
    117  1.1  perry 
    118  1.1  perry extern const char *__progname;
    119  1.1  perry 
    120  1.1  perry #define MAX_C_A 10
    121  1.1  perry #define MAX_C_B 10
    122  1.1  perry #define BUF_SIZ 1024
    123  1.1  perry 
    124  1.1  perry static int debugging;
    125  1.1  perry static FILE *tempf;
    126  1.2  perry static long tbeg;
    127  1.1  perry static FILE *workf;
    128  1.1  perry static char *str1;
    129  1.1  perry static char *str2;
    130  1.1  perry static int s1l;
    131  1.1  perry static int s2l;
    132  1.5  perry static long nls[MAX_C_A + 1];
    133  1.5  perry static char buf[(BUF_SIZ * 2) + 2];
    134  1.1  perry static char *bufp;
    135  1.1  perry static char *bufp0;
    136  1.1  perry static char *bufpmax;
    137  1.1  perry static int rahead;
    138  1.1  perry static int cabove;
    139  1.1  perry static int cbelow;
    140  1.1  perry static int wordmode;
    141  1.1  perry static int flying;
    142  1.1  perry static int flystate;
    143  1.1  perry static int allfly;
    144  1.1  perry static const char *nullstr = "";
    145  1.1  perry static int ul_;
    146  1.1  perry static char *current_file;
    147  1.1  perry static const char *beginul;
    148  1.1  perry static const char *endul;
    149  1.1  perry static char tcp_buf[1024];
    150  1.1  perry static char cap_buf[1024];
    151  1.1  perry static struct termios orig_tio;
    152  1.1  perry 
    153  1.5  perry static void
    154  1.5  perry tstp_self(void)
    155  1.1  perry {
    156  1.5  perry 	void (*old_tstp) (int);
    157  1.5  perry 	int mask;
    158  1.1  perry 
    159  1.5  perry 	mask = sigblock(0);
    160  1.5  perry 	kill(getpid(), SIGTSTP);
    161  1.5  perry 	old_tstp = signal(SIGTSTP, SIG_DFL);
    162  1.5  perry 	sigsetmask(mask & ~sigmask(SIGTSTP));
    163  1.5  perry 	signal(SIGTSTP, old_tstp);
    164  1.1  perry }
    165  1.1  perry 
    166  1.2  perry /* ARGSUSED */
    167  1.5  perry static void
    168  1.5  perry sigtstp(int sig)
    169  1.1  perry {
    170  1.5  perry 	struct termios tio;
    171  1.1  perry 
    172  1.5  perry 	if (tcgetattr(0, &tio) < 0) {
    173  1.5  perry 		tstp_self();
    174  1.5  perry 		return;
    175  1.5  perry 	}
    176  1.5  perry 	tcsetattr(0, TCSAFLUSH | TCSASOFT, &orig_tio);
    177  1.5  perry 	tstp_self();
    178  1.5  perry 	tcsetattr(0, TCSADRAIN | TCSASOFT, &tio);
    179  1.5  perry }
    180  1.5  perry 
    181  1.5  perry static void
    182  1.5  perry limit_above_below(void)
    183  1.5  perry {
    184  1.5  perry 	if (cabove > MAX_C_A) {
    185  1.5  perry 		cabove = MAX_C_A;
    186  1.5  perry 	}
    187  1.5  perry 	if (cbelow > MAX_C_B) {
    188  1.5  perry 		cbelow = MAX_C_B;
    189  1.5  perry 	}
    190  1.5  perry }
    191  1.5  perry 
    192  1.5  perry static int
    193  1.5  perry issymchar(char c)
    194  1.5  perry {
    195  1.5  perry 	return (isascii(c) && (isalnum(c) || (c == '_') || (c == '$')));
    196  1.5  perry }
    197  1.5  perry 
    198  1.5  perry static int
    199  1.5  perry foundit(void)
    200  1.5  perry {
    201  1.5  perry 	if (wordmode) {
    202  1.5  perry 		return (!issymchar(bufp[-1]) &&
    203  1.5  perry 		    !issymchar(bufp[-2 - s1l]) &&
    204  1.5  perry 		    !bcmp(bufp - 1 - s1l, str1, s1l));
    205  1.5  perry 	} else {
    206  1.5  perry 		return (!bcmp(bufp - s1l, str1, s1l));
    207  1.5  perry 	}
    208  1.5  perry }
    209  1.5  perry 
    210  1.5  perry static int
    211  1.5  perry putcharf(int c)
    212  1.5  perry {
    213  1.5  perry 	return (putchar(c));
    214  1.5  perry }
    215  1.5  perry 
    216  1.5  perry static void
    217  1.5  perry put_ul(char *s)
    218  1.5  perry {
    219  1.5  perry 	if (ul_) {
    220  1.5  perry 		for (; *s; s++) {
    221  1.5  perry 			printf("_\b%c", *s);
    222  1.5  perry 		}
    223  1.5  perry 	} else {
    224  1.5  perry 		tputs(beginul, 1, putcharf);
    225  1.5  perry 		fputs(s, stdout);
    226  1.5  perry 		tputs(endul, 1, putcharf);
    227  1.5  perry 	}
    228  1.5  perry }
    229  1.5  perry 
    230  1.5  perry static int
    231  1.5  perry getc_cbreak(void)
    232  1.5  perry {
    233  1.5  perry 	struct termios tio;
    234  1.5  perry 	struct termios otio;
    235  1.5  perry 	char c;
    236  1.5  perry 
    237  1.5  perry 	if (tcgetattr(0, &tio) < 0)
    238  1.5  perry 		return (getchar());
    239  1.5  perry 	otio = tio;
    240  1.5  perry 	tio.c_lflag &= ~(ICANON | ECHOKE | ECHOE | ECHO | ECHONL);
    241  1.5  perry 	tio.c_cc[VMIN] = 1;
    242  1.5  perry 	tio.c_cc[VTIME] = 0;
    243  1.5  perry 	tcsetattr(0, TCSANOW | TCSASOFT, &tio);
    244  1.5  perry 	switch (read(0, &c, 1)) {
    245  1.5  perry 	case -1:
    246  1.5  perry 		break;
    247  1.5  perry 	case 0:
    248  1.5  perry 		break;
    249  1.5  perry 	case 1:
    250  1.5  perry 		break;
    251  1.5  perry 	}
    252  1.5  perry 	tcsetattr(0, TCSANOW | TCSASOFT, &otio);
    253  1.5  perry 	return (c);
    254  1.5  perry }
    255  1.5  perry 
    256  1.5  perry static int
    257  1.5  perry doit(void)
    258  1.5  perry {
    259  1.5  perry 	long save;
    260  1.5  perry 	int i;
    261  1.5  perry 	int lastnl;
    262  1.5  perry 	int use_replacement;
    263  1.5  perry 
    264  1.5  perry 	if (flying) {
    265  1.5  perry 		return (flystate);
    266  1.5  perry 	}
    267  1.5  perry 	use_replacement = 0;
    268  1.5  perry 	save = ftell(workf);
    269  1.5  perry 	do {
    270  1.5  perry 		for (i = MAX_C_A - cabove; nls[i] < 0; i++);
    271  1.5  perry 		fseek(workf, nls[i], 0);
    272  1.5  perry 		for (i = save - nls[i] - rahead; i; i--) {
    273  1.5  perry 			putchar(getc(workf));
    274  1.5  perry 		}
    275  1.5  perry 		put_ul(use_replacement ? str2 : str1);
    276  1.5  perry 		fseek(workf, save + s1l - rahead, 0);
    277  1.5  perry 		lastnl = 0;
    278  1.5  perry 		i = cbelow + 1;
    279  1.5  perry 		while (i > 0) {
    280  1.5  perry 			int c;
    281  1.5  perry 			c = getc(workf);
    282  1.5  perry 			if (c == EOF) {
    283  1.5  perry 				clearerr(workf);
    284  1.5  perry 				break;
    285  1.5  perry 			}
    286  1.5  perry 			putchar(c);
    287  1.5  perry 			lastnl = 0;
    288  1.5  perry 			if (c == '\n') {
    289  1.5  perry 				i--;
    290  1.5  perry 				lastnl = 1;
    291  1.5  perry 			}
    292  1.5  perry 		}
    293  1.5  perry 		if (!lastnl)
    294  1.5  perry 			printf("\n[no final newline] ");
    295  1.5  perry 		fseek(workf, save, 0);
    296  1.5  perry 		i = -1;
    297  1.5  perry 		while (i == -1) {
    298  1.5  perry 			switch (getc_cbreak()) {
    299  1.5  perry 			case ' ':
    300  1.5  perry 				i = 1;
    301  1.5  perry 				break;
    302  1.5  perry 			case '.':
    303  1.5  perry 				i = 1;
    304  1.5  perry 				flying = 1;
    305  1.5  perry 				flystate = 0;
    306  1.5  perry 				break;
    307  1.5  perry 			case 'n':
    308  1.5  perry 				i = 0;
    309  1.5  perry 				break;
    310  1.5  perry 			case '\7':
    311  1.5  perry 				i = 0;
    312  1.5  perry 				flying = 1;
    313  1.5  perry 				flystate = 0;
    314  1.5  perry 				break;
    315  1.5  perry 			case '!':
    316  1.5  perry 				i = 1;
    317  1.5  perry 				flying = 1;
    318  1.5  perry 				flystate = 1;
    319  1.5  perry 				break;
    320  1.5  perry 			case ',':
    321  1.5  perry 				use_replacement = !use_replacement;
    322  1.5  perry 				i = -2;
    323  1.5  perry 				printf("(using %s string gives)\n",
    324  1.5  perry 				    use_replacement ? "new" : "old");
    325  1.5  perry 				break;
    326  1.5  perry 			case '?':
    327  1.5  perry 				printf("File is `%s'\n", current_file);
    328  1.5  perry 				break;
    329  1.5  perry 			default:
    330  1.5  perry 				putchar('\7');
    331  1.5  perry 				break;
    332  1.5  perry 			}
    333  1.5  perry 		}
    334  1.5  perry 	} while (i < 0);
    335  1.5  perry 	if (i) {
    336  1.5  perry 		printf("(replacing");
    337  1.5  perry 	} else {
    338  1.5  perry 		printf("(leaving");
    339  1.5  perry 	}
    340  1.5  perry 	if (flying) {
    341  1.5  perry 		if (flystate == i) {
    342  1.5  perry 			printf(" this and all the rest");
    343  1.5  perry 		} else if (flystate) {
    344  1.5  perry 			printf(" this, replacing all the rest");
    345  1.5  perry 		} else {
    346  1.5  perry 			printf(" this, leaving all the rest");
    347  1.5  perry 		}
    348  1.5  perry 	}
    349  1.5  perry 	printf(")\n");
    350  1.5  perry 	return (i);
    351  1.5  perry }
    352  1.5  perry 
    353  1.5  perry static void
    354  1.5  perry add_shift(long *a, long e, int n)
    355  1.5  perry {
    356  1.5  perry 	int i;
    357  1.5  perry 
    358  1.5  perry 	n--;
    359  1.5  perry 	for (i = 0; i < n; i++) {
    360  1.5  perry 		a[i] = a[i + 1];
    361  1.5  perry 	}
    362  1.5  perry 	a[n] = e;
    363  1.5  perry }
    364  1.5  perry 
    365  1.5  perry static void
    366  1.5  perry process_file(char *fn)
    367  1.5  perry {
    368  1.5  perry 	int i;
    369  1.5  perry 	long n;
    370  1.5  perry 	int c;
    371  1.5  perry 
    372  1.5  perry 	workf = fopen(fn, "r+");
    373  1.5  perry 	if (workf == NULL) {
    374  1.5  perry 		fprintf(stderr, "%s: cannot read %s\n", __progname, fn);
    375  1.5  perry 		return;
    376  1.5  perry 	}
    377  1.5  perry 	printf("(file: %s)\n", fn);
    378  1.5  perry 	current_file = fn;
    379  1.5  perry 	for (i = 0; i <= MAX_C_A; i++) {
    380  1.5  perry 		nls[i] = -1;
    381  1.5  perry 	}
    382  1.5  perry 	nls[MAX_C_A] = 0;
    383  1.5  perry 	tbeg = -1;
    384  1.5  perry 	if (wordmode) {
    385  1.5  perry 		bufp0 = &buf[1];
    386  1.5  perry 		rahead = s1l + 1;
    387  1.5  perry 		buf[0] = '\0';
    388  1.5  perry 	} else {
    389  1.5  perry 		bufp0 = &buf[0];
    390  1.5  perry 		rahead = s1l;
    391  1.5  perry 	}
    392  1.5  perry 	if (debugging) {
    393  1.5  perry 		printf("[rahead = %d, bufp0-buf = %ld]\n",
    394  1.5  perry 		    rahead, (long) (bufp0 - &buf[0]));
    395  1.5  perry 	}
    396  1.5  perry 	n = 0;
    397  1.5  perry 	bufp = bufp0;
    398  1.5  perry 	bufpmax = &buf[sizeof(buf) - s1l - 2];
    399  1.5  perry 	flying = allfly;
    400  1.5  perry 	flystate = 1;
    401  1.5  perry 	while (1) {
    402  1.5  perry 		c = getc(workf);
    403  1.5  perry 		if (c == EOF) {
    404  1.5  perry 			if (tbeg >= 0) {
    405  1.5  perry 				if (bufp > bufp0)
    406  1.5  perry 					fwrite(bufp0, 1, bufp - bufp0, tempf);
    407  1.5  perry 				fseek(workf, tbeg, 0);
    408  1.5  perry 				n = ftell(tempf);
    409  1.5  perry 				fseek(tempf, 0L, 0);
    410  1.5  perry 				for (; n; n--) {
    411  1.5  perry 					putc(getc(tempf), workf);
    412  1.5  perry 				}
    413  1.5  perry 				fflush(workf);
    414  1.5  perry 				ftruncate(fileno(workf), ftell(workf));
    415  1.5  perry 			}
    416  1.5  perry 			fclose(workf);
    417  1.5  perry 			return;
    418  1.5  perry 		}
    419  1.5  perry 		*bufp++ = c;
    420  1.5  perry 		n++;
    421  1.5  perry 		if (debugging) {
    422  1.5  perry 			printf("[got %c, n now %ld, bufp-buf %ld]\n",
    423  1.5  perry 			    c, n, (long) (bufp - bufp0));
    424  1.5  perry 		}
    425  1.5  perry 		if ((n >= rahead) && foundit() && doit()) {
    426  1.5  perry 			int wbehind;
    427  1.5  perry 			if (debugging) {
    428  1.5  perry 				printf("[doing change]\n");
    429  1.5  perry 			}
    430  1.5  perry 			wbehind = 1;
    431  1.5  perry 			if (tbeg < 0) {
    432  1.5  perry 				tbeg = ftell(workf) - rahead;
    433  1.5  perry 				fseek(tempf, 0L, 0);
    434  1.5  perry 				if (debugging) {
    435  1.5  perry 					printf("[tbeg set to %d]\n",
    436  1.5  perry 					    (int)tbeg);
    437  1.5  perry 				}
    438  1.5  perry 				wbehind = 0;
    439  1.5  perry 			}
    440  1.5  perry 			if (bufp[-1] == '\n')
    441  1.5  perry 				add_shift(nls, ftell(workf), MAX_C_A + 1);
    442  1.5  perry 			if ((n > rahead) && wbehind) {
    443  1.5  perry 				fwrite(bufp0, 1, n - rahead, tempf);
    444  1.5  perry 				if (debugging) {
    445  1.5  perry 					printf("[writing %ld from bufp0]\n",
    446  1.5  perry 					    n - rahead);
    447  1.5  perry 				}
    448  1.5  perry 			}
    449  1.5  perry 			fwrite(str2, 1, s2l, tempf);
    450  1.5  perry 			n = rahead - s1l;
    451  1.5  perry 			if (debugging) {
    452  1.5  perry 				printf("[n now %ld]\n", n);
    453  1.5  perry 			}
    454  1.5  perry 			if (n > 0) {
    455  1.5  perry 				bcopy(bufp - n, bufp0, n);
    456  1.5  perry 				if (debugging) {
    457  1.5  perry 					printf("[copying %ld back]\n", n);
    458  1.5  perry 				}
    459  1.5  perry 			}
    460  1.5  perry 			bufp = bufp0 + n;
    461  1.5  perry 		} else {
    462  1.5  perry 			if (bufp[-1] == '\n')
    463  1.5  perry 				add_shift(nls, ftell(workf), MAX_C_A + 1);
    464  1.5  perry 			if (bufp >= bufpmax) {
    465  1.5  perry 				if (tbeg >= 0) {
    466  1.5  perry 					fwrite(bufp0, 1, n - rahead, tempf);
    467  1.5  perry 					if (debugging) {
    468  1.5  perry 						printf("[flushing %ld]\n",
    469  1.5  perry 						    n - rahead);
    470  1.5  perry 					}
    471  1.5  perry 				}
    472  1.5  perry 				n = rahead;
    473  1.5  perry 				bcopy(bufp - n, bufp0, n);
    474  1.5  perry 				if (debugging) {
    475  1.5  perry 					printf("[n now %ld]\n[copying %ld back]\n", n, n);
    476  1.5  perry 				}
    477  1.5  perry 				bufp = bufp0 + n;
    478  1.5  perry 			}
    479  1.5  perry 		}
    480  1.5  perry 	}
    481  1.5  perry }
    482  1.5  perry 
    483  1.5  perry static void
    484  1.5  perry process_indir_file(char *fn)
    485  1.5  perry {
    486  1.5  perry 	char newfn[1024];
    487  1.5  perry 	FILE *f;
    488  1.5  perry 
    489  1.5  perry 	f = fopen(fn, "r");
    490  1.5  perry 	if (f == NULL) {
    491  1.5  perry 		fprintf(stderr, "%s: cannot read %s\n", __progname, fn);
    492  1.5  perry 		return;
    493  1.5  perry 	}
    494  1.5  perry 	while (fgets(newfn, sizeof(newfn), f) == newfn) {
    495  1.5  perry 		newfn[strlen(newfn) - 1] = '\0';
    496  1.5  perry 		process_file(newfn);
    497  1.5  perry 	}
    498  1.5  perry 	fclose(f);
    499  1.5  perry }
    500  1.5  perry 
    501  1.5  perry int
    502  1.5  perry main(int ac, char **av)
    503  1.5  perry {
    504  1.5  perry 	int skip;
    505  1.5  perry 	char *cp;
    506  1.5  perry 
    507  1.5  perry 	if (ac < 3) {
    508  1.5  perry 		fprintf(stderr, "Usage: %s str1 str2 [ -w -! -noask -go -f file -F file ]\n",
    509  1.5  perry 		    __progname);
    510  1.5  perry 		exit(1);
    511  1.5  perry 	}
    512  1.5  perry 	cp = getenv("TERM");
    513  1.5  perry 	if (cp == 0) {
    514  1.5  perry 		beginul = nullstr;
    515  1.1  perry 		endul = nullstr;
    516  1.5  perry 	} else {
    517  1.5  perry 		if (tgetent(tcp_buf, cp) != 1) {
    518  1.5  perry 			beginul = nullstr;
    519  1.5  perry 			endul = nullstr;
    520  1.5  perry 		} else {
    521  1.5  perry 			cp = cap_buf;
    522  1.5  perry 			if (tgetflag("os") || tgetflag("ul")) {
    523  1.5  perry 				ul_ = 1;
    524  1.5  perry 			} else {
    525  1.5  perry 				ul_ = 0;
    526  1.5  perry 				beginul = tgetstr("us", &cp);
    527  1.5  perry 				if (beginul == 0) {
    528  1.5  perry 					beginul = tgetstr("so", &cp);
    529  1.5  perry 					if (beginul == 0) {
    530  1.5  perry 						beginul = nullstr;
    531  1.5  perry 						endul = nullstr;
    532  1.5  perry 					} else {
    533  1.5  perry 						endul = tgetstr("se", &cp);
    534  1.5  perry 					}
    535  1.5  perry 				} else {
    536  1.5  perry 					endul = tgetstr("ue", &cp);
    537  1.5  perry 				}
    538  1.5  perry 			}
    539  1.5  perry 		}
    540  1.5  perry 	}
    541  1.5  perry 	{
    542  1.5  perry 		static char tmp[] = "/tmp/qsubst.XXXXXX";
    543  1.5  perry 		int fd;
    544  1.5  perry 		fd = mkstemp(&tmp[0]);
    545  1.5  perry 		if (fd < 0) {
    546  1.5  perry 			fprintf(stderr, "%s: cannot create temp file: %s\n",
    547  1.5  perry 			    __progname, strerror(errno));
    548  1.5  perry 			exit(1);
    549  1.5  perry 		}
    550  1.5  perry 		tempf = fdopen(fd, "w+");
    551  1.5  perry 	}
    552  1.5  perry 	if ((access(av[1], R_OK | W_OK) == 0) &&
    553  1.5  perry 	    (access(av[ac - 1], R_OK | W_OK) < 0) &&
    554  1.5  perry 	    (access(av[ac - 2], R_OK | W_OK) < 0)) {
    555  1.5  perry 		fprintf(stderr, "%s: argument order has changed, it's now: str1 str2 files...\n", __progname);
    556  1.5  perry 	}
    557  1.5  perry 	str1 = av[1];
    558  1.5  perry 	str2 = av[2];
    559  1.5  perry 	av += 2;
    560  1.5  perry 	ac -= 2;
    561  1.5  perry 	s1l = strlen(str1);
    562  1.5  perry 	s2l = strlen(str2);
    563  1.5  perry 	if (s1l > BUF_SIZ) {
    564  1.5  perry 		fprintf(stderr, "%s: search string too long (max %d chars)\n",
    565  1.5  perry 		    __progname, BUF_SIZ);
    566  1.5  perry 		exit(1);
    567  1.5  perry 	}
    568  1.5  perry 	tcgetattr(0, &orig_tio);
    569  1.5  perry 	signal(SIGTSTP, sigtstp);
    570  1.5  perry 	allfly = 0;
    571  1.5  perry 	cabove = 2;
    572  1.5  perry 	cbelow = 2;
    573  1.5  perry 	skip = 0;
    574  1.5  perry 	for (ac--, av++; ac; ac--, av++) {
    575  1.5  perry 		if (skip > 0) {
    576  1.5  perry 			skip--;
    577  1.5  perry 			continue;
    578  1.5  perry 		}
    579  1.5  perry 		if (**av == '-') {
    580  1.5  perry 			++*av;
    581  1.5  perry 			if (!strcmp(*av, "debug")) {
    582  1.5  perry 				debugging++;
    583  1.5  perry 			} else if (!strcmp(*av, "w")) {
    584  1.5  perry 				wordmode = !wordmode;
    585  1.5  perry 			} else if ((strcmp(*av, "!") == 0) ||
    586  1.5  perry 				    (strcmp(*av, "go") == 0) ||
    587  1.5  perry 			    (strcmp(*av, "noask") == 0)) {
    588  1.5  perry 				allfly = 1;
    589  1.5  perry 			} else if ((strcmp(*av, "nogo") == 0) ||
    590  1.5  perry 			    (strcmp(*av, "ask") == 0)) {
    591  1.5  perry 				allfly = 0;
    592  1.5  perry 			} else if (**av == 'c') {
    593  1.5  perry 				cabove = atoi(++*av);
    594  1.5  perry 				cbelow = cabove;
    595  1.5  perry 				limit_above_below();
    596  1.5  perry 			} else if (**av == 'C') {
    597  1.5  perry 				++*av;
    598  1.5  perry 				if (**av == 'A') {
    599  1.5  perry 					cabove = atoi(++*av);
    600  1.5  perry 					limit_above_below();
    601  1.5  perry 				} else if (**av == 'B') {
    602  1.5  perry 					cbelow = atoi(++*av);
    603  1.5  perry 					limit_above_below();
    604  1.5  perry 				} else {
    605  1.5  perry 					fprintf(stderr, "%s: -C must be -CA or -CB\n", __progname);
    606  1.5  perry 				}
    607  1.5  perry 			} else if ((strcmp(*av, "f") == 0) ||
    608  1.5  perry 			    (strcmp(*av, "F") == 0)) {
    609  1.5  perry 				if (++skip >= ac) {
    610  1.5  perry 					fprintf(stderr, "%s: -%s what?\n",
    611  1.5  perry 					    __progname, *av);
    612  1.5  perry 				} else {
    613  1.5  perry 					if (**av == 'f') {
    614  1.5  perry 						process_file(av[skip]);
    615  1.5  perry 					} else {
    616  1.5  perry 						process_indir_file(av[skip]);
    617  1.5  perry 					}
    618  1.5  perry 				}
    619  1.5  perry 			}
    620  1.5  perry 		} else {
    621  1.5  perry 			process_file(*av);
    622  1.5  perry 		}
    623  1.5  perry 	}
    624  1.5  perry 	exit(0);
    625  1.1  perry }
    626