home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3498 < prev    next >
Internet Message Format  |  1991-06-19  |  56KB

  1. From: pgf@cayman.COM (Paul Fox)
  2. Newsgroups: alt.sources
  3. Subject: Vile 12/17 - vi feel-alike (multi-window)
  4. Message-ID: <4531@cayman.COM>
  5. Date: 7 Jun 91 22:10:04 GMT
  6.  
  7. #!/bin/sh
  8. # this is vileshar.12 (part 12 of Vile)
  9. # do not concatenate these parts, unpack them in order with /bin/sh
  10. # file readme.news continued
  11. #
  12. if test ! -r _shar_seq_.tmp; then
  13.     echo 'Please unpack part 1 first!'
  14.     exit 1
  15. fi
  16. (read Scheck
  17.  if test "$Scheck" != 12; then
  18.     echo Please unpack part "$Scheck" next!
  19.     exit 1
  20.  else
  21.     exit 0
  22.  fi
  23. ) < _shar_seq_.tmp || exit 1
  24. echo 'x - continuing file readme.news'
  25. sed 's/^X//' << 'SHAR_EOF' >> 'readme.news' &&
  26. X    buffers,  windows, and files.
  27. X
  28. X    The number of lines may be selected by the user when the editor is
  29. X    invoked (-L40 for 40 lines), and the font size and the number of
  30. X    columns is then set by the size of the window the user chooses
  31. X    from the NeWS interface.
  32. X
  33. The primary distribution mechanism used to offload i/o is selective time
  34. buffering. Printable text is displayed locally as it is issued by the
  35. user, being flushed to the remote machine (where the actual editor is
  36. running) after a suitable period has elapsed during which no input is
  37. received. For normal text this period is 2 seconds. Commands (control
  38. characters and escape sequences) are also buffered in time, with a
  39. period of .4 seconds. Certain prefixes are also defined (^X and escape),
  40. so that these characters are assigned long timeouts and the following
  41. character a short timeout. The editor controls this timing data, and has
  42. the capability to throw the system into "immediate" mode, where every
  43. character is treated as a command. This is done temporarily to support
  44. the incremental search and query replace functions of emacs. The
  45. protocol puts an absolute upper bound on the number of packets that can
  46. be transmitted per second, which would be 1 every .4 seconds if the user
  47. entered commands at exactly that rate. Issuing commands at a faster or
  48. slower rate will improve the performance (reduce the packet load).
  49. X
  50. As local printable text is inserted, a different font is used to
  51. indicate that the remote machine has yet to confirm the entry. After a
  52. timeout has occurred and a packet of text and commands sent to the
  53. remote machine, the screen update will be done with the normal font.
  54. X
  55. Screen updates are optimized so that an update is done only when
  56. absolutely necessary. To help with apparent performance in low bandwidth
  57. situations, the remote display driver will search for and optimize out
  58. any scrolls or reverse scrolls. Essentially what has been implemented
  59. here (in a limited fashion) is a NeWS distributed implementation of
  60. curses, although as yet no attempt has been made to obey the syntax of
  61. curses.
  62. X
  63. The Mouse
  64. X
  65. The mouse is used to position the cursor and for cutting and pasting
  66. text.  It should be used in preference to the motion keys because it is
  67. much more efficient, sending far fewer packets to the remote machine. 
  68. It should not be used in keyboard macros however, as it's movement
  69. commands are not relative. 
  70. X
  71. Text is entered at the block cursor, NOT the mouse cursor.  To move the
  72. block cursor, move the mouse cursor to the desired position.  After the
  73. mouse has been motionless for 1/5 second, the remote machine will adjust
  74. the block cursor to match the mouse position.  While waiting for the
  75. remote machine to respond the mouse cursor takes the form of an
  76. hourglass, to indicate to the user that it is not safe to type. The
  77. alignment of cursors is not exact, since the text cursor positioning
  78. must take tabs into account and can't be placed past the end of a line. 
  79. This is a feature, not a bug
  80. X
  81. The left mouse button is used for cutting out text.  To cut out a block
  82. of text, move the mouse cursor to the starting location, press the left
  83. button and move the mouse to the ending location (keeping the button
  84. depressed).  When the button is released the text will be wiped out
  85. (moved to the kill buffer).  The middle mouse button will yank text from
  86. the kill buffer and insert it at the current (mouse cursor) location.
  87. The right mouse button invokes a walking menu. This mouse behavior is
  88. not in the standard Sunview style, and as a result it is not (yet)
  89. possible to exchange information between the editor and other NeWS
  90. applications.
  91. X
  92. Function Keys
  93. X
  94. The user is free to bind the function keys to various emacs commands. If
  95. this is done, it is recommended that the definitions be kept in a file
  96. named .emacsrc to avoid retyping them (the file ..emacsrc is
  97. automatically read when the editor is invoked). The function keys can
  98. also be redefined on the fly using the menu. The shift and control keys
  99. have no effect when used with the function keys.
  100. X
  101. Altering the definitions is only necessary if the default definitions
  102. are not satisfactory. The default definitions for the function keys are:
  103. X
  104. X      top          right
  105. X
  106. 1)    find file    page up
  107. 2)    read file    top of file
  108. 3)    insert file    reverse incremental search
  109. 4)    view file    page down
  110. 5)    save file    end of file
  111. 6)    write file    incremental search
  112. 7)    rename file    beginning of line
  113. 8)    copy region    cursor up
  114. 9)    get argument    end of line
  115. 10)            cursor left
  116. 11)            set mark
  117. 12)            cursor right
  118. 13)            previous word
  119. 14)            cursor down
  120. 15)            next word
  121. X
  122. X
  123. "Bugs" and Limitations
  124. X
  125. At present the distribution mechanism is ignorant of key rebindings,
  126. that is, the emacs rebinding function does not alter the timing
  127. information. Care should be taken when binding characters to keys. In
  128. particular, be careful not to rebind the emacs prefix keys ^X or ESC.
  129. Also, since the menu entries send "normal" emacs sequences, rebinding
  130. these sequences should be avoided. Function keys are available for
  131. binding.
  132. X
  133. If for some reason the editing process on the remote machine is killed
  134. by methods other than emacs commands, the window may not be eliminated
  135. (and NeWS might have to be restarted to get rid of it). Currently the
  136. only "correct" ways of terminating are with the window menu "quit" or
  137. "save & exit" choices, or with their equivalent emacs sequences (^X C
  138. and ESC Z). The frame or icon menu "Zap" function will also terminate
  139. the editor, but will not prompt the user for confirmation if changes
  140. have not been saved to files. Do not ^C or otherwise kill the remote
  141. editor.
  142. SHAR_EOF
  143. echo 'File readme.news is complete' &&
  144. chmod 0444 readme.news ||
  145. echo 'restore of readme.news failed'
  146. Wc_c="`wc -c < 'readme.news'`"
  147. test 7014 -eq "$Wc_c" ||
  148.     echo 'readme.news: original size 7014, current size' "$Wc_c"
  149. # ============= region.c ==============
  150. echo 'x - extracting region.c (Text)'
  151. sed 's/^X//' << 'SHAR_EOF' > 'region.c' &&
  152. /*
  153. X * The routines in this file
  154. X * deal with the region, that magic space
  155. X * between "." and mark. Some functions are
  156. X * commands. Some functions are just for
  157. X * internal use.
  158. X */
  159. #include        <stdio.h>
  160. #include    "estruct.h"
  161. #include        "edef.h"
  162. X
  163. #if    MEGAMAX & ST520
  164. overlay    "region"
  165. #endif
  166. X
  167. /*
  168. X * Kill the region. Ask "getregion"
  169. X * to figure out the bounds of the region.
  170. X * Move "." to the start, and kill the characters.
  171. X */
  172. killregion(f, n)
  173. {
  174. X        register int    s;
  175. X        REGION          region;
  176. X
  177. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  178. X        return(rdonly());    /* we are in read only mode    */
  179. X        if ((s=getregion(®ion)) != TRUE)
  180. X                return (s);
  181. X    kregcirculate(TRUE);
  182. X        kdelete();                      /* command, so do magic */
  183. X        curwp->w_dotp = region.r_linep;
  184. X        curwp->w_doto = region.r_offset;
  185. X    if (fulllineregions)
  186. X        kregflag |= KLINES;
  187. X    s = ldelete(region.r_size, TRUE);
  188. X    ukb = 0;
  189. X        return (s);
  190. }
  191. X
  192. /*
  193. X * Copy all of the characters in the
  194. X * region to the kill buffer. Don't move dot
  195. X * at all. This is a bit like a kill region followed
  196. X * by a yank.
  197. X */
  198. yankregion(f, n)
  199. {
  200. X        register LINE   *linep;
  201. X        register int    loffs;
  202. X        register int    s;
  203. X        REGION          region;
  204. X
  205. X        if ((s=getregion(®ion)) != TRUE)
  206. X                return (s);
  207. X    kregcirculate(TRUE);
  208. X        kdelete();
  209. X        linep = region.r_linep;                 /* Current line.        */
  210. X        loffs = region.r_offset;                /* Current offset.      */
  211. X    if (fulllineregions)
  212. X        kregflag |= KLINES|KYANK;
  213. X        while (region.r_size--) {
  214. X                if (loffs == llength(linep)) {  /* End of line.         */
  215. X                        if ((s=kinsert('\n')) != TRUE) {
  216. X                ukb = 0;
  217. X                                return (s);
  218. X            }
  219. X                        linep = lforw(linep);
  220. X                        loffs = 0;
  221. X                } else {                        /* Middle of line.      */
  222. X                        if ((s=kinsert(lgetc(linep, loffs))) != TRUE) {
  223. X                ukb = 0;
  224. X                                return (s);
  225. X            }
  226. X                        ++loffs;
  227. X                }
  228. X        }
  229. X    mlwrite("[region yanked]");
  230. X    ukb = 0;
  231. X        return (TRUE);
  232. }
  233. X
  234. /*
  235. X * shift region left by a tab stop
  236. X */
  237. shiftrregion(f, n)
  238. {
  239. X        register LINE   *linep;
  240. X        register int    loffs;
  241. X        register int    s;
  242. X        REGION          region;
  243. X
  244. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  245. X        return(rdonly());    /* we are in read only mode    */
  246. X        if ((s=getregion(®ion)) != TRUE)
  247. X                return (s);
  248. X        linep = region.r_linep;
  249. X        loffs = region.r_offset;
  250. X    if (loffs != 0) {  /* possibly on first time through */
  251. X        region.r_size -= llength(linep)-loffs+1;
  252. X        loffs = 0;
  253. X        linep = lforw(linep);
  254. X    }
  255. X    s = TRUE;
  256. X    while (region.r_size > 0) {
  257. X        /* adjust r_size now, while line length is right */
  258. X        region.r_size -= llength(linep)+1;
  259. X        if (llength(linep) != 0) {
  260. X            curwp->w_dotp = linep;
  261. X            curwp->w_doto = 0;
  262. X            if ((s = linsert(1,'\t')) != TRUE)
  263. X                return (s);
  264. X        }
  265. X        linep = lforw(linep);
  266. X        }
  267. X    firstnonwhite(f,n);
  268. X    return (TRUE);
  269. }
  270. X
  271. /*
  272. X * shift region left by a tab stop
  273. X */
  274. shiftlregion(f, n)
  275. {
  276. X        register LINE   *linep;
  277. X        register int    loffs;
  278. X        register int    c;
  279. X        register int    s;
  280. X    register int    i;
  281. X        REGION          region;
  282. X
  283. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  284. X        return(rdonly());    /* we are in read only mode    */
  285. X        if ((s=getregion(®ion)) != TRUE)
  286. X                return (s);
  287. X        linep = region.r_linep;
  288. X        loffs = region.r_offset;
  289. X    if (loffs != 0) {  /* possibly on first time through */
  290. X        region.r_size -= llength(linep)-loffs+1;
  291. X        loffs = 0;
  292. X        linep = lforw(linep);
  293. X    }
  294. X    s = TRUE;
  295. X    while (region.r_size > 0) {
  296. X        /* adjust r_size now, while line length is right */
  297. X        region.r_size -= llength(linep)+1;
  298. X        if (llength(linep) != 0) {
  299. X            curwp->w_dotp = linep;
  300. X            curwp->w_doto = 0;
  301. X            if ((c = lgetc(linep,0)) == '\t') { /* delete the tab */
  302. X                i = 1;
  303. X            } else if (c == ' ') {
  304. X                i = 1; 
  305. X                /* after this, i'th char is _not_ a space, 
  306. X                    or 0-7 are spaces  */
  307. X                while ((c = lgetc(linep,i)) == ' ' && i < TABVAL)
  308. X                    i++;
  309. X                if (i != TABVAL && c == '\t') /* ith char is tab */
  310. X                    i++;
  311. X            } else {
  312. X                i = 0;
  313. X            }
  314. X            
  315. X            if ( i!=0 && (s = ldelete((long)i,FALSE)) != TRUE)
  316. X                return (s);
  317. X        }
  318. X        linep = lforw(linep);
  319. X        }
  320. X    firstnonwhite(f,n);
  321. X        return (TRUE);
  322. }
  323. X
  324. _to_lower(c)
  325. {
  326. X    if (isupper(c))
  327. X        return(c ^ DIFCASE);
  328. X    return -1;
  329. }
  330. X
  331. _to_upper(c)
  332. {
  333. X    if (islower(c))
  334. X        return(c ^ DIFCASE);
  335. X    return -1;
  336. }
  337. X
  338. _to_caseflip(c)
  339. {
  340. X    if (isalpha(c))
  341. X        return(c ^ DIFCASE);
  342. X    return -1;
  343. }
  344. X
  345. flipregion(f, n)
  346. {
  347. X    return charprocreg(f,n,_to_caseflip);
  348. }
  349. X
  350. lowerregion(f, n)
  351. {
  352. X    return charprocreg(f,n,_to_lower);
  353. }
  354. X
  355. upperregion(f, n)
  356. {
  357. X    return charprocreg(f,n,_to_upper);
  358. }
  359. X
  360. charprocreg(f, n, func)
  361. int (*func)();
  362. {
  363. X        register LINE   *linep;
  364. X        register int    loffs;
  365. X        register int    c,nc;
  366. X        register int    s;
  367. X        REGION          region;
  368. X
  369. X    if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  370. X        return(rdonly());    /* we are in read only mode    */
  371. X        if ((s=getregion(®ion)) != TRUE)
  372. X                return (s);
  373. X        lchange(WFHARD);
  374. X        linep = region.r_linep;
  375. X        loffs = region.r_offset;
  376. X        while (region.r_size--) {
  377. X                if (loffs == llength(linep)) {
  378. X                        linep = lforw(linep);
  379. X                        loffs = 0;
  380. X                } else {
  381. X                        c = lgetc(linep, loffs);
  382. X            nc = (func)(c);
  383. X            if (nc != -1) {
  384. X                copy_for_undo(linep);
  385. X                                lputc(linep, loffs, nc);
  386. X            }
  387. X                        ++loffs;
  388. X                }
  389. X        }
  390. X        return (TRUE);
  391. }
  392. X
  393. /*
  394. X * This routine figures out the
  395. X * bounds of the region in the current window, and
  396. X * fills in the fields of the "REGION" structure pointed
  397. X * to by "rp". Because the dot and mark are usually very
  398. X * close together, we scan outward from dot looking for
  399. X * mark. This should save time. Return a standard code.
  400. X */
  401. getregion(rp)
  402. register REGION *rp;
  403. {
  404. X        register LINE   *flp;
  405. X        register LINE   *blp;
  406. X        long fsize;
  407. X        long bsize;
  408. X
  409. X        if (curwp->w_mkp == NULL) {
  410. X                mlwrite("No mark set in this window");
  411. X                return FALSE;
  412. X        }
  413. X        if (curwp->w_dotp == curwp->w_mkp) {
  414. X                rp->r_linep = curwp->w_dotp;
  415. X        if (fulllineregions) {
  416. X                        rp->r_offset = 0;
  417. X                        rp->r_size = (long)llength(curwp->w_dotp)+1;
  418. X                    rp->r_endlinep = lforw(curwp->w_dotp);
  419. X                        rp->r_endoffset = 0;
  420. X            return TRUE;
  421. X        }
  422. X                rp->r_endlinep = curwp->w_dotp;
  423. X                if (curwp->w_doto < curwp->w_mko) {
  424. X                        rp->r_offset = curwp->w_doto;
  425. X                        rp->r_size = (long)(curwp->w_mko-curwp->w_doto);
  426. X                        rp->r_endoffset = curwp->w_mko;
  427. X                } else {
  428. X                        rp->r_offset = curwp->w_mko;
  429. X                        rp->r_size = (long)(curwp->w_doto-curwp->w_mko);
  430. X                        rp->r_endoffset = curwp->w_doto;
  431. X                }
  432. X                return TRUE;
  433. X        }
  434. X        blp = curwp->w_dotp;
  435. X        flp = curwp->w_dotp;
  436. X    if (fulllineregions) {
  437. X        bsize = (long)(llength(blp)+1);
  438. X        fsize = (long)(llength(flp)+1);
  439. X    } else {
  440. X        bsize = (long)curwp->w_doto;
  441. X        fsize = (long)(llength(flp)-curwp->w_doto+1);
  442. X    }
  443. X        while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
  444. X                if (flp != curbp->b_linep) {
  445. X                        flp = lforw(flp);
  446. X                        if (flp == curwp->w_mkp) {
  447. X                                rp->r_linep = curwp->w_dotp;
  448. X                if (fulllineregions) {
  449. X                    rp->r_offset = 0;
  450. X                    rp->r_size = fsize+
  451. X                            llength(curwp->w_mkp)+1;
  452. X                                    rp->r_endlinep = lforw(flp);
  453. X                    rp->r_endoffset = 0;
  454. X                                    return TRUE;
  455. X                }
  456. X                rp->r_offset = curwp->w_doto;
  457. X                rp->r_size = fsize+curwp->w_mko;
  458. X                                rp->r_endlinep = flp;
  459. X                rp->r_endoffset = curwp->w_mko;
  460. X                                return TRUE;
  461. X                        }
  462. X                        fsize += llength(flp)+1;
  463. X                }
  464. X                if (lback(blp) != curbp->b_linep) {
  465. X                        blp = lback(blp);
  466. X                        bsize += llength(blp)+1;
  467. X                        if (blp == curwp->w_mkp) {
  468. X                                rp->r_linep = blp;
  469. X                if (fulllineregions) {
  470. X                    rp->r_offset = 0;
  471. X                    rp->r_size = bsize;
  472. X                                    rp->r_endlinep = lforw(curwp->w_dotp);
  473. X                    rp->r_endoffset = 0;
  474. X                                    return TRUE;
  475. X                }
  476. X                                rp->r_endlinep = curwp->w_dotp;
  477. X                rp->r_endoffset = curwp->w_doto;
  478. X                rp->r_offset = curwp->w_mko;
  479. X                rp->r_size = bsize - curwp->w_mko;
  480. X                                return TRUE;
  481. X                        }
  482. X                }
  483. X        }
  484. X        mlwrite("Bug: lost mark");
  485. X        return FALSE;
  486. }
  487. X
  488. SHAR_EOF
  489. chmod 0444 region.c ||
  490. echo 'restore of region.c failed'
  491. Wc_c="`wc -c < 'region.c'`"
  492. test 9127 -eq "$Wc_c" ||
  493.     echo 'region.c: original size 9127, current size' "$Wc_c"
  494. # ============= search.c ==============
  495. echo 'x - extracting search.c (Text)'
  496. sed 's/^X//' << 'SHAR_EOF' > 'search.c' &&
  497. /*
  498. X * The functions in this file implement commands that search in the forward
  499. X * and backward directions.
  500. X *  heavily modified by Paul Fox, 1990
  501. X *
  502. X * Aug. 1986 John M. Gamble:
  503. X *    ... a limited number of regular expressions - 'any',
  504. X *    'character class', 'closure', 'beginning of line', and
  505. X *    'end of line'.
  506. X *
  507. X *    Replacement metacharacters will have to wait for a re-write of
  508. X *    the replaces function, and a new variation of ldelete().
  509. X *
  510. X *    For those curious as to my references, i made use of
  511. X *    Kernighan & Plauger's "Software Tools."
  512. X *    I deliberately did not look at any published grep or editor
  513. X *    source (aside from this one) for inspiration.  I did make use of
  514. X *    Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
  515. X *    June, 1985 and modified them for the limited needs of character class
  516. X *    matching.  Any inefficiences, bugs, stupid coding examples, etc.,
  517. X *    are therefore my own responsibility.
  518. X *
  519. X */
  520. X
  521. #include        <stdio.h>
  522. #include    "estruct.h"
  523. #include        "edef.h"
  524. X
  525. #if    LATTICE
  526. #define    void    int
  527. #endif
  528. X
  529. int    mcmatch();
  530. int    readpattern();
  531. #if SEARCH_AND_REPLACE
  532. int    replaces();
  533. #endif
  534. int    nextch();
  535. #if MAGIC
  536. int    mcstr();
  537. int    mceq();
  538. int    cclmake();
  539. int    biteq();
  540. BITMAP   clearbits();
  541. void     setbit();
  542. #endif
  543. X
  544. int lastdirec;
  545. LINE *boundline;
  546. int boundoff;
  547. X
  548. scrforwsearch(f,n)
  549. {
  550. X    return fsearch(f,n,FALSE,TRUE);
  551. }
  552. X
  553. scrbacksearch(f,n)
  554. {
  555. X    return bsearch(f,n,FALSE,TRUE);
  556. }
  557. X
  558. char onlyonemsg[] = "Only one occurence of pattern";
  559. char notfoundmsg[] = "Not found";
  560. X
  561. /*
  562. X * forwsearch -- Search forward.  Get a search string from the user, and
  563. X *    search for the string.  If found, reset the "." to be just after
  564. X *    the match string, and (perhaps) repaint the display.
  565. X */
  566. X
  567. forwsearch(f, n)
  568. int f, n;
  569. {
  570. X    fsearch(f, n, FALSE, NULL);
  571. }
  572. X
  573. /* extra args -- marking if called from globals, and should mark lines, and
  574. X    fromscreen, if the searchpattern is on the screen, so we don't need to
  575. X    ask for it.  */
  576. fsearch(f, n, marking, fromscreen)
  577. int f, n;
  578. {
  579. X    register int status = TRUE;
  580. X    int wrapok;
  581. X    int c;
  582. X    LINE *curdotp;
  583. X    int curoff;
  584. X    int didmark = FALSE;
  585. X
  586. X    if (f && n < 0)
  587. X        return bsearch(f, -n, NULL, NULL);
  588. X
  589. X    wrapok = marking || (curwp->w_bufp->b_mode & MDSWRAP) != 0;
  590. X
  591. X    lastdirec = 0;
  592. X
  593. X    /* Ask the user for the text of a pattern.  If the
  594. X     * response is TRUE (responses other than FALSE are
  595. X     * possible), search for the pattern for as long as
  596. X     * n is positive (n == 0 will go through once, which
  597. X     * is just fine).
  598. X     *
  599. X     * If "marking", then we were called to do line marking for the
  600. X     *  global command.
  601. X     */
  602. X    if (!marking && (status = readpattern("Search: ", &pat[0],
  603. X                    TRUE, lastkey, fromscreen)) != TRUE) {
  604. X        return status;
  605. X    }
  606. X        
  607. X    curdotp = curwp->w_dotp;
  608. X    curoff = curwp->w_doto;
  609. X    setboundry(wrapok,curwp->w_dotp,curwp->w_doto,FORWARD);
  610. X    do {
  611. X        nextch(&(curwp->w_dotp),&(curwp->w_doto), FORWARD,wrapok);
  612. X        status = thescanner(&pat[0], FORWARD, PTBEG, wrapok);
  613. X        if (status == ABORT) {
  614. X            TTbeep();
  615. X            mlwrite("[Aborted]");
  616. X            curwp->w_dotp = curdotp;
  617. X            curwp->w_doto = curoff;
  618. X            return status;
  619. X        }
  620. X        /* if found, mark the line */
  621. X        if (status && marking) {
  622. X            /* if we were on a match when we started, then
  623. X                thescanner returns TRUE, even though it's
  624. X                on a boundary. quit if we find ourselves
  625. X                marking a line twice */
  626. X            if (lismarked(curwp->w_dotp))
  627. X                break;
  628. X            lsetmarked(curwp->w_dotp);
  629. X            /* and, so the next nextch gets to next line */
  630. X            curwp->w_doto = llength(curwp->w_dotp);
  631. X            didmark = TRUE;
  632. X        }
  633. X    } while ((marking || --n > 0) && status == TRUE);
  634. X    
  635. X    if (!marking && !status)
  636. X        nextch(&(curwp->w_dotp),&(curwp->w_doto), REVERSE,wrapok);
  637. X        
  638. X    if (marking) {  /* restore dot and offset */
  639. X        curwp->w_dotp = curdotp;
  640. X        curwp->w_doto = curoff;
  641. X    } else if (status) {
  642. X        savematch();
  643. X        if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
  644. X            mlwrite(onlyonemsg);
  645. X            TTbeep();
  646. X        }
  647. X    }
  648. X
  649. X    /* Complain if not there.  */
  650. X    if ((marking && didmark == FALSE) ||
  651. X                (!marking && status == FALSE)) {
  652. X        mlwrite(notfoundmsg);
  653. X        TTbeep();
  654. X        return FALSE;
  655. X    }
  656. X    
  657. X    return TRUE;
  658. }
  659. X
  660. /*
  661. X * forwhunt -- Search forward for a previously acquired search string.
  662. X *    If found, reset the "." to be just after the match string,
  663. X *    and (perhaps) repaint the display.
  664. X */
  665. X
  666. forwhunt(f, n)
  667. int f, n;    /* default flag / numeric argument */
  668. {
  669. X    register int status = TRUE;
  670. X    int wrapok;
  671. X    LINE *curdotp;
  672. X    int curoff;
  673. X    
  674. X    wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
  675. X
  676. X    if (n < 0)        /* search backwards */
  677. X        return(backhunt(f, -n));
  678. X
  679. X    /* Make sure a pattern exists, or that we didn't switch
  680. X     * into MAGIC mode until after we entered the pattern.
  681. X     */
  682. X    if (pat[0] == '\0')
  683. X    {
  684. X        mlwrite("No pattern set");
  685. X        return FALSE;
  686. X    }
  687. X    /* mlwrite("Searching ahead..."); */
  688. #if    MAGIC
  689. X    if ((curwp->w_bufp->b_mode & MDMAGIC) && (mcpat[0].mc_type == MCNIL))
  690. X    {
  691. X        if (!mcstr())
  692. X            return FALSE;
  693. X    }
  694. #endif
  695. X
  696. X    /* Search for the pattern for as long as
  697. X     * n is positive (n == 0 will go through once, which
  698. X     * is just fine).
  699. X     */
  700. X    curdotp = curwp->w_dotp;
  701. X    curoff = curwp->w_doto;
  702. X    setboundry(wrapok,curwp->w_dotp,curwp->w_doto,FORWARD);
  703. X    do {
  704. X        nextch(&(curwp->w_dotp),&(curwp->w_doto),FORWARD,wrapok);
  705. X        status = thescanner(&pat[0], FORWARD, PTBEG, wrapok);
  706. X    } while ((--n > 0) && status == TRUE);
  707. X
  708. X    /* Save away the match, or complain if not there.  */
  709. X    if (status == TRUE) {
  710. X        savematch();
  711. X        if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
  712. X            mlwrite(onlyonemsg);
  713. X            TTbeep();
  714. X        }
  715. X    } else if (status == FALSE) {
  716. X        nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,wrapok);
  717. X        mlwrite(notfoundmsg);
  718. X        TTbeep();
  719. X    } else if (status == ABORT) {
  720. X        TTbeep();
  721. X        mlwrite("[Aborted]");
  722. X        curwp->w_dotp = curdotp;
  723. X        curwp->w_doto = curoff;
  724. X        return status;
  725. X    }
  726. X
  727. X    return(status);
  728. }
  729. X
  730. /*
  731. X * backsearch -- Reverse search.  Get a search string from the user, and
  732. X *    search, starting at "." and proceeding toward the front of the buffer.
  733. X *    If found "." is left pointing at the first character of the pattern
  734. X *    (the last character that was matched).
  735. X */
  736. backsearch(f, n)
  737. int f, n;
  738. {
  739. X    return bsearch(f, n, FALSE, NULL);
  740. }
  741. X
  742. bsearch(f, n, dummy, fromscreen)
  743. int f, n;    /* default flag / numeric argument */
  744. {
  745. X    register int status = TRUE;
  746. X    int wrapok;
  747. X    LINE *curdotp;
  748. X    int curoff;
  749. X    
  750. X    if (n < 0)
  751. X        return fsearch(f, -n, NULL, fromscreen);
  752. X
  753. X    wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
  754. X
  755. X    lastdirec = 1;
  756. X
  757. X    /* Ask the user for the text of a pattern.  If the
  758. X     * response is TRUE (responses other than FALSE are
  759. X     * possible), search for the pattern for as long as
  760. X     * n is positive (n == 0 will go through once, which
  761. X     * is just fine).
  762. X     */
  763. X    if ((status = readpattern("Reverse search: ", &pat[0],
  764. X                    TRUE, lastkey, fromscreen)) == TRUE) {
  765. X        curdotp = curwp->w_dotp;
  766. X        curoff = curwp->w_doto;
  767. X        setboundry(wrapok,curwp->w_dotp,curwp->w_doto,REVERSE);
  768. X        do {
  769. X            nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,
  770. X                                    wrapok);
  771. X            status = thescanner(&tap[0], REVERSE, PTBEG, wrapok);
  772. X        } while ((--n > 0) && status == TRUE);
  773. X
  774. X        /* Save away the match, or complain if not there.  */
  775. X        if (status == TRUE)
  776. X            savematch();
  777. X            if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
  778. X                mlwrite(onlyonemsg);
  779. X                TTbeep();
  780. X            }
  781. X        else if (status == FALSE) {
  782. X            nextch(&(curwp->w_dotp),&(curwp->w_doto),FORWARD,
  783. X                                    wrapok);
  784. X            mlwrite(notfoundmsg);
  785. X            TTbeep();
  786. X        } else if (status == ABORT) {
  787. X            TTbeep();
  788. X            mlwrite("[Aborted]");
  789. X            curwp->w_dotp = curdotp;
  790. X            curwp->w_doto = curoff;
  791. X            return status;
  792. X        }
  793. X    }
  794. X    return(status);
  795. }
  796. X
  797. /*
  798. X * backhunt -- Reverse search for a previously acquired search string,
  799. X *    starting at "." and proceeding toward the front of the buffer.
  800. X *    If found "." is left pointing at the first character of the pattern
  801. X *    (the last character that was matched).
  802. X */
  803. backhunt(f, n)
  804. int f, n;    /* default flag / numeric argument */
  805. {
  806. X    register int status = TRUE;
  807. X    int wrapok;
  808. X    LINE *curdotp;
  809. X    int curoff;
  810. X    
  811. X    wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
  812. X
  813. X    if (n < 0)
  814. X        return(forwhunt(f, -n));
  815. X
  816. X    /* Make sure a pattern exists, or that we didn't switch
  817. X     * into MAGIC mode until after we entered the pattern.
  818. X     */
  819. X    if (tap[0] == '\0')
  820. X    {
  821. X        mlwrite("No pattern set");
  822. X        return FALSE;
  823. X    }
  824. X    /* mlwrite("Searching back..."); */
  825. #if    MAGIC
  826. X    if ((curwp->w_bufp->b_mode & MDMAGIC) && (tapcm[0].mc_type == MCNIL))
  827. X    {
  828. X        if (!mcstr())
  829. X            return FALSE;
  830. X    }
  831. #endif
  832. X
  833. X    /* Go search for it for as long as
  834. X     * n is positive (n == 0 will go through once, which
  835. X     * is just fine).
  836. X     */
  837. X
  838. X    curdotp = curwp->w_dotp;
  839. X    curoff = curwp->w_doto;
  840. X    setboundry(wrapok,curwp->w_dotp,curwp->w_doto,REVERSE);
  841. X    do {
  842. X        nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,wrapok);
  843. X        status = thescanner(&tap[0], REVERSE, PTBEG, wrapok);
  844. X    } while ((--n > 0) && status == TRUE);
  845. X
  846. X    /* Save away the match, or complain
  847. X     * if not there.
  848. X     */
  849. X    if (status == TRUE) {
  850. X        savematch();
  851. X        if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
  852. X            mlwrite(onlyonemsg);
  853. X            TTbeep();
  854. X        }
  855. X    } else if (status == FALSE) {
  856. X        nextch(&(curwp->w_dotp),&(curwp->w_doto), FORWARD,wrapok);
  857. X        mlwrite(notfoundmsg);
  858. X        TTbeep();
  859. X    } else if (status == ABORT) {
  860. X        TTbeep();
  861. X        mlwrite("[Aborted]");
  862. X        curwp->w_dotp = curdotp;
  863. X        curwp->w_doto = curoff;
  864. X        return status;
  865. X    }
  866. X
  867. X    return(status);
  868. }
  869. X
  870. consearch(f,n)
  871. {
  872. X    if (lastdirec == 0)
  873. X        return(forwhunt(f,n));
  874. X    else
  875. X        return(backhunt(f,n));
  876. }
  877. X
  878. revsearch(f,n)
  879. {
  880. X    if (lastdirec == 0)
  881. X        return(backhunt(f,n));
  882. X    else
  883. X        return(forwhunt(f,n));
  884. }
  885. X
  886. X
  887. /*
  888. X * thescanner -- Search for a pattern in either direction.  If found,
  889. X *    reset the "." to be at the start or just after the match string,
  890. X *    and (perhaps) repaint the display.
  891. X */
  892. int    
  893. thescanner(patrn, direct, beg_or_end, wrapok)
  894. char    *patrn;        /* pointer into pattern */
  895. int    direct;        /* which way to go.*/
  896. int    beg_or_end;    /* put point at beginning or end of pattern.*/
  897. {
  898. X    LINE *curline;            /* current line during scan */
  899. X    int curoff;            /* position within current line */
  900. X    int found;
  901. X    int (*matcher)();
  902. X    int mcmatch();
  903. X    int litmatch();
  904. X
  905. X    /* If we are going in reverse, then the 'end' is actually
  906. X     * the beginning of the pattern.  Toggle it.
  907. X     */
  908. X    beg_or_end ^= direct;
  909. X
  910. X    /*
  911. X     * Save the old matchlen length, in case it is
  912. X     * horribly different (closure) from the old length.
  913. X     * This is terribly important for query-replace undo
  914. X     * command.
  915. X     */
  916. X    mlenold = matchlen;
  917. X
  918. X    /* Setup local scan pointers to global ".".
  919. X     */
  920. X    curline = curwp->w_dotp;
  921. X    curoff  = curwp->w_doto;
  922. #if MAGIC
  923. X    if (magical && (curwp->w_bufp->b_mode & MDMAGIC)) {
  924. X        matcher = mcmatch;
  925. X        if (direct == FORWARD)
  926. X            patrn = (char *)mcpat;
  927. X        else
  928. X            patrn = (char *)tapcm;
  929. X    } else
  930. #endif
  931. X    {
  932. X        matcher = litmatch;
  933. X        if (direct == FORWARD)
  934. X            patrn = pat;
  935. X        else
  936. X            patrn = tap;
  937. X    }
  938. X            
  939. X    /* Scan each character until we hit the head link record.
  940. X     */
  941. X    do {
  942. X        if (interrupted) return ABORT;
  943. X
  944. X        /* Save the current position in case we need to
  945. X         * restore it on a match, and initialize matchlen to
  946. X         * zero in case we are doing a search for replacement.
  947. X         */
  948. X        matchline = curline;
  949. X        matchoff = curoff;
  950. X        matchlen = 0;
  951. X        
  952. X        if ((*matcher)(patrn, direct, &curline, &curoff)) {
  953. X            /* A SUCCESSFULL MATCH!!!
  954. X             * reset the global "." pointers.
  955. X             */
  956. X            if (beg_or_end == PTEND)    /* at end of string */
  957. X            {
  958. X                curwp->w_dotp = curline;
  959. X                curwp->w_doto = curoff;
  960. X            }
  961. X            else        /* at beginning of string */
  962. X            {
  963. X                curwp->w_dotp = matchline;
  964. X                curwp->w_doto = matchoff;
  965. X            }
  966. X
  967. X            curwp->w_flag |= WFMOVE; /* flag that we have moved */
  968. X            return TRUE;
  969. X        }
  970. X
  971. X        /* Advance the cursor.
  972. X         */
  973. X        nextch(&curline, &curoff, direct,wrapok);
  974. X    } while (!boundry(curline, curoff, direct, wrapok));
  975. X
  976. X    return FALSE;    /* We could not find a match.*/
  977. }
  978. X
  979. #if MAGIC
  980. /*
  981. X * mcmatch -- Search for a meta-pattern in either direction.  Based on the
  982. X *    recursive routine amatch() (for "anchored match") in
  983. X *    Kernighan & Plauger's "Software Tools".
  984. X */
  985. mcmatch(mcptr, direct, pcwline, pcwoff)
  986. register MC    *mcptr;    /* string to scan for */
  987. int        direct;        /* which way to go.*/
  988. LINE        **pcwline;    /* current line during scan */
  989. int        *pcwoff;    /* position within current line */
  990. {
  991. X    register int c;            /* character at current position */
  992. X    LINE *curline;            /* current line during scan */
  993. X    int curoff;            /* position within current line */
  994. X    int nchars;
  995. X
  996. X    /* Set up local scan pointers to ".", and get
  997. X     * the current character.  Then loop around
  998. X     * the pattern pointer until success or failure.
  999. X     */
  1000. X    curline = *pcwline;
  1001. X    curoff = *pcwoff;
  1002. X
  1003. X    /* The beginning-of-line and end-of-line metacharacters
  1004. X     * do not compare against characters, they compare
  1005. X     * against positions.
  1006. X     * BOL is guaranteed to be at the start of the pattern
  1007. X     * for forward searches, and at the end of the pattern
  1008. X     * for reverse searches.  The reverse is true for EOL.
  1009. X     * So, for a start, we check for them on entry.
  1010. X     */
  1011. X    if (mcptr->mc_type == BOL)
  1012. X    {
  1013. X        if (curoff != 0)
  1014. X            return FALSE;
  1015. X        mcptr++;
  1016. X    }
  1017. X
  1018. X    if (mcptr->mc_type == EOL)
  1019. X    {
  1020. X        if (curoff != llength(curline))
  1021. X            return FALSE;
  1022. X        mcptr++;
  1023. X    }
  1024. X
  1025. X    while (mcptr->mc_type != MCNIL)
  1026. X    {
  1027. X        c = nextch(&curline, &curoff, direct, FALSE);
  1028. X
  1029. X        if (mcptr->mc_type & CLOSURE)
  1030. X        {
  1031. X            /* Try to match as many characters as possible
  1032. X             * against the current meta-character.  A
  1033. X             * newline or boundary never matches a closure.
  1034. X             */
  1035. X            nchars = 0;
  1036. X            while (c != '\n' && c != -1 && mceq(c, mcptr))
  1037. X            {
  1038. X                nchars++;
  1039. X                c = nextch(&curline, &curoff, direct, FALSE);
  1040. X            }
  1041. X
  1042. X            /* We are now at the character that made us
  1043. X             * fail.  nchars is the number of successful
  1044. X             * matches.  Try to match the rest of the pattern.
  1045. X             * Shrink the closure by one for each failure.
  1046. X             * Since closure matches *zero* or more occurences
  1047. X             * of a pattern, a match may start even if the
  1048. X             * previous loop matched no characters.
  1049. X             */
  1050. X            mcptr++;
  1051. X
  1052. X            for (;;)
  1053. X            {
  1054. X                /* back up, since mcmatch goes forward first */
  1055. X                (void)nextch(&curline, &curoff, 
  1056. X                    direct ^ REVERSE, FALSE);
  1057. X
  1058. X                if (mcmatch(mcptr, direct, &curline, &curoff))
  1059. X                {
  1060. X                    matchlen += nchars;
  1061. X                    goto success;
  1062. X                }
  1063. X
  1064. X                if (nchars-- == 0)
  1065. X                    return FALSE;
  1066. X            }
  1067. X        }
  1068. X        else            /* Not closure.*/
  1069. X        {
  1070. X            /* The only way we'd get a BOL metacharacter
  1071. X             * at this point is at the end of the reversed pattern.
  1072. X             * The only way we'd get an EOL metacharacter
  1073. X             * here is at the end of a regular pattern.
  1074. X             * So if we match one or the other, and are at
  1075. X             * the appropriate position, we are guaranteed success
  1076. X             * (since the next pattern character has to be MCNIL).
  1077. X             * Before we report success, however, we back up by
  1078. X             * one character, so as to leave the cursor in the
  1079. X             * correct position.  For example, a search for ")$"
  1080. X             * will leave the cursor at the end of the line, while
  1081. X             * a search for ")<NL>" will leave the cursor at the
  1082. X             * beginning of the next line.  This follows the
  1083. X             * notion that the meta-character '$' (and likewise
  1084. X             * '^') match positions, not characters.
  1085. X             */
  1086. X            if (mcptr->mc_type == BOL)
  1087. X            {
  1088. X                if (curoff == llength(curline))
  1089. X                {
  1090. X                    (void)nextch(&curline, &curoff,
  1091. X                           direct ^ REVERSE, FALSE);
  1092. X                    goto success;
  1093. X                }
  1094. X                else
  1095. X                {
  1096. X                    return FALSE;
  1097. X                }
  1098. X            }
  1099. X            if (mcptr->mc_type == EOL)
  1100. X            {
  1101. X                if (curoff == 0)
  1102. X                {
  1103. X                    (void)nextch(&curline, &curoff,
  1104. X                           direct ^ REVERSE, FALSE);
  1105. X                    goto success;
  1106. X                }
  1107. X                else
  1108. X                {
  1109. X                    return FALSE;
  1110. X                }
  1111. X            }
  1112. X                
  1113. X
  1114. X            /* Neither BOL nor EOL, so go through
  1115. X             * the meta-character equal function.
  1116. X             */
  1117. X            if (!mceq(c, mcptr))
  1118. X                return FALSE;
  1119. X        }
  1120. X
  1121. X        /* Increment the length counter and
  1122. X         * advance the pattern pointer.
  1123. X         */
  1124. X        matchlen++;
  1125. X        mcptr++;
  1126. X    }            /* End of mcptr loop.*/
  1127. X
  1128. X    /* A SUCCESSFULL MATCH!!!
  1129. X     * Reset the "." pointers.
  1130. X     */
  1131. success:
  1132. X    *pcwline = curline;
  1133. X    *pcwoff  = curoff;
  1134. X    
  1135. X
  1136. X    return TRUE;
  1137. }
  1138. #endif
  1139. X
  1140. /*
  1141. X * litmatch -- Search for a literal match in either direction.
  1142. X */
  1143. litmatch(patptr, direct, pcwline, pcwoff)
  1144. register char    *patptr;    /* string to scan for */
  1145. int        direct;        /* which way to go.*/
  1146. LINE        **pcwline;    /* current line during scan */
  1147. int        *pcwoff;    /* position within current line */
  1148. {
  1149. X    register int c;            /* character at current position */
  1150. X    LINE *curline;        /* current line during scan */
  1151. X    int curoff;        /* position within current line */
  1152. X
  1153. X    /* Set up local scan pointers to ".", and get
  1154. X     * the current character.  Then loop around
  1155. X     * the pattern pointer until success or failure.
  1156. X     */
  1157. X    curline = *pcwline;
  1158. X    curoff = *pcwoff;
  1159. X
  1160. X    while (*patptr != '\0') {
  1161. X        c = nextch(&curline, &curoff, direct, FALSE);
  1162. X
  1163. X        if (!eq(c, *patptr))
  1164. X            return FALSE;
  1165. X
  1166. X        /* Increment the length counter and
  1167. X         * advance the pattern pointer.
  1168. X         */
  1169. X        matchlen++;
  1170. X        patptr++;
  1171. X    }
  1172. X
  1173. X    *pcwline = curline;
  1174. X    *pcwoff  = curoff;
  1175. X    
  1176. X
  1177. X    return TRUE;
  1178. }
  1179. X
  1180. X
  1181. /*
  1182. X * eq -- Compare two characters.  The "bc" comes from the buffer, "pc"
  1183. X *    from the pattern.  If we are not in EXACT mode, fold out the case.
  1184. X */
  1185. int    
  1186. eq(bc, pc)
  1187. register char    bc;
  1188. register char    pc;
  1189. {
  1190. X    if (curwp->w_bufp->b_mode & MDEXACT)
  1191. X        return (bc ^ pc) == 0;
  1192. X    /* take out the bit that makes upper and lowercase different */
  1193. X    return ((bc ^ pc) & ~DIFCASE) == 0;
  1194. }
  1195. X
  1196. scrsearchpat(f,n)
  1197. {
  1198. X    int s;
  1199. X    s =  readpattern("", pat, TRUE, 0, TRUE);
  1200. X    mlwrite("Search pattern is now %s", pat);
  1201. X    lastdirec = 0;
  1202. X    return s;
  1203. }
  1204. /*
  1205. X * readpattern -- Read a pattern.  Stash it in apat.  If it is the
  1206. X *    search string, create the reverse pattern and the magic
  1207. X *    pattern, assuming we are in MAGIC mode (and defined that way).
  1208. X *    Apat is not updated if the user types in an empty line.  If
  1209. X *    the user typed an empty line, and there is no old pattern, it is
  1210. X *    an error.  Display the old pattern, in the style of Jeff Lomicka.
  1211. X *    There is some do-it-yourself control expansion.
  1212. X *    An alternate termination character is passed in.
  1213. X */
  1214. readpattern(prompt, apat, srch, c, fromscreen)
  1215. char    *prompt;
  1216. char    *apat;
  1217. int    srch;
  1218. int    fromscreen;
  1219. {
  1220. X    int status;
  1221. X
  1222. X    /* Read a pattern.  Either we get one,
  1223. X     * or we just get the META charater, and use the previous pattern.
  1224. X     * Then, if it's the search string, make a reversed pattern.
  1225. X     * *Then*, make the meta-pattern, if we are defined that way.
  1226. X     */
  1227. X    if (fromscreen) {
  1228. X         status = screen_string(apat, NPAT, _ident);
  1229. X        if (status != TRUE)
  1230. X            return status;
  1231. X    } else {
  1232. X         status = kbd_string(prompt, apat, NPAT, c, NO_EXPAND);
  1233. X    }
  1234. X     if (status == TRUE) {
  1235. X        if (srch) {    /* If we are doing the search string.*/
  1236. X            mlenold = matchlen = strlen(apat);
  1237. X            /* Reverse string copy.
  1238. X             */
  1239. X            rvstrcpy(tap, apat);
  1240. #if    MAGIC
  1241. X            /* Only make the meta-pattern if in magic mode,
  1242. X             * since the pattern in question might have an
  1243. X             * invalid meta combination.
  1244. X             */
  1245. X            if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
  1246. X                mcclear();
  1247. X            else
  1248. X                status = mcstr();
  1249. #endif
  1250. X        }
  1251. X    } else if (status == FALSE && *apat != 0) { /* Old one */
  1252. X        status = TRUE;
  1253. X    }
  1254. X
  1255. X    return status;
  1256. }
  1257. X
  1258. /*
  1259. X * savematch -- We found the pattern?  Let's save it away.
  1260. X */
  1261. X
  1262. savematch()
  1263. {
  1264. X    register char *ptr;    /* ptr into malloced last match string */
  1265. X    register int j;        /* index */
  1266. X    LINE *curline;        /* line of last match */
  1267. X    int curoff;        /* offset "      "    */
  1268. X
  1269. X    /* free any existing match string */
  1270. X    if (patmatch != NULL)
  1271. X        free(patmatch);
  1272. X
  1273. X    /* attempt to allocate a new one */
  1274. X    ptr = patmatch = malloc(matchlen + 1);
  1275. X    if (ptr == NULL)
  1276. X        return;
  1277. X
  1278. X    /* save the match! */
  1279. X    curoff = matchoff;
  1280. X    curline = matchline;
  1281. X
  1282. X    for (j = 0; j < matchlen; j++)
  1283. X        *ptr++ = nextch(&curline, &curoff, FORWARD, FALSE);
  1284. X
  1285. X    /* null terminate the match string */
  1286. X    *ptr = '\0';
  1287. }
  1288. X
  1289. /*
  1290. X * rvstrcpy -- Reverse string copy.
  1291. X */
  1292. rvstrcpy(rvstr, str)
  1293. register char    *rvstr, *str;
  1294. {
  1295. X    register int i;
  1296. X
  1297. X    str += (i = strlen(str));
  1298. X
  1299. X    while (i-- > 0)
  1300. X        *rvstr++ = *--str;
  1301. X
  1302. X    *rvstr = '\0';
  1303. }
  1304. X
  1305. rvstrncpy(rvstr, str, n)
  1306. register char    *rvstr, *str;
  1307. {
  1308. X    register int i;
  1309. X
  1310. X    i = strlen(str);
  1311. X    if (n < i) i = n;
  1312. X
  1313. X    str += i;
  1314. X
  1315. X    while (i-- > 0)
  1316. X        *rvstr++ = *--str;
  1317. X
  1318. X    *rvstr = '\0';
  1319. }
  1320. X
  1321. #if SEARCH_AND_REPLACE
  1322. /*
  1323. X * sreplace -- Search and replace.
  1324. X */
  1325. sreplace(f, n)
  1326. {
  1327. X    return replaces(FALSE, f, n);
  1328. }
  1329. X
  1330. /*
  1331. X * qreplace -- search and replace with query.
  1332. X */
  1333. qreplace(f, n)
  1334. {
  1335. X    register int s;
  1336. X    s = replaces(TRUE, f, n);
  1337. #if    NeWS    /* user must not buffer output */
  1338. X    newsimmediateoff() ;
  1339. #endif
  1340. X    return(s) ;
  1341. }
  1342. X
  1343. /*
  1344. X * replaces -- Search for a string and replace it with another
  1345. X *    string.  Query might be enabled (according to kind).
  1346. X * f,n unused
  1347. X */
  1348. replaces(kind, f, n)
  1349. int    kind;    /* Query enabled flag */
  1350. {
  1351. X    register int status;    /* success flag on pattern inputs */
  1352. X    register int rlength;    /* length of replacement string */
  1353. X    register int numsub;    /* number of substitutions */
  1354. X    int nlflag;        /* last char of search string a <NL>? */
  1355. X    int nlrepl;        /* was a replace done on the last line? */
  1356. X    int c;            /* input char for query */
  1357. X    char tpat[NPAT];    /* temporary to hold search pattern */
  1358. X    LINE *lastline;        /* position of last replace and */
  1359. X    int lastoff;        /* offset (for 'u' query option) */
  1360. X    REGION region;
  1361. X
  1362. X    /* we don't really care much about size, etc., but getregion does
  1363. X        a nice job of scanning for the mark, so we use it.  Then
  1364. X        we pretend that wrapping around the bottom of the file is
  1365. X        okay, and use the boundary code to keep us from going
  1366. X        past the region end. */
  1367. X    if (curwp->w_mkp == curwp->w_dotp) {
  1368. X        if (curwp->w_doto > curwp->w_mko) {
  1369. X            int tmpoff;
  1370. X            tmpoff = curwp->w_doto;
  1371. X            curwp->w_doto = curwp->w_mko;
  1372. X            curwp->w_mko = tmpoff;
  1373. X        }
  1374. X    } else {
  1375. X        getregion(®ion);
  1376. X        if (region.r_linep == curwp->w_mkp)
  1377. X            swapmark();
  1378. X    }
  1379. X    if (fulllineregions) {
  1380. X        curwp->w_doto = 0;
  1381. X        curwp->w_mko = llength(curwp->w_mkp);
  1382. X    }
  1383. X    if (curwp->w_mkp == curbp->b_linep) {
  1384. X        mlwrite("BUG: mark is at b_linep");
  1385. X        return FALSE;
  1386. X    }
  1387. X
  1388. X    /* Ask the user for the text of a pattern.
  1389. X     */
  1390. X    if ((status = readpattern(
  1391. X        (kind == FALSE ? "Replace: " : "Query replace: "),
  1392. X                 &pat[0], TRUE, '\n', FALSE)) != TRUE)
  1393. X        return status;
  1394. X
  1395. X    /* Ask for the replacement string.
  1396. X     */
  1397. X    if ((status = readpattern("with: ", &rpat[0], FALSE, '\n', FALSE))
  1398. X                                == ABORT)
  1399. X        return status;
  1400. X
  1401. X    /* Find the length of the replacement string.
  1402. X     */
  1403. X    rlength = strlen(&rpat[0]);
  1404. X
  1405. X    /* Set up flags so we can make sure not to do a recursive
  1406. X     * replace on the last line.
  1407. X     */
  1408. X    nlflag = (pat[matchlen - 1] == '\n');
  1409. X    nlrepl = FALSE;
  1410. X
  1411. X    if (kind)
  1412. X    {
  1413. X        /* Build query replace question string.
  1414. X         */
  1415. X        strcpy(tpat, "Replace '");
  1416. X        expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
  1417. X        strcat(tpat, "' with '");
  1418. X        expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
  1419. X        strcat(tpat, "'? ");
  1420. X
  1421. X        /* Initialize last replaced pointers.
  1422. X         */
  1423. X        lastline = NULL;
  1424. X        lastoff = 0;
  1425. #if    NeWS
  1426. X        newsimmediateon() ;
  1427. #endif
  1428. X    }
  1429. X
  1430. X    numsub = 0;
  1431. X
  1432. X    while ( nlflag == FALSE || nlrepl == FALSE ) {
  1433. X
  1434. X        if (interrupted) return ABORT;
  1435. X
  1436. X        /* Search for the pattern.
  1437. X         * If we search with a regular expression,
  1438. X         * matchlen is reset to the true length of
  1439. X         * the matched string.
  1440. X         */
  1441. X        setboundry(TRUE,curwp->w_mkp,curwp->w_mko,FORWARD);
  1442. #if    MAGIC
  1443. X        if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0) {
  1444. X            if (!thescanner(&mcpat[0], FORWARD, PTBEG, TRUE))
  1445. X                break;
  1446. X        } else
  1447. #endif
  1448. X            if (!thescanner(&pat[0], FORWARD, PTBEG, TRUE))
  1449. X                break;        /* all done */
  1450. X
  1451. X        /* Check if we are on the last line.
  1452. X         */
  1453. X        nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
  1454. X
  1455. X        /* Check for query.
  1456. X         */
  1457. X        if (kind)
  1458. X        {
  1459. X            /* Get the query.
  1460. X             */
  1461. pprompt:        mlwrite(&tpat[0], &pat[0], &rpat[0]);
  1462. qprompt:
  1463. X            update(TRUE);  /* show the proposed place to change */
  1464. nprompt:
  1465. X            c = kbd_key();            /* and input */
  1466. X            mlwrite("");            /* and clear it */
  1467. X
  1468. X            if (c == abortc) {
  1469. X                mlwrite("[Aborted]");
  1470. X                return(FALSE);
  1471. X            }
  1472. X
  1473. X            /* And respond appropriately.
  1474. X             */
  1475. X            switch (c)
  1476. X            {
  1477. X                case tocntrl('Q'):
  1478. X                case tocntrl('S'):
  1479. X                    goto nprompt;
  1480. X
  1481. X                case 'y':    /* yes, substitute */
  1482. X                    savematch();
  1483. X                    break;
  1484. X
  1485. X                case 'n':    /* no, onward */
  1486. X                    nextch( &(curwp->w_dotp),
  1487. X                        &(curwp->w_doto),FORWARD,TRUE);
  1488. X                    continue;
  1489. X
  1490. X                case '!':    /* yes/stop asking */
  1491. X                    kind = FALSE;
  1492. X                    break;
  1493. X
  1494. X                case 'u':    /* undo last and re-prompt */
  1495. X
  1496. X                    /* Restore old position.
  1497. X                     */
  1498. X                    if (lastline == NULL)
  1499. X                    {
  1500. X                        /* There is nothing to undo.
  1501. X                         */
  1502. X                        TTbeep();
  1503. X                        goto pprompt;
  1504. X                    }
  1505. X                    curwp->w_dotp = lastline;
  1506. X                    curwp->w_doto = lastoff;
  1507. X                    lastline = NULL;
  1508. X                    lastoff = 0;
  1509. X
  1510. X                    /* Delete the new string.
  1511. X                     */
  1512. X                    backchar(FALSE, rlength);
  1513. X                    status = delins(rlength, patmatch);
  1514. X                    if (status != TRUE) {
  1515. X                        return (status);
  1516. X                    }
  1517. X
  1518. X                    /* Record one less substitution,
  1519. X                     * backup, and reprompt.
  1520. X                     */
  1521. X                    --numsub;
  1522. X                    backchar(TRUE, mlenold);
  1523. X                    matchline = curwp->w_dotp;
  1524. X                    matchoff  = curwp->w_doto;
  1525. X                    goto pprompt;
  1526. X
  1527. X                default:    /* bitch and beep */
  1528. X                    TTbeep();
  1529. X
  1530. X                case 'h':
  1531. X                case '?':    /* help me */
  1532. X                    mlwrite(
  1533. X            "(Y)es, (N)o, (!)Do rest, (U)ndo last, (ESC)Abort: ");
  1534. X                    goto qprompt;
  1535. X
  1536. X            }    /* end of switch */
  1537. X        }    /* end of "if kind" */
  1538. X
  1539. X        /*
  1540. X         * Delete the sucker, and insert its
  1541. X         * replacement.
  1542. X         */
  1543. X        status = delins(matchlen, &rpat[0]);
  1544. X        if (status != TRUE) {
  1545. X            return (status);
  1546. X        }
  1547. X
  1548. X        /* Save where we are if we might undo this....
  1549. X         */
  1550. X        if (kind)
  1551. X        {
  1552. X            lastline = curwp->w_dotp;
  1553. X            lastoff = curwp->w_doto;
  1554. X        }
  1555. X
  1556. X        numsub++;    /* increment # of substitutions */
  1557. X    }
  1558. X
  1559. X    /* And report the results.
  1560. X     */
  1561. X    mlwrite("%d substitutions", numsub);
  1562. X    return(TRUE);
  1563. }
  1564. X
  1565. /*
  1566. X * delins -- Delete a specified length from the current
  1567. X *    point, then insert the string.
  1568. X */
  1569. delins(dlength, instr)
  1570. int    dlength;
  1571. char    *instr;
  1572. {
  1573. X    int    status;
  1574. X    char    tmpc;
  1575. X
  1576. X    /* Zap what we gotta,
  1577. X     * and insert its replacement.
  1578. X     */
  1579. X    if (!(status = ldelete((long) dlength, FALSE)))
  1580. X    {
  1581. X        mlwrite("Error while deleting");
  1582. X        return(FALSE);
  1583. X    } else {
  1584. X        while (tmpc = *instr)
  1585. X        {
  1586. X            status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));
  1587. X
  1588. X            /* Insertion error?
  1589. X             */
  1590. X            if (!status)
  1591. X            {
  1592. X                mlwrite("Out of memory while inserting");
  1593. X                break;
  1594. X            }
  1595. X            instr++;
  1596. X        }
  1597. X    }
  1598. X    return (status);
  1599. }
  1600. #endif
  1601. X
  1602. /*
  1603. X * expandp -- Expand control key sequences for output.
  1604. X */
  1605. expandp(srcstr, deststr, maxlength)
  1606. char *srcstr;    /* string to expand */
  1607. char *deststr;    /* destination of expanded string */
  1608. int maxlength;    /* maximum chars in destination */
  1609. {
  1610. X    unsigned char c;    /* current char to translate */
  1611. X
  1612. X    /* Scan through the string.
  1613. X     */
  1614. X    while ((c = *srcstr++) != 0)
  1615. X    {
  1616. X        if (c == '\n')        /* it's a newline */
  1617. X        {
  1618. X            *deststr++ = '<';
  1619. X            *deststr++ = 'N';
  1620. X            *deststr++ = 'L';
  1621. X            *deststr++ = '>';
  1622. X            maxlength -= 4;
  1623. X        }
  1624. X        else if (!isprint(c))    /* control character */
  1625. X        {
  1626. X            *deststr++ = '^';
  1627. X            *deststr++ = toalpha(c);
  1628. X            maxlength -= 2;
  1629. X        }
  1630. X        else if (c == '%')
  1631. X        {
  1632. X            *deststr++ = '%';
  1633. X            *deststr++ = '%';
  1634. X            maxlength -= 2;
  1635. X        }
  1636. X        else            /* any other character */
  1637. X        {
  1638. X            *deststr++ = c;
  1639. X            maxlength--;
  1640. X        }
  1641. X
  1642. X        /* check for maxlength */
  1643. X        if (maxlength < 4)
  1644. X        {
  1645. X            *deststr++ = '$';
  1646. X            *deststr = '\0';
  1647. X            return(FALSE);
  1648. X        }
  1649. X    }
  1650. X    *deststr = '\0';
  1651. X    return(TRUE);
  1652. }
  1653. X
  1654. /*
  1655. X * boundry -- Return information depending on whether we may search no
  1656. X *    further.  Beginning of file and end of file are the obvious
  1657. X *    cases, but we may want to add further optional boundary restrictions
  1658. X *    in future, a' la VMS EDT.  At the moment, just return TRUE or
  1659. X *    FALSE depending on if a boundary is hit (ouch).
  1660. X */
  1661. int    
  1662. boundry(curline, curoff)
  1663. LINE    *curline;
  1664. int    curoff;
  1665. {
  1666. X    return (curline == boundline) && (curoff == boundoff);
  1667. }
  1668. X
  1669. setboundry(wrapok,lp,off,dir)
  1670. LINE *lp;
  1671. {
  1672. X    if (wrapok) {
  1673. X        (void)nextch(&lp,&off,dir,TRUE);
  1674. X        boundline = lp;
  1675. X        boundoff = off;
  1676. X    } else {
  1677. X        boundline = curbp->b_linep;
  1678. X        boundoff = 0;
  1679. X    }
  1680. }
  1681. X
  1682. /*
  1683. X * nextch -- retrieve the next/previous character in the buffer,
  1684. X *    and advance/retreat the point.
  1685. X *    The order in which this is done is significant, and depends
  1686. X *    upon the direction of the search.  Forward searches look at
  1687. X *    the current character and move, reverse searches move and
  1688. X *    look at the character.
  1689. X */
  1690. nextch(pcurline, pcuroff, dir, wrapok)
  1691. LINE    **pcurline;
  1692. int    *pcuroff;
  1693. int    dir;
  1694. {
  1695. X    register LINE    *curline;
  1696. X    register int    curoff;
  1697. X    register int    c;
  1698. X
  1699. X    /* dummy up a -1, which will never match anything, as the only
  1700. X        character on the header line */
  1701. X    
  1702. X    curline = *pcurline;
  1703. X    curoff = *pcuroff;
  1704. X    if (dir == FORWARD) {
  1705. X        if (curoff == ((curline == curbp->b_linep)?1:llength(curline)))
  1706. X        {    /* if at EOL */
  1707. X            curline = lforw(curline);    /* skip to next line */
  1708. X            curoff = 0;
  1709. X            c = '\n';            /* and return a <NL> */
  1710. X        } else {
  1711. X            c = lgetc(curline, curoff++);    /* get the char */
  1712. X            if (curline == curbp->b_linep)
  1713. X                c = -1;
  1714. X        }
  1715. X    } else     {        /* Reverse.*/
  1716. X        if (curoff == 0) {
  1717. X            curline = lback(curline);
  1718. X            curoff = (curline == curbp->b_linep)?1:llength(curline);
  1719. X            c = '\n';
  1720. X        } else {
  1721. X            c = lgetc(curline, --curoff);
  1722. X            if (curline == curbp->b_linep)
  1723. X                c = -1;
  1724. X        }
  1725. X    }
  1726. X    *pcurline = curline;
  1727. X    *pcuroff = curoff;
  1728. X
  1729. X    return (c);
  1730. }
  1731. X
  1732. #if    MAGIC
  1733. /*
  1734. X * mcstr -- Set up the 'magic' array.  The closure symbol is taken as
  1735. X *    a literal character when (1) it is the first character in the
  1736. X *    pattern, and (2) when preceded by a symbol that does not allow
  1737. X *    closure, such as a newline, beginning of line symbol, or another
  1738. X *    closure symbol.
  1739. X *
  1740. X *    Coding comment (jmg):  yes, i know i have gotos that are, strictly
  1741. X *    speaking, unnecessary.  But right now we are so cramped for
  1742. X *    code space that i will grab what i can in order to remain
  1743. X *    within the 64K limit.  C compilers actually do very little
  1744. X *    in the way of optimizing - they expect you to do that.
  1745. X */
  1746. int 
  1747. mcstr()
  1748. {
  1749. X    MC    *mcptr, *rtpcm;
  1750. X    char    *patptr;
  1751. X     int    mj;
  1752. X     int    pchr;
  1753. X     int    status = TRUE;
  1754. X     int    does_closure = FALSE;
  1755. X
  1756. X    /* If we had metacharacters in the MC array previously,
  1757. X     * free up any bitmaps that may have been allocated.
  1758. X     */
  1759. X    if (magical)
  1760. X        mcclear();
  1761. X
  1762. X    magical = FALSE;
  1763. X    mj = 0;
  1764. X    mcptr = &mcpat[0];
  1765. X    patptr = &pat[0];
  1766. X
  1767. X    while ((pchr = *patptr) && status)
  1768. X    {
  1769. X        switch (pchr)
  1770. X        {
  1771. X            case MC_CCL:
  1772. X                status = cclmake(&patptr, mcptr);
  1773. X                magical = TRUE;
  1774. X                does_closure = TRUE;
  1775. X                break;
  1776. X            case MC_BOL:
  1777. X                if (mj != 0)
  1778. X                    goto litcase;
  1779. X
  1780. X                mcptr->mc_type = BOL;
  1781. X                magical = TRUE;
  1782. X                does_closure = FALSE;
  1783. X                break;
  1784. X            case MC_EOL:
  1785. X                if (*(patptr + 1) != '\0')
  1786. X                    goto litcase;
  1787. X
  1788. X                mcptr->mc_type = EOL;
  1789. X                magical = TRUE;
  1790. X                does_closure = FALSE;
  1791. X                break;
  1792. X            case MC_ANY:
  1793. X                mcptr->mc_type = ANY;
  1794. X                magical = TRUE;
  1795. X                does_closure = TRUE;
  1796. X                break;
  1797. X            case MC_CLOSURE:
  1798. X                /* Does the closure symbol mean closure here?
  1799. X                 * If so, back up to the previous element
  1800. X                 * and indicate it is enclosed.
  1801. X                 */
  1802. X                if (!does_closure)
  1803. X                    goto litcase;
  1804. X                mj--;
  1805. X                mcptr--;
  1806. X                mcptr->mc_type |= CLOSURE;
  1807. X                magical = TRUE;
  1808. X                does_closure = FALSE;
  1809. X                break;
  1810. X
  1811. X            /* Note: no break between MC_ESC case and the default.
  1812. X             */
  1813. X            case MC_ESC:
  1814. X                if (*(patptr + 1) != '\0')
  1815. X                {
  1816. X                    pchr = *++patptr;
  1817. X                    magical = TRUE;
  1818. X                }
  1819. X            default:
  1820. litcase:            mcptr->mc_type = LITCHAR;
  1821. X                mcptr->u.lchar = pchr;
  1822. X                does_closure = (pchr != '\n');
  1823. X                break;
  1824. X        }        /* End of switch.*/
  1825. X        mcptr++;
  1826. X        patptr++;
  1827. X        mj++;
  1828. X    }        /* End of while.*/
  1829. X
  1830. X    /* Close off the meta-string.
  1831. X     */
  1832. X    mcptr->mc_type = MCNIL;
  1833. X
  1834. X    /* Set up the reverse array, if the status is good.  Please note the
  1835. X     * structure assignment - your compiler may not like that.
  1836. X     * If the status is not good, nil out the meta-pattern.
  1837. X     * The only way the status would be bad is from the cclmake()
  1838. X     * routine, and the bitmap for that member is guarenteed to be
  1839. X     * freed.  So we stomp a MCNIL value there, and call mcclear()
  1840. X     * to free any other bitmaps.
  1841. X     */
  1842. X    if (status)
  1843. X    {
  1844. X        rtpcm = &tapcm[0];
  1845. X        while (--mj >= 0)
  1846. X        {
  1847. #if    LATTICE
  1848. X            movmem(--mcptr, rtpcm++, sizeof (MC));
  1849. #endif
  1850. X
  1851. #if    MWC86 | AZTEC | MSC | TURBO | VMS | USG | BSD | V7
  1852. X            *rtpcm++ = *--mcptr;
  1853. #endif
  1854. X        }
  1855. X        rtpcm->mc_type = MCNIL;
  1856. X    }
  1857. X    else
  1858. X    {
  1859. X        (--mcptr)->mc_type = MCNIL;
  1860. X        mcclear();
  1861. X    }
  1862. X
  1863. X    return(status);
  1864. }
  1865. X
  1866. /*
  1867. X * mcclear -- Free up any CCL bitmaps, and MCNIL the MC arrays.
  1868. X */
  1869. mcclear()
  1870. {
  1871. X    register MC    *mcptr;
  1872. X
  1873. X    mcptr = &mcpat[0];
  1874. X
  1875. X    while (mcptr->mc_type != MCNIL)
  1876. X    {
  1877. X        if ((mcptr->mc_type & MASKCL) == CCL ||
  1878. X            (mcptr->mc_type & MASKCL) == NCCL)
  1879. X            free(mcptr->u.cclmap);
  1880. X        mcptr++;
  1881. X    }
  1882. X    mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
  1883. }
  1884. X
  1885. /*
  1886. X * mceq -- meta-character equality with a character.  In Kernighan & Plauger's
  1887. X *    Software Tools, this is the function omatch(), but i felt there
  1888. X *    were too many functions with the 'match' name already.
  1889. X */
  1890. mceq(bc, mt)
  1891. int    bc;
  1892. MC    *mt;
  1893. {
  1894. X    register int result;
  1895. X    
  1896. X    if (bc < 0)
  1897. X        return FALSE;
  1898. X
  1899. X    switch (mt->mc_type & MASKCL)
  1900. X    {
  1901. X        case LITCHAR:
  1902. X            result = eq(bc, mt->u.lchar);
  1903. X            break;
  1904. X
  1905. X        case ANY:
  1906. X            result = (bc != '\n');
  1907. X            break;
  1908. X
  1909. X        case CCL:
  1910. X            if (!(result = biteq(bc, mt->u.cclmap)))
  1911. X            {
  1912. X                if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
  1913. X                    isalpha(bc))
  1914. X                {
  1915. X                    result = biteq(CHCASE(bc),mt->u.cclmap);
  1916. X                }
  1917. X            }
  1918. X            break;
  1919. X
  1920. X        case NCCL:
  1921. X            
  1922. X            if (bc == '\n') {
  1923. X                result = FALSE;
  1924. X            } else {
  1925. X                result = !biteq(bc, mt->u.cclmap);
  1926. X
  1927. X                if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
  1928. X                        isalpha(bc))
  1929. X                {
  1930. X                    result &= !biteq(CHCASE(bc),
  1931. X                                 mt->u.cclmap);
  1932. X                }
  1933. X            }
  1934. X            break;
  1935. X
  1936. X        default:
  1937. X            mlwrite("mceq: what is %d?", mt->mc_type);
  1938. X            result = FALSE;
  1939. X            break;
  1940. X
  1941. X    }    /* End of switch.*/
  1942. X
  1943. X    return (result);
  1944. }
  1945. X
  1946. /*
  1947. X * cclmake -- create the bitmap for the character class.
  1948. X *    ppatptr is left pointing to the end-of-character-class character,
  1949. X *    so that a loop may automatically increment with safety.
  1950. X */
  1951. cclmake(ppatptr, mcptr)
  1952. char    **ppatptr;
  1953. MC    *mcptr;
  1954. {
  1955. X    BITMAP        bmap;
  1956. X    register char    *patptr;
  1957. X    register int    pchr, ochr;
  1958. X
  1959. X    if ((bmap = clearbits()) == NULL)
  1960. X    {
  1961. X        mlwrite("Out of memory");
  1962. X        return FALSE;
  1963. X    }
  1964. X
  1965. X    mcptr->u.cclmap = bmap;
  1966. X    patptr = *ppatptr;
  1967. X
  1968. X    /*
  1969. X     * Test the initial character(s) in ccl for
  1970. X     * special cases - negate ccl, or an end ccl
  1971. X     * character as a first character.  Anything
  1972. X     * else gets set in the bitmap.
  1973. X     */
  1974. X    if (*++patptr == MC_NCCL)
  1975. X    {
  1976. X        patptr++;
  1977. X        mcptr->mc_type = NCCL;
  1978. X    }
  1979. X    else
  1980. X        mcptr->mc_type = CCL;
  1981. X
  1982. X    if ((ochr = *patptr) == MC_ECCL)
  1983. X    {
  1984. X        mlwrite("Empty character class");
  1985. X        return (FALSE);
  1986. X    }
  1987. X    else
  1988. X    {
  1989. X        if (ochr == MC_ESC)
  1990. X            ochr = *++patptr;
  1991. X
  1992. X        setbit(ochr, bmap);
  1993. X        patptr++;
  1994. X    }
  1995. X
  1996. X    while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
  1997. X    {
  1998. X        switch (pchr)
  1999. X        {
  2000. X            /* Range character loses its meaning
  2001. X             * if it is the last character in
  2002. X             * the class.
  2003. X             */
  2004. X            case MC_RCCL:
  2005. X                if (*(patptr + 1) == MC_ECCL)
  2006. X                    setbit(pchr, bmap);
  2007. X                else
  2008. X                {
  2009. X                    pchr = *++patptr;
  2010. X                    while (++ochr <= pchr)
  2011. X                        setbit(ochr, bmap);
  2012. X                }
  2013. X                break;
  2014. X
  2015. X            /* Note: no break between case MC_ESC and the default.
  2016. X             */
  2017. X            case MC_ESC:
  2018. X                pchr = *++patptr;
  2019. X            default:
  2020. X                setbit(pchr, bmap);
  2021. X                break;
  2022. X        }
  2023. X        patptr++;
  2024. X        ochr = pchr;
  2025. X    }
  2026. X
  2027. X    *ppatptr = patptr;
  2028. X
  2029. X    if (ochr == '\0')
  2030. X    {
  2031. X        mlwrite("Missing '%c'",MC_ECCL);
  2032. X        free(bmap);
  2033. X        return FALSE;
  2034. X    }
  2035. X    return TRUE;
  2036. }
  2037. X
  2038. /*
  2039. X * biteq -- is the character in the bitmap?
  2040. X */
  2041. biteq(bc, cclmap)
  2042. int    bc;
  2043. BITMAP    cclmap;
  2044. {
  2045. X    if (bc >= HICHAR || bc < 0)
  2046. X        return FALSE;
  2047. X
  2048. X    return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
  2049. }
  2050. X
  2051. /*
  2052. X * clearbits -- Allocate and zero out a CCL bitmap.
  2053. X */
  2054. BITMAP 
  2055. clearbits()
  2056. {
  2057. X
  2058. X    BITMAP        cclstart, cclmap;
  2059. X    register int    j;
  2060. X
  2061. X    if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
  2062. X        for (j = 0; j < HIBYTE; j++)
  2063. X            *cclmap++ = 0;
  2064. X
  2065. X    return (cclstart);
  2066. }
  2067. X
  2068. /*
  2069. X * setbit -- Set a bit (ON only) in the bitmap.
  2070. X */
  2071. void 
  2072. setbit(bc, cclmap)
  2073. int    bc;
  2074. BITMAP    cclmap;
  2075. {
  2076. X    if (bc < HICHAR && bc >= 0)
  2077. X        *(cclmap + (bc >> 3)) |= BIT(bc & 7);
  2078. }
  2079. #endif
  2080. SHAR_EOF
  2081. chmod 0444 search.c ||
  2082. echo 'restore of search.c failed'
  2083. Wc_c="`wc -c < 'search.c'`"
  2084. test 35047 -eq "$Wc_c" ||
  2085.     echo 'search.c: original size 35047, current size' "$Wc_c"
  2086. # ============= shorten/COPYING ==============
  2087. if test ! -d 'shorten'; then
  2088.     echo 'x - creating directory shorten'
  2089.     mkdir 'shorten'
  2090. fi
  2091. echo 'x - extracting shorten/COPYING (Text)'
  2092. sed 's/^X//' << 'SHAR_EOF' > 'shorten/COPYING' &&
  2093. The code distributed with vile in the "shortnames" subdirectory is covered
  2094. by the following license.  The vile code itself is _not_ covered by the GNU
  2095. public license.
  2096. X
  2097. X         GNU EMACS GENERAL PUBLIC LICENSE
  2098. X            (Clarified 11 Feb 1988)
  2099. X
  2100. X Copyright (C) 1985, 1987, 1988 Richard M. Stallman
  2101. X Everyone is permitted to copy and distribute verbatim copies
  2102. X of this license, but changing it is not allowed.  You can also
  2103. X use this wording to make the terms for other programs.
  2104. X
  2105. X  The license agreements of most software companies keep you at the
  2106. mercy of those companies.  By contrast, our general public license is
  2107. intended to give everyone the right to share GNU Emacs.  To make
  2108. sure that you get the rights we want you to have, we need to make
  2109. restrictions that forbid anyone to deny you these rights or to ask you
  2110. to surrender the rights.  Hence this license agreement.
  2111. X
  2112. X  Specifically, we want to make sure that you have the right to give
  2113. away copies of Emacs, that you receive source code or else can get it
  2114. if you want it, that you can change Emacs or use pieces of it in new
  2115. free programs, and that you know you can do these things.
  2116. X
  2117. X  To make sure that everyone has such rights, we have to forbid you to
  2118. deprive anyone else of these rights.  For example, if you distribute
  2119. copies of Emacs, you must give the recipients all the rights that you
  2120. have.  You must make sure that they, too, receive or can get the
  2121. source code.  And you must tell them their rights.
  2122. X
  2123. X  Also, for our own protection, we must make certain that everyone
  2124. finds out that there is no warranty for GNU Emacs.  If Emacs is
  2125. modified by someone else and passed on, we want its recipients to know
  2126. that what they have is not what we distributed, so that any problems
  2127. introduced by others will not reflect on our reputation.
  2128. X
  2129. X  Therefore we (Richard Stallman and the Free Software Fundation,
  2130. Inc.) make the following terms which say what you must do to be
  2131. allowed to distribute or change GNU Emacs.
  2132. X
  2133. X            COPYING POLICIES
  2134. X
  2135. X  1. You may copy and distribute verbatim copies of GNU Emacs source code
  2136. as you receive it, in any medium, provided that you conspicuously and
  2137. appropriately publish on each copy a valid copyright notice "Copyright
  2138. (C) 1988 Free Software Foundation, Inc." (or with whatever year is
  2139. appropriate); keep intact the notices on all files that refer to this
  2140. License Agreement and to the absence of any warranty; and give any
  2141. other recipients of the GNU Emacs program a copy of this License
  2142. Agreement along with the program.  You may charge a distribution fee
  2143. SHAR_EOF
  2144. true || echo 'restore of shorten/COPYING failed'
  2145. echo 'End of Vile part 12'
  2146. echo 'File shorten/COPYING is continued in part 13'
  2147. echo 13 > _shar_seq_.tmp
  2148. exit 0
  2149. -- 
  2150.         paul fox, pgf@cayman.com, (617)494-1999
  2151.         Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
  2152.