home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / qsubst < prev    next >
Text File  |  1987-08-12  |  18KB  |  744 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v11i007:  A query-replace program
  5. Message-ID: <897@uunet.UU.NET>
  6. Date: 13 Aug 87 22:37:41 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 733
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: der Mouse  <mouse@larry.ee.mcgill>
  12. Posting-number: Volume 11, Issue 7
  13. Archive-name: qsubst
  14.  
  15. [  This is a program to do large amounts of query-replaces on a bunch
  16.    of files.  I spliced the Makefile into the shar.  --r$  ]
  17.  
  18. A useful little program.  Designed one evening when someone wanted to
  19. rename a few routines which were used in umpteen zillion places all
  20. over a bunch of files.  This code is known to work on mtXinu 4.3+NFS
  21. and on Sunix 3.0; I would expect it to work on BSD systems in general.
  22. I have no idea how easy porting to a USG (SysIII, SysV) environment
  23. would be; we don't have USG systems around here.
  24.  
  25. #! /bin/sh
  26. #
  27. # Shar: Shell Archiver
  28. #
  29. # Run this through sh to create:
  30. #    Makefile
  31. #    qsubst.1
  32. #    qsubst.c
  33. echo x - Makefile \(some number of characters\)
  34. sed 's/^X//' > Makefile << \SHAR_EOF
  35. all:    qsubst
  36. install:    qsubst qsubst.1
  37.     @echo copy qsubst and qsubst.1 to appropriate directories.
  38. qsubst:        qsubst.c
  39.     $(CC) $(CFLAGS) -o qsubst qsubst.c
  40. SHAR_EOF
  41. echo No error check because the moderator is lazy...
  42. echo x - qsubst.1 \(4752 characters\)
  43. sed 's/^X//' > qsubst.1 << \SHAR_EOF
  44. X.TH QSUBST 1 "31 March 1985"
  45. X.UC 4
  46. X.SH NAME
  47. Xqsubst - query/substitute strings in files
  48. X.SH SYNOPSIS
  49. X.nf
  50. X.ft B
  51. Xqsubst string1 string2 [ options / files ]
  52. X.PP
  53. X.fi
  54. X.SH DESCRIPTION
  55. X\fIQsubst\fP is designed for substituting strings in (large) files.  It
  56. Xaccepts a list of file names and two strings.  For each of the files,
  57. X\fIqsubst\fP modifies it in-place to replace \fIstring1\fP with \fIstring2\fP
  58. Xwherever the user approves the change.
  59. X.PP
  60. XEach time \fIqsubst\fP finds the \fIstring1\fP in a file, it prints a few
  61. Xlines of context (see the -c option below) and expects the user to type a
  62. Xcharacter to indicate whether or not the replacement should be done.  The
  63. Xuser can type:
  64. X.TP 8
  65. X space
  66. XReplace this instance and go on to the next one.
  67. X.TP
  68. X .
  69. XReplace this instance but don't do any more in this file (ie, go on to the
  70. Xnext file).
  71. X.TP
  72. X n
  73. XDon't change this instance, just go on to the next one.
  74. X.TP
  75. X ^G
  76. XDon't change this instance or any more in this file, just go on to the next
  77. Xfile.
  78. X.TP
  79. X !
  80. XChange this instance and all further ones in this file without asking, then
  81. Xgo on to the next file (for which \fIqsubst\fP will begin asking again).
  82. X.PP
  83. XThe arguments preceding the strings are interpreted as filenames (which
  84. X\fIqsubst\fP then performs replacements in) if they do not begin with \-
  85. Xsigns.  If they do, they are interpreted as follows:
  86. X.TP 8
  87. X\-!
  88. X.br
  89. X.ns
  90. X.TP
  91. X\-go
  92. X.br
  93. X.ns
  94. X.TP
  95. X\-noask
  96. XDon't bother asking, just replace.  This is like hitting ! as soon as the
  97. Xfirst instance appears for each file except that nothing is printed.  This is
  98. Xin effect for all files encountered until a \-nogo or \-ask option is given.
  99. XNote that if you use csh, you will probably have to backslash the !, which is
  100. Xwhy the alternative forms exist.
  101. X.TP
  102. X\-nogo
  103. X.br
  104. X.ns
  105. X.TP
  106. X\-ask
  107. XNegate a \-go or \-noask option.  \fIQsubst\fP will once more prompt the user
  108. Xas usual.
  109. X.TP
  110. X\-CA\fIN\fP
  111. XGive \fIN\fP lines of context above the line with the match when prompting
  112. Xthe user.
  113. X.TP
  114. X\-CB\fIN\fP
  115. XGive \fIN\fP lines of context below the line with the match when prompting
  116. Xthe user.
  117. X.TP
  118. X\-c\fIN\fP
  119. XGive \fIN\fP lines of context above and as many below the line with the
  120. Xmatch when prompting the user (equivalent to \-CA\fIN\fP \-CB\fIN\fP).
  121. X.TP
  122. X.SM
  123. X\-f \fIfilename\fP
  124. XSame as a simple \fIfilename\fP argument, but is useful if the file name
  125. Xbegins with a \-.
  126. X.TP
  127. X.SM
  128. X\-F \fIfilename\fP
  129. X\fIQsubst\fP reads file names from the file, one per line, and performs
  130. Xsubstitutions on the files whose names it reads thus.
  131. X.SH ERRORS
  132. X\fIQsubst\fP can generate the following error messages:
  133. X.PP
  134. XUsage: qsubst str1 str2 [ \-! \-noask \-go \-f file \-F file ]
  135. X.PP
  136. XThis is a usage message printed if fewer than two arguments are given.
  137. X.PP
  138. Xqsubst: argument order has changed, it's now: str1 str2 files...
  139. X.PP
  140. XQsubst used to take arguments differently; the two strings were the *last*
  141. Xtwo arguments rather than the first two.  This message is printed if the
  142. Xfirst argument is a valid file name but the last two are not - qsubst assumes
  143. Xthat you didn't know of the change yet.  However, qsubst continues as though
  144. Xwhat you gave were actually what you meant.
  145. X.PP
  146. Xqsubst: cannot create temp file /tmp/qsubst.012345
  147. X.PP
  148. X(The number may vary).  This message is generated if \fIqsubst\fP cannot open
  149. Xits temporary file (the name appears in the message).  Something is seriously
  150. Xwrong with either \fIqsubst\fP or /tmp.
  151. X.PP
  152. Xqsubst: search string too long (max 512 chars)
  153. X.PP
  154. XThis is surely self-explanatory.
  155. X.PP
  156. Xqsubst: \-C must be \-CA or \-CB
  157. X.PP
  158. XYou gave \-C, but it was neither \-CA nor \-CB.
  159. X.PP
  160. Xqsubst: \-f what?
  161. X.br
  162. Xqsubst: \-F what?
  163. X.PP
  164. XYou gave \-f (or -\F) without a file name.
  165. X.PP
  166. Xqsubst: cannot read \fIfilename\fP
  167. X.PP
  168. X\fIQsubst\fP couldn't open the named file for read-only.
  169. X.PP
  170. Xqsubst: cannot rewrite \fIfilename\fP
  171. X.PP
  172. X\fIQsubst\fP couldn't open the named file read/write for substitution.
  173. X.SH NOTES
  174. X\fIQsubst\fP reads its argument list in order and processes files as it comes
  175. Xto them.  Hence (for instance), a \-go option will affect only files named
  176. Xafter the \-go option.
  177. X.PP
  178. XThe most context you can get is \-c10.
  179. X.PP
  180. XThe search string (\fIstring1\fP) is limited to 512 characters.  There is no
  181. Xsimilar limit on the length of the replacement string (\fIstring2\fP).
  182. X.PP
  183. XNulls in the file may cause \fIqsubst\fP to make various mistakes.
  184. X.PP
  185. XIf any other program modifies the file while \fIqsubst\fP is running, all
  186. Xbets are off.
  187. X.PP
  188. X\fIQsubst\fP expect the files it is performing substitutions in to be real
  189. Xfiles, that is, objects on which \fIlseek(2)\fP works sensibly.  Not, for
  190. Xexample, terminals or pipes.
  191. X.PP
  192. X\fIQsubst\fP is careful to modify files only when necessary, so it interacts
  193. Xnicely with \fImake(1)\fP.
  194. X.SH AUTHOR
  195. Xder Mouse (Mike Parker, mcgill-vision!mouse), March, 1985.
  196. SHAR_EOF
  197. if test 4752 -ne "`wc -c qsubst.1`"
  198. then
  199. echo shar: error transmitting qsubst.1 \(should have been 4752 characters\)
  200. fi
  201. echo x - qsubst.c \(10813 characters\)
  202. sed 's/^X//' > qsubst.c << \SHAR_EOF
  203. X/*
  204. X * Qsubst -- designed for renaming routines existing in a whole bunch of
  205. X *  files.  Must be compiled with -ltermcap.
  206. X *
  207. X * Usage:
  208. X *
  209. X * qsubst str1 str2 [ options ]
  210. X *
  211. X * Qsubst reads its options (see below) to get a list of files.  For each
  212. X *  file on this list, it then replaces str1 with str2 wherever possible in
  213. X *  that file, depending on user input (see below).  The result is written
  214. X *  back onto the original file.
  215. X *
  216. X * For each possible substitution, the user is prompted with a few lines
  217. X *  before and after the line containing the string to be substituted.  The
  218. X *  string itself is underlined, if the terminal supports this.  Then one
  219. X *  character is read from the terminal.  This is then interpreted as
  220. X *  follows (this is designed to be like Emacs' query-replace-string):
  221. X *
  222. X *    space    replace this occurrence and go on to the next one
  223. X *    .    replace this occurrence and don't change any more in this
  224. X *        file (ie, go on to the next file).
  225. X *    ,    tentatively replace this occurrence.  The lines as they would
  226. X *        look if the substitution were made are printed out.  Then
  227. X *        another character is read and it is used to decide the
  228. X *        result (possibly undoing the tentative replacement).
  229. X *    n    don't change this one, but go on to the next one
  230. X *    ^G    don't change this one or any others in this file, but instead
  231. X *        go on to the next file.
  232. X *    !    change the rest in this file without asking, then go on to
  233. X *        the next file (at which point qsubst will start asking
  234. X *        again).
  235. X *    ?    print out the current filename and ask again.
  236. X *
  237. X * The first two arguments to qsubst are always the string to replace and the
  238. X *  string to replace it with.  The options are as follows:
  239. X *
  240. X *    -!    Enter ! mode automatically at the beginning of each file
  241. X *    -go    Same as -!
  242. X *    -noask    Same as -!
  243. X *    -nogo    Negate -go
  244. X *    -ask    Negate -noask (same as -nogo)
  245. X *    -cN    (N is a number) Give N lines of context above and below the
  246. X *        line with the match when prompting the user.
  247. X *    -CAN    (N is a number) Give N lines of context above the line with
  248. X *        the match when prompting the user.
  249. X *    -CBN    (N is a number) Give N lines of context below the line with
  250. X *        the match when prompting the user.
  251. X *    -f filename
  252. X *        The filename following the -f argument is one of the files
  253. X *        qsubst should perform substitutions in.
  254. X *    -F filename
  255. X *        Qsubst should read the named file to get the names of files
  256. X *        to perform substitutions in.  The names should appear one to
  257. X *        a line.
  258. X *
  259. X * The default amount of context is -c2, that is, two lines above and two
  260. X *  lines below the line with the match.
  261. X *
  262. X * Arguments not beginning with a - sign in the options field are implicitly
  263. X *  preceded by -f.  Thus, -f is really needed only when the file name begins
  264. X *  with a - sign.
  265. X *
  266. X * Qsubst reads its options in order and processes files as it gets them.
  267. X *  This means, for example, that a -go will affect only files from -f or -F
  268. X *  options appearing after the -go option.
  269. X *
  270. X * The most context you can get is ten lines each, above and below
  271. X *  (corresponding to -c10).
  272. X *
  273. X * Str1 is limited to 512 characters; there is no limit on the size of str2.
  274. X *  Neither one may contain a null.
  275. X *
  276. X * Nulls in the file may cause qsubst to make various mistakes.
  277. X *
  278. X * If any other program modifies the file while qsubst is running, all bets
  279. X *  are off.
  280. X */
  281. X#include <stdio.h>
  282. X#include <sgtty.h>
  283. X#include <signal.h>
  284. X#include <sys/file.h>
  285. X
  286. X#ifndef sigmask
  287. X#define sigmask(sig) (1<<((sig)-1))
  288. X#endif
  289. X
  290. X#define MAX_C_A 10
  291. X#define MAX_C_B 10
  292. X#define BUF_SIZ 1024
  293. X
  294. Xchar **argvec;
  295. X
  296. Xchar *getenv();
  297. Xchar *tgetstr();
  298. Xchar *malloc();
  299. Xchar *sindex();
  300. Xchar *mktemp();
  301. X
  302. XFILE *tempf;
  303. Xlong int tbeg;
  304. XFILE *workf;
  305. Xchar *str1;
  306. Xchar *str2;
  307. Xint s1l;
  308. Xint s2l;
  309. Xlong int nls[MAX_C_A+1];
  310. Xchar buf[BUF_SIZ*2];
  311. Xchar *buf1 = buf;
  312. Xchar *buf2 = buf + BUF_SIZ;
  313. Xint cabove;
  314. Xint cbelow;
  315. Xint flying;
  316. Xint flystate;
  317. Xint allfly;
  318. Xchar *nullstr = "";
  319. Xint ul_;
  320. Xchar *current_file;
  321. Xchar *beginul;
  322. Xchar *endul;
  323. Xchar tcp_buf[1024];
  324. Xchar cap_buf[1024];
  325. Xstruct sgttyb orig_sg;
  326. X
  327. Xtstp_self()
  328. X{
  329. X int (*old_tstp)();
  330. X int mask;
  331. X
  332. X mask = sigblock(0);
  333. X old_tstp = signal(SIGTSTP,SIG_DFL);
  334. X sigsetmask(mask&~sigmask(SIGTSTP));
  335. X kill(getpid(),SIGTSTP);
  336. X signal(SIGTSTP,old_tstp);
  337. X}
  338. X
  339. Xsigtstp()
  340. X{
  341. X struct sgttyb sg;
  342. X
  343. X if (ioctl(fileno(stdin),TIOCGETP,&sg) < 0)
  344. X  { tstp_self();
  345. X    return;
  346. X  }
  347. X ioctl(fileno(stdin),TIOCSETN,&orig_sg);
  348. X tstp_self();
  349. X ioctl(fileno(stdin),TIOCSETN,&sg);
  350. X}
  351. X
  352. Xmain(ac,av)
  353. Xint ac;
  354. Xchar **av;
  355. X{
  356. X int skip;
  357. X char *cp;
  358. X
  359. X argvec = av;
  360. X if (ac < 3)
  361. X  { fprintf(stderr,"Usage: %s str1 str2 [ -! -noask -go -f file -F file ]\n",
  362. X                argvec[0]);
  363. X    exit(1);
  364. X  }
  365. X cp = getenv("TERM");
  366. X if (cp == 0)
  367. X  { beginul = nullstr;
  368. X    endul = nullstr;
  369. X  }
  370. X else
  371. X  { if (tgetent(tcp_buf,cp) != 1)
  372. X     { beginul = nullstr;
  373. X       endul = nullstr;
  374. X     }
  375. X    else
  376. X     { cp = cap_buf;
  377. X       if (tgetflag("os") || tgetflag("ul"))
  378. X    { ul_ = 1;
  379. X    }
  380. X       else
  381. X    { ul_ = 0;
  382. X      beginul = tgetstr("us",&cp);
  383. X      if (beginul == 0)
  384. X       { beginul = tgetstr("so",&cp);
  385. X         if (beginul == 0)
  386. X          { beginul = nullstr;
  387. X        endul = nullstr;
  388. X          }
  389. X         else
  390. X          { endul = tgetstr("se",&cp);
  391. X          }
  392. X       }
  393. X      else
  394. X       { endul = tgetstr("ue",&cp);
  395. X       }
  396. X    }
  397. X     }
  398. X  }
  399. X cp = mktemp("/tmp/qsubst.XXXXXX");
  400. X tempf = fopen(cp,"w+");
  401. X if (tempf == NULL)
  402. X  { fprintf(stderr,"%s: cannot create temp file %s\n",argvec[0],cp);
  403. X    exit(1);
  404. X  }
  405. X unlink(cp);
  406. X if ( (access(av[1],R_OK|W_OK) == 0) &&
  407. X      (access(av[ac-1],R_OK|W_OK) < 0) &&
  408. X      (access(av[ac-2],R_OK|W_OK) < 0) )
  409. X  { fprintf(stderr,"\
  410. X%s: argument order has changed, it's now: str1 str2 files...\n",argvec[0]);
  411. X  }
  412. X str1 = av[1];
  413. X str2 = av[2];
  414. X av += 2;
  415. X ac -= 2;
  416. X s1l = strlen(str1);
  417. X s2l = strlen(str2);
  418. X if (s1l > BUF_SIZ/2)
  419. X  { fprintf(stderr,"%s: search string too long (max %d chars)\n",
  420. X                        argvec[0],BUF_SIZ/2);
  421. X    exit(1);
  422. X  }
  423. X ioctl(fileno(stdin),TIOCGETP,&orig_sg);
  424. X signal(SIGTSTP,sigtstp);
  425. X allfly = 0;
  426. X cabove = 2;
  427. X cbelow = 2;
  428. X skip = 0;
  429. X for (ac--,av++;ac;ac--,av++)
  430. X  { if (skip > 0)
  431. X     { skip --;
  432. X       continue;
  433. X     }
  434. X    if (**av == '-')
  435. X     { ++*av;
  436. X       if ( (strcmp(*av,"!") == 0) ||
  437. X        (strcmp(*av,"go") == 0) ||
  438. X        (strcmp(*av,"noask") == 0) )
  439. X    { allfly = 1;
  440. X    }
  441. X       else if ( (strcmp(*av,"nogo") == 0) ||
  442. X         (strcmp(*av,"ask") == 0) )
  443. X    { allfly = 0;
  444. X    }
  445. X       else if (**av == 'c')
  446. X    { cabove = atoi(++*av);
  447. X      cbelow = cabove;
  448. X      limit_above_below();
  449. X    }
  450. X       else if (**av == 'C')
  451. X    { ++*av;
  452. X      if (**av == 'A')
  453. X       { cabove = atoi(++*av);
  454. X         limit_above_below();
  455. X       }
  456. X      else if (**av == 'B')
  457. X       { cbelow = atoi(++*av);
  458. X         limit_above_below();
  459. X       }
  460. X      else
  461. X       { fprintf(stderr,"%s: -C must be -CA or -CB\n",argvec[0]);
  462. X       }
  463. X    }
  464. X       else if ( (strcmp(*av,"f") == 0) ||
  465. X         (strcmp(*av,"F") == 0) )
  466. X    { if (++skip >= ac)
  467. X       { fprintf(stderr,"%s: -%s what?\n",argvec[0],*av);
  468. X       }
  469. X      else
  470. X       { if (**av == 'f')
  471. X          { process_file(av[skip]);
  472. X          }
  473. X         else
  474. X          { process_indir_file(av[skip]);
  475. X          }
  476. X       }
  477. X    }
  478. X     }
  479. X    else
  480. X     { process_file(*av);
  481. X     }
  482. X  }
  483. X exit(0);
  484. X}
  485. X
  486. Xlimit_above_below()
  487. X{
  488. X if (cabove > MAX_C_A)
  489. X  { cabove = MAX_C_A;
  490. X  }
  491. X if (cbelow > MAX_C_B)
  492. X  { cbelow = MAX_C_B;
  493. X  }
  494. X}
  495. X
  496. Xprocess_indir_file(fn)
  497. Xchar *fn;
  498. X{
  499. X char newfn[1024];
  500. X FILE *f;
  501. X
  502. X f = fopen(fn,"r");
  503. X if (f == NULL)
  504. X  { fprintf(stderr,"%s: cannot read %s\n",argvec[0],fn);
  505. X    return;
  506. X  }
  507. X while (fgets(newfn,sizeof(newfn),f) == newfn)
  508. X  { newfn[strlen(newfn)-1] = '\0';
  509. X    process_file(newfn);
  510. X  }
  511. X fclose(f);
  512. X}
  513. X
  514. Xprocess_file(fn)
  515. Xchar *fn;
  516. X{
  517. X int i;
  518. X long int n;
  519. X char *cp;
  520. X
  521. X workf = fopen(fn,"r+");
  522. X if (workf == NULL)
  523. X  { fprintf(stderr,"%s: cannot read %s\n",argvec[0],fn);
  524. X    return;
  525. X  }
  526. X printf("(file: %s)\n",fn);
  527. X current_file = fn;
  528. X for (i=0;i<=MAX_C_A;i++)
  529. X  { nls[i] = -1;
  530. X  }
  531. X nls[MAX_C_A] = 0;
  532. X tbeg = -1;
  533. X n = 0;
  534. X flying = allfly;
  535. X flystate = 1;
  536. X while (1)
  537. X  { while (n < s1l)
  538. X     { buf[n] = getc(workf);
  539. X       if (buf[n] == '\n')
  540. X    { add_shift(nls,ftell(workf),MAX_C_A+1);
  541. X    }
  542. X       n ++;
  543. X       if (feof(workf))
  544. X    { if (tbeg >= 0)
  545. X       { n --;
  546. X         fwrite(buf,1,n,tempf);
  547. X         fseek(workf,tbeg,0);
  548. X         n = ftell(tempf);
  549. X         fseek(tempf,0L,0);
  550. X         for (;n;n--)
  551. X          { putc(getc(tempf),workf);
  552. X          }
  553. X         fflush(workf);
  554. X         ftruncate(fileno(workf),ftell(workf));
  555. X       }
  556. X      fclose(workf);
  557. X      return;
  558. X    }
  559. X     }
  560. X    if ((bcmp(buf,str1,s1l) == 0) && doit())
  561. X     { if (tbeg < 0)
  562. X    { tbeg = ftell(workf) - s1l;
  563. X      fseek(tempf,0L,0);
  564. X    }
  565. X       fwrite(str2,1,s2l,tempf);
  566. X       n = 0;
  567. X     }
  568. X    else
  569. X     { if (tbeg >= 0)
  570. X    { putc(buf[0],tempf);
  571. X    }
  572. X       n --;
  573. X       bcopy(buf+1,buf,n);
  574. X     }
  575. X  }
  576. X}
  577. X
  578. Xadd_shift(a,e,n)
  579. Xregister long int *a;
  580. Xregister long int e;
  581. Xregister int n;
  582. X{
  583. X register int i;
  584. X
  585. X n --;
  586. X for (i=0;i<n;i++)
  587. X  { a[i] = a[i+1];
  588. X  }
  589. X a[n] = e;
  590. X}
  591. X
  592. Xchar getc_cbreak()
  593. X{
  594. X struct sgttyb sg;
  595. X struct sgttyb osg;
  596. X char c;
  597. X
  598. X if (ioctl(fileno(stdin),TIOCGETP,&sg) < 0)
  599. X  { return(getchar());
  600. X  }
  601. X osg = sg;
  602. X sg.sg_flags |= CBREAK;
  603. X sg.sg_flags &= ~ECHO;
  604. X ioctl(fileno(stdin),TIOCSETN,&sg);
  605. X c = getchar();
  606. X ioctl(fileno(stdin),TIOCSETN,&osg);
  607. X return(c);
  608. X}
  609. X
  610. Xint doit()
  611. X{
  612. X long int save;
  613. X int i;
  614. X char c;
  615. X int use_replacement;
  616. X
  617. X if (flying)
  618. X  { return(flystate);
  619. X  }
  620. X use_replacement = 0;
  621. X save = ftell(workf);
  622. X i = -1;
  623. X while (i < 0)
  624. X  { for (i=MAX_C_A-cabove;nls[i]<0;i++) ;
  625. X    fseek(workf,nls[i],0);
  626. X    for (i=save-nls[i]-s1l;i;i--)
  627. X     { putchar(getc(workf));
  628. X     }
  629. X    put_ul(use_replacement?str2:str1);
  630. X    fseek(workf,save,0);
  631. X    i = cbelow + 1;
  632. X    while (i > 0)
  633. X     { char c;
  634. X       c = getc(workf);
  635. X       if (feof(workf))
  636. X    { clearerr(workf);
  637. X      break;
  638. X    }
  639. X       putchar(c);
  640. X       if (c == '\n')
  641. X    { i --;
  642. X    }
  643. X     }
  644. X    fseek(workf,save,0);
  645. X    i = -1;
  646. X    while (i == -1)
  647. X     { switch (getc_cbreak())
  648. X    { case ' ':
  649. X         i = 1;
  650. X         break;
  651. X      case '.':
  652. X         i = 1;
  653. X         flying = 1;
  654. X         flystate = 0;
  655. X         break;
  656. X      case 'n':
  657. X         i = 0;
  658. X         break;
  659. X      case '\7':
  660. X         i = 0;
  661. X         flying = 1;
  662. X         flystate = 0;
  663. X         break;
  664. X      case '!':
  665. X         i = 1;
  666. X         flying = 1;
  667. X         flystate = 1;
  668. X         break;
  669. X      case ',':
  670. X         use_replacement = ! use_replacement;
  671. X         i = -2;
  672. X         printf("(using %s string gives)\n",use_replacement?"new":"old");
  673. X         break;
  674. X      case '?':
  675. X         printf("File is `%s'\n",current_file);
  676. X         break;
  677. X      default:
  678. X         putchar('\7');
  679. X         break;
  680. X    }
  681. X     }
  682. X  }
  683. X if (i)
  684. X  { printf("(replacing");
  685. X  }
  686. X else
  687. X  { printf("(leaving");
  688. X  }
  689. X if (flying)
  690. X  { if (flystate == i)
  691. X     { printf(" this and all the rest");
  692. X     }
  693. X    else if (flystate)
  694. X     { printf(" this, replacing all the rest");
  695. X     }
  696. X    else
  697. X     { printf(" this, leaving all the rest");
  698. X     }
  699. X  }
  700. X printf(")\n");
  701. X return(i);
  702. X}
  703. X
  704. Xputcharf(c)
  705. Xchar c;
  706. X{
  707. X putchar(c);
  708. X}
  709. X
  710. Xput_ul(s)
  711. Xchar *s;
  712. X{
  713. X if (ul_)
  714. X  { for (;*s;s++)
  715. X     { printf("_\b%c",*s);
  716. X     }
  717. X  }
  718. X else
  719. X  { tputs(beginul,1,putcharf);
  720. X    fputs(s,stdout);
  721. X    tputs(endul,1,putcharf);
  722. X  }
  723. X}
  724. SHAR_EOF
  725. if test 10813 -ne "`wc -c qsubst.c`"
  726. then
  727. echo shar: error transmitting qsubst.c \(should have been 10813 characters\)
  728. fi
  729. exit 0
  730. # end of shell archive
  731.  
  732.                     der Mouse
  733.  
  734. Smart mailers: mouse@mcgill-vision.uucp
  735. USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!musocs!mcgill-vision!mouse
  736.      think!mosart!mcgill-vision!mouse
  737. ARPAnet: think!mosart!mcgill-vision!mouse@harvard.harvard.edu
  738.  
  739. -- 
  740.  
  741. Rich $alz
  742. Cronus Project, BBN Labs            rsalz@bbn.com
  743. Moderator, comp.sources.unix            sources@uunet.uu.net
  744.