home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / xvi / part07 < prev    next >
Encoding:
Text File  |  1992-10-22  |  55.5 KB  |  2,339 lines

  1. Newsgroups: comp.sources.misc
  2. From: jmd@cyclone.bt.co.uk (John Downey)
  3. Subject:  v33i016:  xvi - portable multi-window vi-like editor, Part07/18
  4. Message-ID: <1992Oct23.181324.315@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8f9a655ab828fae583d4e2c9b4204d1c
  6. Date: Fri, 23 Oct 1992 18:13:24 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jmd@cyclone.bt.co.uk (John Downey)
  10. Posting-number: Volume 33, Issue 16
  11. Archive-name: xvi/part07
  12. Environment: Unix, MS-DOS, OS/2, QNX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then feed it
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # Contents:  xvi/src/fileio.c xvi/src/makefile.os2 xvi/src/regexp.c
  19. # Wrapped by kent@sparky on Thu Oct 22 09:03:42 1992
  20. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  21. echo If this archive is complete, you will see the following message:
  22. echo '          "shar: End of archive 7 (of 18)."'
  23. if test -f 'xvi/src/fileio.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'xvi/src/fileio.c'\"
  25. else
  26.   echo shar: Extracting \"'xvi/src/fileio.c'\" \(15127 characters\)
  27.   sed "s/^X//" >'xvi/src/fileio.c' <<'END_OF_FILE'
  28. X/* Copyright (c) 1990,1991,1992 Chris and John Downey */
  29. X#ifndef lint
  30. Xstatic char *sccsid = "@(#)fileio.c    2.1 (Chris & John Downey) 7/29/92";
  31. X#endif
  32. X
  33. X/***
  34. X
  35. X* program name:
  36. X    xvi
  37. X* function:
  38. X    PD version of UNIX "vi" editor, with extensions.
  39. X* module name:
  40. X    fileio.c
  41. X* module function:
  42. X    File i/o routines.
  43. X* history:
  44. X    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  45. X    Originally by Tim Thompson (twitch!tjt)
  46. X    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  47. X    Heavily modified by Chris & John Downey
  48. X
  49. X***/
  50. X
  51. X#include "xvi.h"
  52. X
  53. X#ifdef    MEGAMAX
  54. Xoverlay "fileio"
  55. X#endif
  56. X
  57. X/*
  58. X * Definition of a text file format.
  59. X *
  60. X * This structure may need additional entries to cope with very strange file
  61. X * formats (such as VMS).
  62. X */
  63. Xstruct tfformat
  64. X{
  65. X    int            tf_eolnchars[2];    /* end of line markers */
  66. X    int            tf_eofchar;        /* end of file marker */
  67. X    unsigned char   tf_dynamic;        /* autodetect format? */
  68. X};
  69. X
  70. X/*
  71. X * Names of values for the P_format enumerated parameter.
  72. X *
  73. X * It is essential that these are in the same order as the fmt_...
  74. X * symbolic constants defined in xvi.h.
  75. X */
  76. Xchar    *fmt_strings[] = {
  77. X    "cstring",
  78. X    "macintosh",
  79. X    "msdos",
  80. X    "os2",
  81. X    "qnx",
  82. X    "tos",
  83. X    "unix",
  84. X    NULL,
  85. X};
  86. X
  87. X/*
  88. X * Format structures.
  89. X *
  90. X * It is essential that these are in the same order as the fmt_...
  91. X * symbolic constants defined in xvi.h.
  92. X *
  93. X * We don't use '\r' or '\n' to define the end-of-line characters
  94. X * because some compilers interpret them differently & this code has
  95. X * to work the same on all systems.
  96. X */
  97. X#define    NOCHAR    EOF
  98. X
  99. Xstatic const struct tfformat tftable [] = {
  100. X    { { '\0',       NOCHAR    }, EOF,          FALSE },    /* fmt_CSTRING */
  101. X    { { CTRL('M'), NOCHAR    }, EOF,          FALSE },    /* fmt_MACINTOSH */
  102. X    { { CTRL('M'), CTRL('J')    }, CTRL('Z'), TRUE  },    /* fmt_MSDOS */
  103. X    { { CTRL('M'), CTRL('J')    }, CTRL('Z'), TRUE  },    /* fmt_OS2 */
  104. X    { { '\036',       NOCHAR    }, EOF,          FALSE },    /* fmt_QNX */
  105. X    { { CTRL('M'), CTRL('J')    }, EOF,          TRUE  },    /* fmt_TOS */
  106. X    { { CTRL('J'), NOCHAR    }, EOF,          FALSE }    /* fmt_UNIX */
  107. X};
  108. X
  109. X/*
  110. X * Index of last entry in tftable.
  111. X */
  112. X#define    TFMAX    (sizeof tftable / sizeof (struct tfformat) - 1)
  113. X
  114. X/*
  115. X * Current text file format.
  116. X */
  117. Xstatic struct tfformat curfmt = { { 0, 0 }, 0, FALSE };
  118. X
  119. X#define eolnchars    curfmt.tf_eolnchars
  120. X#define eofchar        curfmt.tf_eofchar
  121. X
  122. X/*
  123. X * Name of current text file format.
  124. X */
  125. Xstatic char *fmtname = "INTERNAL ERROR";
  126. X
  127. X/*
  128. X * Copy the tftable entry indexed by tfindex into curfmt & update
  129. X * fmtname. Return FALSE if the parameter is invalid, otherwise TRUE.
  130. X *
  131. X * This is called from set_format() (below).
  132. X *
  133. X * Note that we copy a whole tfformat structure here, instead of just copying
  134. X * a pointer. This is so that curfmt.eolnchars & curfmt.eofchar will compile
  135. X * to absolute address references instead of indirections, which should be
  136. X * significantly more efficient because they are referenced for every
  137. X * character we read or write.
  138. X */
  139. Xstatic bool_t
  140. Xtxtformset(tfindex)
  141. Xint    tfindex;
  142. X{
  143. X    if (tfindex < 0 || tfindex > TFMAX)
  144. X    return FALSE;
  145. X    (void) memcpy((char *) &curfmt, (const char *) &tftable[tfindex],
  146. X                          sizeof curfmt);
  147. X    fmtname = fmt_strings[tfindex];
  148. X    return TRUE;
  149. X}
  150. X
  151. X/*
  152. X * Check value of P_format parameter.
  153. X */
  154. Xbool_t
  155. Xset_format(window, new_value, interactive)
  156. XXviwin    *window;
  157. XParamval new_value;
  158. Xbool_t    interactive;
  159. X{
  160. X    if (!txtformset(new_value.pv_i)) {
  161. X    if (interactive) {
  162. X        show_error(window, "Invalid text file format (%d)",
  163. X                            new_value.pv_i);
  164. X    }
  165. X    return(FALSE);
  166. X    }
  167. X    return(TRUE);
  168. X}
  169. X
  170. X/*
  171. X * Find out if there's a format we know about with the single specified
  172. X * end-of-line character. If so, change to it.
  173. X */
  174. Xstatic bool_t
  175. Xeolnhack(c)
  176. X    register int    c;
  177. X{
  178. X    register int    tfindex;
  179. X
  180. X    for (tfindex = 0; tfindex <= TFMAX; tfindex++) {
  181. X    register const int    *eolp;
  182. X
  183. X    eolp = tftable[tfindex].tf_eolnchars;
  184. X    if (eolp[0] == c && eolp[1] == NOCHAR) {
  185. X        (void) txtformset(tfindex);
  186. X        set_param(P_format, tfindex, (char **) NULL);
  187. X        P_setchanged(P_format);
  188. X        return TRUE;
  189. X    }
  190. X    }
  191. X    return FALSE;
  192. X}
  193. X
  194. X/*
  195. X * Read in the given file, filling in the given "head" and "tail"
  196. X * arguments with pointers to the first and last elements of the
  197. X * linked list of Lines; if nothing was read, both pointers are set to
  198. X * NULL. The return value is the number of lines read, if successful
  199. X * (this can be 0 for an empty file), or an error return code, which
  200. X * can be gf_NEWFILE, gf_CANTOPEN, gf_IOERR or gf_NOMEM.
  201. X *
  202. X * If there is an error, such as not being able to read the file or
  203. X * running out of memory, an error message is printed; otherwise, a
  204. X * statistics line is printed using show_message().
  205. X *
  206. X * The "extra_str" string is printed just after the filename in the
  207. X * displayed line, and is typically used for "Read Only" messages. If
  208. X * the file doesn't appear to exist, the filename is printed again,
  209. X * immediately followed by the "no_file_str" string, & we return
  210. X * gf_NEWFILE.
  211. X */
  212. Xlong
  213. Xget_file(window, filename, headp, tailp, extra_str, no_file_str)
  214. XXviwin        *window;
  215. Xchar        *filename;
  216. XLine        **headp;
  217. XLine        **tailp;
  218. Xchar        *extra_str;
  219. Xchar        *no_file_str;
  220. X{
  221. X    register FILE    *fp;        /* ptr to open file */
  222. X#ifndef i386
  223. X    register
  224. X#endif
  225. X    unsigned long    nchars;        /* number of chars read */
  226. X    unsigned long    nlines;        /* number of lines read */
  227. X    unsigned long    nulls;        /* number of null chars */
  228. X    unsigned long    toolong;    /*
  229. X                     * number of lines
  230. X                     * which were too long
  231. X                     */
  232. X    bool_t        incomplete;    /* incomplete last line */
  233. X    Line        *lptr = NULL;    /* pointer to list of lines */
  234. X    Line        *last = NULL;    /*
  235. X                     * last complete line
  236. X                     * read in
  237. X                     */
  238. X    Line        *lp;        /*
  239. X                     * line currently
  240. X                     * being read in
  241. X                     */
  242. X    register enum {
  243. X    at_soln,
  244. X    in_line,
  245. X    got_eolnc0,
  246. X    at_eoln,
  247. X    at_eof
  248. X    }            state;
  249. X    register char    *buff;        /*
  250. X                     * text of line
  251. X                     * being read in
  252. X                     */
  253. X    register int    col;        /* current column in line */
  254. X
  255. X    if (P_ischanged(P_format)) {
  256. X    show_message(window, "\"%s\" [%s]%s", filename, fmtname, extra_str);
  257. X    } else {
  258. X    show_message(window, "\"%s\"%s", filename, extra_str);
  259. X    }
  260. X
  261. X    fp = fopenrb(filename);
  262. X    if (fp == NULL) {
  263. X    *headp = *tailp = NULL;
  264. X    if (exists(filename)) {
  265. X        show_error(window, "Can't read \"%s\"", filename);
  266. X        return(gf_CANTOPEN);
  267. X    } else {
  268. X        show_message(window, "\"%s\"%s", filename, no_file_str);
  269. X        return(gf_NEWFILE);
  270. X    }
  271. X    }
  272. X
  273. X#ifdef    SETVBUF_AVAIL
  274. X    {
  275. X    unsigned int    bufsize;
  276. X
  277. X    bufsize = READBUFSIZ;
  278. X
  279. X    /*
  280. X     * Keep trying to set the buffer size to something
  281. X     * large, reducing the size by 1/2 each time.
  282. X     * This will eventually work, and will not usually
  283. X     * take very many calls. (jmd)
  284. X     */
  285. X    while (setvbuf(fp, (char *) NULL, _IOFBF, bufsize) != 0 &&
  286. X                        bufsize > 1) {
  287. X        bufsize /= 2;
  288. X    }
  289. X    }
  290. X#endif /* SETVBUF_AVAIL */
  291. X
  292. X    nchars = nlines = nulls = toolong = 0;
  293. X    col = 0;
  294. X    incomplete = FALSE;
  295. X    state = at_soln;
  296. X    while (state != at_eof) {
  297. X
  298. X    register int    c;
  299. X
  300. X    c = getc(fp);
  301. X
  302. X    if (c == EOF || c == eofchar) {
  303. X        if (state != at_soln) {
  304. X        /*
  305. X         * Reached EOF in the middle of a line; what
  306. X         * we do here is to pretend we got a properly
  307. X         * terminated line, and assume that a
  308. X         * subsequent getc will still return EOF.
  309. X         */
  310. X        incomplete = TRUE;
  311. X        state = at_eoln;
  312. X        } else {
  313. X        state = at_eof;
  314. X        break;
  315. X        }
  316. X    } else {
  317. X        nchars++;
  318. X
  319. X        switch (state) {
  320. X        case at_soln:
  321. X        /*
  322. X         * We're at the start of a line, &
  323. X         * we've got at least one character,
  324. X         * so we have to allocate a new Line
  325. X         * structure.
  326. X         *
  327. X         * If we can't do it, we throw away
  328. X         * the lines we've read in so far, &
  329. X         * return gf_NOMEM.
  330. X         */
  331. X        if ((lp = newline(MAX_LINE_LENGTH)) == NULL) {
  332. X            if (lptr != NULL) {
  333. X            throw(lptr);
  334. X            }
  335. X            (void) fclose(fp);
  336. X            *headp = *tailp = NULL;
  337. X            return(gf_NOMEM);
  338. X        } else {
  339. X            buff = lp->l_text;
  340. X        }
  341. X        case in_line:
  342. X        if (c == eolnchars[0]) {
  343. X            if (eolnchars[1] == NOCHAR) {
  344. X            state = at_eoln;
  345. X            } else {
  346. X            state = got_eolnc0;
  347. X            continue;
  348. X            }
  349. X        } else if (c == eolnchars [1] && curfmt.tf_dynamic &&
  350. X                         eolnhack(c)) {
  351. X            /*
  352. X             * If we get the second end-of-line
  353. X             * marker, but not the first, see if
  354. X             * we can accept the second one by
  355. X             * itself as an end-of-line.
  356. X             */
  357. X            state = at_eoln;
  358. X        }
  359. X        break;
  360. X        case got_eolnc0:
  361. X        if (c == eolnchars[1]) {
  362. X            state = at_eoln;
  363. X        } else if (curfmt.tf_dynamic && eolnhack(eolnchars[0])) {
  364. X            /*
  365. X             * If we get the first end-of-line
  366. X             * marker, but not the second, see
  367. X             * if we can accept the first one
  368. X             * by itself as an end-of-line.
  369. X             */
  370. X            (void) ungetc(c, fp);
  371. X            state = at_eoln;
  372. X        } else {
  373. X            /*
  374. X             * We can't. Just take the first one
  375. X             * literally.
  376. X             */
  377. X            state = in_line;
  378. X            (void) ungetc(c, fp);
  379. X            c = eolnchars [0];
  380. X        }
  381. X        }
  382. X    }
  383. X
  384. X    if (state == at_eoln || col >= MAX_LINE_LENGTH - 1) {
  385. X        /*
  386. X         * First null-terminate the old line.
  387. X         */
  388. X        buff[col] = '\0';
  389. X
  390. X        /*
  391. X         * If this fails, we squeak at the user and
  392. X         * then throw away the lines read in so far.
  393. X         */
  394. X        buff = realloc(buff, (unsigned) col + 1);
  395. X        if (buff == NULL) {
  396. X        if (lptr != NULL)
  397. X            throw(lptr);
  398. X        (void) fclose(fp);
  399. X        *headp = *tailp = NULL;
  400. X        return gf_NOMEM;
  401. X        }
  402. X        lp->l_text = buff;
  403. X        lp->l_size = col + 1;
  404. X
  405. X        /*
  406. X         * Tack the line onto the end of the list,
  407. X         * and then point "last" at it.
  408. X         */
  409. X        if (lptr == NULL) {
  410. X        lptr = lp;
  411. X        last = lptr;
  412. X        } else {
  413. X        last->l_next = lp;
  414. X        lp->l_prev = last;
  415. X        last = lp;
  416. X        }
  417. X
  418. X        nlines++;
  419. X        col = 0;
  420. X        if (state != at_eoln) {
  421. X        toolong++;
  422. X        /*
  423. X         * We didn't get a properly terminated line,
  424. X         * but we still have to do something with the
  425. X         * character we've read.
  426. X         */
  427. X        (void) ungetc(c, fp);
  428. X        }
  429. X        state = at_soln;
  430. X    } else {
  431. X        /*
  432. X         * Nulls are special; they can't show up in the file.
  433. X         */
  434. X        if (c == '\0') {
  435. X        nulls++;
  436. X        continue;
  437. X        }
  438. X        state = in_line;
  439. X        buff[col++] = c;
  440. X    }
  441. X    }
  442. X    (void) fclose(fp);
  443. X
  444. X    {
  445. X    /*
  446. X     * Assemble error messages for status line.
  447. X     */
  448. X    Flexbuf        errbuf;
  449. X    char        *errs;
  450. X
  451. X    flexnew(&errbuf);
  452. X    if (nulls > 0) {
  453. X        (void) lformat(&errbuf, " (%ld null character%s)",
  454. X               nulls, (nulls == 1 ? "" : "s"));
  455. X    }
  456. X    if (toolong > 0) {
  457. X        (void) lformat(&errbuf, " (%ld line%s too long)",
  458. X               toolong, (toolong == 1 ? "" : "s"));
  459. X    }
  460. X    if (incomplete) {
  461. X        (void) lformat(&errbuf, " (incomplete last line)");
  462. X    }
  463. X
  464. X    /*
  465. X     * Show status line.
  466. X     */
  467. X    errs = flexgetstr(&errbuf);
  468. X    if (P_ischanged(P_format)) {
  469. X        show_message(window, "\"%s\" [%s]%s %ld/%ld%s",
  470. X                filename, fmtname, extra_str,
  471. X                nlines, nchars, errs);
  472. X    } else {
  473. X        show_message(window, "\"%s\"%s %ld/%ld%s",
  474. X                filename, extra_str, nlines, nchars, errs);
  475. X    }
  476. X    flexdelete(&errbuf);
  477. X    }
  478. X
  479. X    *headp = lptr;
  480. X    *tailp = last;
  481. X
  482. X    return(nlines);
  483. X}
  484. X
  485. X/*
  486. X * writeit - write to file 'fname' lines 'start' through 'end'
  487. X *
  488. X * If either 'start' or 'end' are NULL, the default
  489. X * is to use the start or end of the file respectively.
  490. X *
  491. X * Unless the "force" argument is TRUE, we do not write
  492. X * out buffers which have the "readonly" flag set.
  493. X */
  494. Xbool_t
  495. Xwriteit(window, fname, start, end, force)
  496. XXviwin    *window;
  497. Xchar    *fname;
  498. XLine    *start, *end;
  499. Xbool_t    force;
  500. X{
  501. X    FILE        *fp;
  502. X    unsigned long    nc;
  503. X    unsigned long    nl;
  504. X    Buffer        *buffer;
  505. X
  506. X    buffer = window->w_buffer;
  507. X
  508. X    if (is_readonly(buffer) && !force) {
  509. X    show_error(window, "\"%s\" File is read only", fname);
  510. X    return(FALSE);
  511. X    }
  512. X
  513. X    show_message(window,
  514. X        (P_ischanged(P_format) ? "\"%s\" [%s]" :  "\"%s\""),
  515. X                        fname, fmtname);
  516. X
  517. X    /*
  518. X     * Preserve the buffer here so if the write fails it will at
  519. X     * least have been saved.
  520. X     */
  521. X    if (!preservebuf(window)) {
  522. X    return(FALSE);
  523. X    }
  524. X
  525. X    if (!can_write(fname)) {
  526. X    show_error(window, "\"%s\" Permission denied", fname);
  527. X    return(FALSE);
  528. X    }
  529. X
  530. X    fp = fopenwb(fname);
  531. X    if (fp == NULL) {
  532. X    show_error(window, "Can't write \"%s\"", fname);
  533. X    return(FALSE);
  534. X    }
  535. X
  536. X    if (put_file(window, fp, start, end, &nc, &nl) == FALSE) {
  537. X    return(FALSE);
  538. X    }
  539. X
  540. X    if (P_ischanged(P_format)) {
  541. X    show_message(window, "\"%s\" [%s] %ld/%ld", fname, fmtname, nl, nc);
  542. X    } else {
  543. X    show_message(window, "\"%s\" %ld/%ld", fname, nl, nc);
  544. X    }
  545. X
  546. X    /*
  547. X     * Make sure any preserve file is removed if it isn't wanted.
  548. X     * It's not worth checking for the file's existence before
  549. X     * trying to remove it; the remove() will do the check anyway.
  550. X     */
  551. X    if (Pn(P_preserve) < psv_PARANOID) {
  552. X    if (buffer->b_tempfname != NULL) {
  553. X        (void) remove(buffer->b_tempfname);
  554. X    }
  555. X    }
  556. X
  557. X    /*
  558. X     * If no start and end lines were specified, or they
  559. X     * were specified as the start and end of the buffer,
  560. X     * and we wrote out the whole file, then we can clear
  561. X     * the modified status. This must be safe.
  562. X     */
  563. X    if ((start == NULL || start == buffer->b_file) &&
  564. X            (end == NULL || end == buffer->b_lastline->l_prev)) {
  565. X    buffer->b_flags &= ~FL_MODIFIED;
  566. X    }
  567. X
  568. X    return(TRUE);
  569. X}
  570. X
  571. X/*
  572. X * Write out the buffer between the given two line pointers
  573. X * (which default to start and end of buffer) to the given file
  574. X * pointer. The reference parameters ncp and nlp are filled in
  575. X * with the number of characters and lines written to the file.
  576. X * The return value is TRUE for success, FALSE for all kinds of
  577. X * failure.
  578. X */
  579. Xbool_t
  580. Xput_file(window, f, start, end, ncp, nlp)
  581. XXviwin        *window;
  582. Xregister FILE    *f;
  583. XLine        *start, *end;
  584. Xunsigned long    *ncp, *nlp;
  585. X{
  586. X    register Line        *lp;
  587. X    register unsigned long    nchars;
  588. X    unsigned long        nlines;
  589. X    Buffer            *buffer;
  590. X
  591. X    buffer = window->w_buffer;
  592. X
  593. X#ifdef    SETVBUF_AVAIL
  594. X    {
  595. X    unsigned int    bufsize = WRTBUFSIZ;
  596. X
  597. X    /*
  598. X     * Keep trying to set the buffer size to something
  599. X     * large, reducing the size by 1/2 each time.
  600. X     * This will eventually work, and will not usually
  601. X     * take very many calls. (jmd)
  602. X     */
  603. X    while (setvbuf(f, (char *) NULL, _IOFBF, bufsize) != 0 &&
  604. X                            bufsize > 1) {
  605. X        bufsize /= 2;
  606. X    }
  607. X    }
  608. X#endif /* SETVBUF_AVAIL */
  609. X
  610. X    /*
  611. X     * If we were given a bound, start there. Otherwise just
  612. X     * start at the beginning of the file.
  613. X     */
  614. X    if (start == NULL) {
  615. X    lp = buffer->b_file;
  616. X    } else {
  617. X    lp = start;
  618. X    }
  619. X
  620. X    nlines = 0;
  621. X    nchars = 0;
  622. X    for ( ; lp != buffer->b_lastline; lp = lp->l_next) {
  623. X
  624. X    register char    *cp;
  625. X
  626. X    /*
  627. X     * Write out the characters which comprise the line.
  628. X     * Register declarations are used for all variables
  629. X     * which form a part of this loop, in order to make
  630. X     * it as fast as possible.
  631. X     */
  632. X    for (cp = lp->l_text; *cp != '\0'; cp++) {
  633. X        putc(*cp, f);
  634. X        nchars++;
  635. X    }
  636. X
  637. X    putc(eolnchars[0], f);
  638. X    nchars++;
  639. X
  640. X    if (eolnchars[1] != NOCHAR) {
  641. X        putc(eolnchars[1], f);
  642. X        nchars++;
  643. X    }
  644. X
  645. X    if (ferror(f)) {
  646. X        (void) fclose(f);
  647. X        return(FALSE);
  648. X    }
  649. X
  650. X    nlines++;
  651. X
  652. X    /*
  653. X     * If we were given an upper bound, and we
  654. X     * just did that line, then bag it now.
  655. X     */
  656. X    if (end != NULL) {
  657. X        if (end == lp)
  658. X        break;
  659. X    }
  660. X    }
  661. X
  662. X    if (fclose(f) != 0) {
  663. X    return(FALSE);
  664. X    }
  665. X
  666. X    /*
  667. X     * Success!
  668. X     */
  669. X    if (ncp != NULL)
  670. X    *ncp = nchars;
  671. X    if (nlp != NULL)
  672. X    *nlp = nlines;
  673. X    return(TRUE);
  674. X}
  675. END_OF_FILE
  676.   if test 15127 -ne `wc -c <'xvi/src/fileio.c'`; then
  677.     echo shar: \"'xvi/src/fileio.c'\" unpacked with wrong size!
  678.   fi
  679.   # end of 'xvi/src/fileio.c'
  680. fi
  681. if test -f 'xvi/src/makefile.os2' -a "${1}" != "-c" ; then 
  682.   echo shar: Will not clobber existing file \"'xvi/src/makefile.os2'\"
  683. else
  684.   echo shar: Extracting \"'xvi/src/makefile.os2'\" \(4555 characters\)
  685.   sed "s/^X//" >'xvi/src/makefile.os2' <<'END_OF_FILE'
  686. X# Copyright (c) 1990,1991,1992 Chris and John Downey
  687. X#***
  688. X#
  689. X# @(#)makefile.os2    2.2 (Chris & John Downey) 7/31/92
  690. X#
  691. X# program name:
  692. X#    xvi
  693. X# function:
  694. X#    PD version of UNIX "vi" editor, with extensions.
  695. X# module name:
  696. X#    makefile.os2
  697. X# module function:
  698. X#    Makefile for OS/2
  699. X#
  700. X#    This is for Microsoft's make, which is the stupidest make
  701. X#    ever.
  702. X# history:
  703. X#    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  704. X#    Originally by Tim Thompson (twitch!tjt)
  705. X#    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  706. X#    Heavily modified by Chris & John Downey
  707. X#***
  708. X
  709. X#
  710. X# Name of this file.
  711. X#
  712. XTHISFILE=    makefile.os2
  713. X
  714. X#
  715. X# Microsoft C directory for OS/2.
  716. X#
  717. XMSCOS2=        d:\msc5.1\os2
  718. X
  719. X#
  720. X# Microsoft C directory for MS-DOS.
  721. X#
  722. XMSCMSDOS=    d:\msc5.1\msdos
  723. X
  724. X#
  725. X# Directory for PMSDK executables.
  726. X#
  727. XPMSDKBIN=    d:\pmsdk\bin
  728. X
  729. XCC=        $(MSCOS2)\pbin\cl
  730. XMODEL=        -AL
  731. XDEBUGFLAG=
  732. XINCDIRS=    -I$(MSCMSDOS)\include -I$(MSCOS2)\include
  733. XCFLAGS=        -DOS2 $(DEBUGFLAG) $(MODEL) $(INCDIRS)
  734. XAS=        c:\bin\masm
  735. XASFLAGS=    -Ml
  736. XLD=        $(MSCOS2)\pbin\link
  737. XLDFLAGS=    /STACK:45056 /NOE /MAP
  738. XMARKEXE=    $(PMSDKBIN)\markexe
  739. XEXEFLAG=    WINDOWCOMPAT
  740. X
  741. XMACHOBJ=    os2vio.obj
  742. XMACHSRC=    os2vio.c
  743. X
  744. XINC=        ascii.h param.h ptrfunc.h regexp.h regmagic.h xvi.h \
  745. X        virtscr.h os2vio.h
  746. X
  747. XOBJ=        defscr.obj \
  748. X        alloc.obj ascii.obj buffers.obj cmdline.obj cursor.obj \
  749. X        edit.obj ex_cmds1.obj ex_cmds2.obj events.obj fileio.obj \
  750. X        find.obj flexbuf.obj map.obj mark.obj misccmds.obj \
  751. X        movement.obj normal.obj param.obj pipe.obj preserve.obj \
  752. X        ptrfunc.obj regexp.obj screen.obj search.obj signal.obj \
  753. X        startup.obj status.obj tags.obj undo.obj \
  754. X        windows.obj yankput.obj \
  755. X        $(MACHOBJ) i286.obj $(LIB)\setargv.obj
  756. X
  757. Xdefscr.obj:    defscr.c $(INC) param.c
  758. X        $(CC) -c $(CFLAGS) defscr.c
  759. X
  760. Xalloc.obj:    alloc.c $(INC) param.c
  761. X        $(CC) -c $(CFLAGS) alloc.c
  762. X
  763. Xascii.obj:    ascii.c $(INC) param.c
  764. X        $(CC) -c $(CFLAGS) ascii.c
  765. X
  766. Xbuffers.obj:    buffers.c $(INC) param.c
  767. X        $(CC) -c $(CFLAGS) buffers.c
  768. X
  769. Xcmdline.obj:    cmdline.c $(INC) param.c
  770. X        $(CC) -c $(CFLAGS) cmdline.c
  771. X
  772. Xcursor.obj:    cursor.c $(INC) param.c
  773. X        $(CC) -c $(CFLAGS) cursor.c
  774. X
  775. Xedit.obj:    edit.c $(INC) param.c
  776. X        $(CC) -c $(CFLAGS) edit.c
  777. X
  778. Xex_cmds1.obj:    ex_cmds1.c $(INC) param.c
  779. X        $(CC) -c $(CFLAGS) ex_cmds1.c
  780. X
  781. Xex_cmds2.obj:    ex_cmds2.c $(INC) param.c
  782. X        $(CC) -c $(CFLAGS) ex_cmds2.c
  783. X
  784. Xevents.obj:    events.c $(INC) param.c
  785. X        $(CC) -c $(CFLAGS) events.c
  786. X
  787. Xfileio.obj:    fileio.c $(INC) param.c
  788. X        $(CC) -c $(CFLAGS) fileio.c
  789. X
  790. Xfind.obj:    find.c $(INC) param.c
  791. X        $(CC) -c $(CFLAGS) find.c
  792. X
  793. Xflexbuf.obj:    flexbuf.c $(INC) param.c
  794. X        $(CC) -c $(CFLAGS) flexbuf.c
  795. X
  796. Xmap.obj:    map.c $(INC) param.c
  797. X        $(CC) -c $(CFLAGS) map.c
  798. X
  799. Xmark.obj:    mark.c $(INC) param.c
  800. X        $(CC) -c $(CFLAGS) mark.c
  801. X
  802. Xmisccmds.obj:    misccmds.c $(INC) param.c
  803. X        $(CC) -c $(CFLAGS) misccmds.c
  804. X
  805. Xmovement.obj:    movement.c $(INC) param.c
  806. X        $(CC) -c $(CFLAGS) movement.c
  807. X
  808. Xnormal.obj:    normal.c $(INC) param.c
  809. X        $(CC) -c $(CFLAGS) normal.c
  810. X
  811. Xparam.obj:    param.c $(INC)
  812. X        $(CC) -c $(CFLAGS) param.c
  813. X
  814. Xpipe.obj:    pipe.c $(INC) param.c
  815. X        $(CC) -c $(CFLAGS) pipe.c
  816. X
  817. Xpreserve.obj:    preserve.c $(INC) param.c
  818. X        $(CC) -c $(CFLAGS) preserve.c
  819. X
  820. Xptrfunc.obj:    ptrfunc.c $(INC) param.c
  821. X        $(CC) -c $(CFLAGS) ptrfunc.c
  822. X
  823. Xregexp.obj:    regexp.c $(INC)
  824. X        $(CC) -c $(CFLAGS) -Fo$@ regexp.c
  825. X
  826. Xscreen.obj:    screen.c $(INC) param.c
  827. X        $(CC) -c $(CFLAGS) screen.c
  828. X
  829. Xsearch.obj:    search.c $(INC) param.c
  830. X        $(CC) -c $(CFLAGS) search.c
  831. X
  832. Xsignal.obj:    signal.c $(INC) param.c
  833. X        $(CC) -c $(CFLAGS) signal.c
  834. X
  835. Xstartup.obj:    startup.c $(INC) param.c
  836. X        $(CC) -c $(CFLAGS) startup.c
  837. X
  838. Xstatus.obj:    status.c $(INC) param.c
  839. X        $(CC) -c $(CFLAGS) status.c
  840. X
  841. Xtags.obj:    tags.c $(INC) param.c
  842. X        $(CC) -c $(CFLAGS) tags.c
  843. X
  844. Xundo.obj:    undo.c $(INC) param.c
  845. X        $(CC) -c $(CFLAGS) undo.c
  846. X
  847. Xwindows.obj:    windows.c $(INC) param.c
  848. X        $(CC) -c $(CFLAGS) windows.c
  849. X
  850. Xyankput.obj:    yankput.c $(INC) param.c
  851. X        $(CC) -c $(CFLAGS) yankput.c
  852. X
  853. Xi286.obj:    i286.asm
  854. X        $(AS) $(ASFLAGS) i286.asm ;
  855. X
  856. X$(MACHOBJ):    $(MACHSRC) $(INC)
  857. X        $(CC) -c $(CFLAGS) $(MACHSRC)
  858. X
  859. XBASENAM=    xvi
  860. XLINKFILE=    $(BASENAM).lnk
  861. X
  862. X$(LINKFILE):    $(THISFILE)
  863. X        echo defscr + > $@
  864. X        echo alloc + ascii + buffers + cmdline + cursor + >> $@
  865. X        echo edit + ex_cmds1 + ex_cmds2 + events + fileio + find + >> $@
  866. X        echo flexbuf + map + mark + misccmds + movement + >> $@
  867. X        echo normal + param + pipe + preserve + ptrfunc + >> $@
  868. X        echo regexp + screen + search + signal + startup + >> $@
  869. X        echo status + tags + undo + version + >> $@
  870. X        echo windows + yankput + >> $@
  871. X        echo $(MACHOBJ) + i286 + $(LIB)\setargv >> $@
  872. X        echo $(BASENAM).exe $(LDFLAGS) ;  >> $@
  873. X
  874. X$(BASENAM).exe: $(OBJ) $(LINKFILE) version.c
  875. X        $(CC) $(CFLAGS) -c version.c
  876. X        $(LD) @$(LINKFILE)
  877. X        $(MARKEXE) $(EXEFLAG) $@
  878. END_OF_FILE
  879.   if test 4555 -ne `wc -c <'xvi/src/makefile.os2'`; then
  880.     echo shar: \"'xvi/src/makefile.os2'\" unpacked with wrong size!
  881.   fi
  882.   # end of 'xvi/src/makefile.os2'
  883. fi
  884. if test -f 'xvi/src/regexp.c' -a "${1}" != "-c" ; then 
  885.   echo shar: Will not clobber existing file \"'xvi/src/regexp.c'\"
  886. else
  887.   echo shar: Extracting \"'xvi/src/regexp.c'\" \(32150 characters\)
  888.   sed "s/^X//" >'xvi/src/regexp.c' <<'END_OF_FILE'
  889. X#ifndef lint
  890. Xstatic char *sccsid = "@(#)regexp.c    2.1 7/29/92";
  891. Xstatic char *copyright = "Copyright (c) 1986 by University of Toronto.";
  892. X#endif
  893. X
  894. X/***
  895. X
  896. X* program name:
  897. X    xvi
  898. X* function:
  899. X    PD version of UNIX "vi" editor, with extensions.
  900. X* module name:
  901. X    regexp.c
  902. X* module function:
  903. X    Regular expression routines.
  904. X* history:
  905. X    Regular expression routines by Henry Spencer.
  906. X    Modfied for use with STEVIE (ST Editor for VI Enthusiasts,
  907. X     Version 3.10) by Tony Andrews.
  908. X    Adapted for use with Xvi by Chris & John Downey.
  909. X    Original copyright notice appears below.
  910. X    Please note that this is a modified version.
  911. X***/
  912. X
  913. X/*
  914. X * regcomp and regexec -- regsub and regerror are elsewhere
  915. X *
  916. X *    Copyright (c) 1986 by University of Toronto.
  917. X *    Written by Henry Spencer.  Not derived from licensed software.
  918. X *
  919. X *    Permission is granted to anyone to use this software for any
  920. X *    purpose on any computer system, and to redistribute it freely,
  921. X *    subject to the following restrictions:
  922. X *
  923. X *    1. The author is not responsible for the consequences of use of
  924. X *        this software, no matter how awful, even if they arise
  925. X *        from defects in it.
  926. X *
  927. X *    2. The origin of this software must not be misrepresented, either
  928. X *        by explicit claim or by omission.
  929. X *
  930. X *    3. Altered versions must be plainly marked as such, and must not
  931. X *        be misrepresented as being the original software.
  932. X *
  933. X * Beware that some of this code is subtly aware of the way operator
  934. X * precedence is structured in regular expressions.  Serious changes in
  935. X * regular-expression syntax might require a total rethink.
  936. X *
  937. X * $Log:    regexp.c,v $
  938. X * Revision 1.2     88/04/28  08:09:45  tony
  939. X * First modification of the regexp library. Added an external variable
  940. X * 'reg_ic' which can be set to indicate that case should be ignored.
  941. X * Added a new parameter to regexec() to indicate that the given string
  942. X * comes from the beginning of a line and is thus eligible to match
  943. X * 'beginning-of-line'.
  944. X *
  945. X * xvi, version 1.7:
  946. X *
  947. X * Pb(P_ignorecase) replaces reg_ic.
  948. X *
  949. X * BWORD (beginning of word) & EWORD (end of word) implemented.
  950. X *
  951. X * Some strings passed to regerror() are altered slightly, for
  952. X * consistency with other error messages in xvi.
  953. X */
  954. X
  955. X#include "xvi.h"
  956. X#include "regexp.h"
  957. X#include "regmagic.h"
  958. X
  959. X#ifdef    MEGAMAX
  960. Xoverlay "regexp"
  961. X#endif
  962. X
  963. X/*
  964. X * Exported functions.
  965. X */
  966. Xint    cstrncmp P((char *s1, char *s2, int n));
  967. Xchar    *cstrchr P((char *s, int c));
  968. X
  969. X/*
  970. X * The "internal use only" fields in regexp.h are present to pass info from
  971. X * compile to execute that permits the execute phase to run lots faster on
  972. X * simple cases.  They are:
  973. X *
  974. X * regstart    char that must begin a match; '\0' if none obvious
  975. X * reganch    is the match anchored (at beginning-of-line only)?
  976. X * regmust    string (pointer into program) that match must include, or NULL
  977. X * regmlen    length of regmust string
  978. X *
  979. X * Regstart and reganch permit very fast decisions on suitable starting points
  980. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  981. X * of lines that cannot possibly match.     The regmust tests are costly enough
  982. X * that regcomp() supplies a regmust only if the r.e. contains something
  983. X * potentially expensive (at present, the only such thing detected is * or +
  984. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  985. X * supplied because the test in regexec() needs it and regcomp() is computing
  986. X * it anyway.
  987. X */
  988. X
  989. X/*
  990. X * Structure for regexp "program".  This is essentially a linear encoding
  991. X * of a nondeterministic finite-state machine (aka syntax charts or
  992. X * "railroad normal form" in parsing technology).  Each node is an opcode
  993. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  994. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  995. X * a BRANCH on both ends of it is connecting two alternatives.    (Here we
  996. X * have one of the subtle syntax dependencies:    an individual BRANCH (as
  997. X * opposed to a collection of them) is never concatenated with anything
  998. X * because of operator precedence.)  The operand of some types of node is
  999. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  1000. X * particular, the operand of a BRANCH node is the first node of the branch.
  1001. X * (NB this is *not* a tree structure:    the tail of the branch connects
  1002. X * to the thing following the set of BRANCHes.)     The opcodes are:
  1003. X */
  1004. X
  1005. X/* definition    number    opnd?    meaning */
  1006. X#define END    0    /* no    End of program. */
  1007. X#define BOL    1    /* no    Match "" at beginning of line. */
  1008. X#define EOL    2    /* no    Match "" at end of line. */
  1009. X#define ANY    3    /* no    Match any one character. */
  1010. X#define ANYOF    4    /* str    Match any character in this string. */
  1011. X#define ANYBUT    5    /* str    Match any character not in this string. */
  1012. X#define BRANCH    6    /* node Match this alternative, or the next... */
  1013. X#define BACK    7    /* no    Match "", "next" ptr points backward. */
  1014. X#define EXACTLY 8    /* str    Match this string. */
  1015. X#define NOTHING 9    /* no    Match empty string. */
  1016. X#define STAR    10    /* node Match this (simple) thing 0 or more times. */
  1017. X#define PLUS    11    /* node Match this (simple) thing 1 or more times. */
  1018. X#define OPEN    20    /* no    Mark this point in input as start of #n. */
  1019. X        /*    OPEN+1 is number 1, etc. */
  1020. X#define CLOSE    30    /* no    Analogous to OPEN. */
  1021. X#define BWORD    64    /* no    Beginning of word. */
  1022. X#define EWORD    65    /* no    End of word. */
  1023. X
  1024. X/*
  1025. X * Opcode notes:
  1026. X *
  1027. X * BRANCH    The set of branches constituting a single choice are hooked
  1028. X *        together with their "next" pointers, since precedence prevents
  1029. X *        anything being concatenated to any individual branch.  The
  1030. X *        "next" pointer of the last BRANCH in a choice points to the
  1031. X *        thing following the whole choice.  This is also where the
  1032. X *        final "next" pointer of each individual branch points; each
  1033. X *        branch starts with the operand node of a BRANCH node.
  1034. X *
  1035. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  1036. X *        exists to make loop structures possible.
  1037. X *
  1038. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  1039. X *        BRANCH structures using BACK.  Simple cases (one character
  1040. X *        per match) are implemented with STAR and PLUS for speed
  1041. X *        and to minimize recursive plunges.
  1042. X *
  1043. X * OPEN,CLOSE    ...are numbered at compile time.
  1044. X */
  1045. X
  1046. X/*
  1047. X * A node is one char of opcode followed by two chars of "next" pointer.
  1048. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  1049. X * value is a positive offset from the opcode of the node containing it.
  1050. X * An operand, if any, simply follows the node.     (Note that much of the
  1051. X * code generation knows about this implicit relationship.)
  1052. X *
  1053. X * Using two bytes for the "next" pointer is vast overkill for most things,
  1054. X * but allows patterns to get big without disasters.
  1055. X */
  1056. X#define OP(p)        (*(p))
  1057. X#define NEXT(p)     (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  1058. X#define OPERAND(p)    ((p) + 3)
  1059. X
  1060. X/*
  1061. X * See regmagic.h for one further detail of program structure.
  1062. X */
  1063. X
  1064. X
  1065. X/*
  1066. X * Utility definitions.
  1067. X */
  1068. X#ifndef CHARBITS
  1069. X#define UCHARAT(p)    ((int)*(unsigned char *)(p))
  1070. X#else
  1071. X#define UCHARAT(p)    ((int)*(p)&CHARBITS)
  1072. X#endif
  1073. X
  1074. X#define FAIL(m)     { regerror(m); return(NULL); }
  1075. X#define ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  1076. X#define META        "^$.[()|?+*\\"
  1077. X
  1078. X/*
  1079. X * Flags to be passed up and down.
  1080. X */
  1081. X#define HASWIDTH    01    /* Known never to match null string. */
  1082. X#define SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  1083. X#define SPSTART        04    /* Starts with * or +. */
  1084. X#define WORST        0    /* Worst case. */
  1085. X
  1086. X/*
  1087. X * mkup - convert to upper case IF we're doing caseless compares
  1088. X */
  1089. X#define mkup(c)        ((Pb(P_ignorecase) && is_lower(c)) ? \
  1090. X                        to_upper(c) : (c))
  1091. X
  1092. X/*
  1093. X * Global work variables for regcomp().
  1094. X */
  1095. Xstatic char *regparse;        /* Input-scan pointer. */
  1096. Xstatic int regnpar;        /* () count. */
  1097. Xstatic char regdummy;
  1098. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  1099. Xstatic long regsize;        /* Code size. */
  1100. X
  1101. X/*
  1102. X * Forward declarations for regcomp()'s friends.
  1103. X */
  1104. X#ifndef STATIC
  1105. X#    define    STATIC    static
  1106. X#endif
  1107. X
  1108. XSTATIC    char    *reg P((int paren, int *flagp));
  1109. XSTATIC    char    *regbranch P((int *flagp));
  1110. XSTATIC    char    *regpiece P((int *flagp));
  1111. XSTATIC    char    *regatom P((int *flagp));
  1112. XSTATIC    char    *regnode P((int op));
  1113. XSTATIC    char    *regnext P((char *p));
  1114. XSTATIC    void    regc P((int b));
  1115. XSTATIC    void    reginsert P((int op, char *opnd));
  1116. XSTATIC    void    regtail P((char *p, char *val));
  1117. XSTATIC    void    regoptail P((char *p, char *val));
  1118. X
  1119. X#ifdef STRCSPN
  1120. X    static    int    strcspn P((char *s1, char *s2));
  1121. X#endif
  1122. X
  1123. X/*
  1124. X - regcomp - compile a regular expression into internal code
  1125. X *
  1126. X * We can't allocate space until we know how big the compiled form will be,
  1127. X * but we can't compile it (and thus know how big it is) until we've got a
  1128. X * place to put the code.  So we cheat:     we compile it twice, once with code
  1129. X * generation turned off and size counting turned on, and once "for real".
  1130. X * This also means that we don't allocate space until we are sure that the
  1131. X * thing really will compile successfully, and we never have to move the
  1132. X * code and thus invalidate pointers into it.  (Note that it has to be in
  1133. X * one piece because free() must be able to free it all.)
  1134. X *
  1135. X * Beware that the optimization-preparation code in here knows about some
  1136. X * of the structure of the compiled regexp.
  1137. X */
  1138. Xregexp *
  1139. Xregcomp(exp)
  1140. Xchar *exp;
  1141. X{
  1142. X    register regexp *r;
  1143. X    register char *scan;
  1144. X    register char *longest;
  1145. X    register int len;
  1146. X    int flags;
  1147. X
  1148. X    if (exp == NULL)
  1149. X    FAIL("NULL argument");
  1150. X
  1151. X    /* First pass: determine size, legality. */
  1152. X    regparse = exp;
  1153. X    regnpar = 1;
  1154. X    regsize = 0L;
  1155. X    regcode = ®dummy;
  1156. X    regc(MAGIC);
  1157. X    if (reg(0, &flags) == NULL)
  1158. X    return(NULL);
  1159. X
  1160. X    /* Small enough for pointer-storage convention? */
  1161. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  1162. X    FAIL("Regular expression too big");
  1163. X
  1164. X    /* Allocate space. */
  1165. X    r = (regexp *) alloc(sizeof(regexp) + (unsigned)regsize);
  1166. X    if (r == NULL)
  1167. X    return NULL;
  1168. X
  1169. X    /* Second pass: emit code. */
  1170. X    regparse = exp;
  1171. X    regnpar = 1;
  1172. X    regcode = r->program;
  1173. X    regc(MAGIC);
  1174. X    if (reg(0, &flags) == NULL)
  1175. X    return(NULL);
  1176. X
  1177. X    /* Dig out information for optimizations. */
  1178. X    r->regstart = '\0';    /* Worst-case defaults. */
  1179. X    r->reganch = 0;
  1180. X    r->regmust = NULL;
  1181. X    r->regmlen = 0;
  1182. X    scan = r->program+1;            /* First BRANCH. */
  1183. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  1184. X    scan = OPERAND(scan);
  1185. X
  1186. X    /* Starting-point info. */
  1187. X    if (OP(scan) == EXACTLY)
  1188. X        r->regstart = *OPERAND(scan);
  1189. X    else if (OP(scan) == BOL)
  1190. X        r->reganch++;
  1191. X
  1192. X    /*
  1193. X     * If there's something expensive in the r.e., find the
  1194. X     * longest literal string that must appear and make it the
  1195. X     * regmust.  Resolve ties in favor of later strings, since
  1196. X     * the regstart check works with the beginning of the r.e.
  1197. X     * and avoiding duplication strengthens checking.  Not a
  1198. X     * strong reason, but sufficient in the absence of others.
  1199. X     */
  1200. X    if (flags&SPSTART) {
  1201. X        longest = NULL;
  1202. X        len = 0;
  1203. X        for (; scan != NULL; scan = regnext(scan))
  1204. X        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  1205. X            longest = OPERAND(scan);
  1206. X            len = strlen(OPERAND(scan));
  1207. X        }
  1208. X        r->regmust = longest;
  1209. X        r->regmlen = len;
  1210. X    }
  1211. X    }
  1212. X
  1213. X    return(r);
  1214. X}
  1215. X
  1216. X/*
  1217. X - reg - regular expression, i.e. main body or parenthesized thing
  1218. X *
  1219. X * Caller must absorb opening parenthesis.
  1220. X *
  1221. X * Combining parenthesis handling with the base level of regular expression
  1222. X * is a trifle forced, but the need to tie the tails of the branches to what
  1223. X * follows makes it hard to avoid.
  1224. X */
  1225. Xstatic char *
  1226. Xreg(paren, flagp)
  1227. Xint paren;            /* Parenthesized? */
  1228. Xint *flagp;
  1229. X{
  1230. X    register char *ret;
  1231. X    register char *br;
  1232. X    register char *ender;
  1233. X    register int parno;
  1234. X    int flags;
  1235. X
  1236. X    *flagp = HASWIDTH;    /* Tentatively. */
  1237. X
  1238. X    /* Make an OPEN node, if parenthesized. */
  1239. X    if (paren) {
  1240. X    if (regnpar >= NSUBEXP)
  1241. X        FAIL("Too many ()");
  1242. X    parno = regnpar;
  1243. X    regnpar++;
  1244. X    ret = regnode(OPEN+parno);
  1245. X    } else
  1246. X    ret = NULL;
  1247. X
  1248. X    /* Pick up the branches, linking them together. */
  1249. X    br = regbranch(&flags);
  1250. X    if (br == NULL)
  1251. X    return(NULL);
  1252. X    if (ret != NULL)
  1253. X    regtail(ret, br);    /* OPEN -> first. */
  1254. X    else
  1255. X    ret = br;
  1256. X    if (!(flags&HASWIDTH))
  1257. X    *flagp &= ~HASWIDTH;
  1258. X    *flagp |= flags&SPSTART;
  1259. X    while (*regparse == '|') {
  1260. X    regparse++;
  1261. X    br = regbranch(&flags);
  1262. X    if (br == NULL)
  1263. X        return(NULL);
  1264. X    regtail(ret, br);    /* BRANCH -> BRANCH. */
  1265. X    if (!(flags&HASWIDTH))
  1266. X        *flagp &= ~HASWIDTH;
  1267. X    *flagp |= flags&SPSTART;
  1268. X    }
  1269. X
  1270. X    /* Make a closing node, and hook it on the end. */
  1271. X    ender = regnode((paren) ? CLOSE+parno : END);
  1272. X    regtail(ret, ender);
  1273. X
  1274. X    /* Hook the tails of the branches to the closing node. */
  1275. X    for (br = ret; br != NULL; br = regnext(br))
  1276. X    regoptail(br, ender);
  1277. X
  1278. X    /* Check for proper termination. */
  1279. X    if (paren && *regparse++ != ')') {
  1280. X    FAIL("Unmatched ()");
  1281. X    } else if (!paren && *regparse != '\0') {
  1282. X    if (*regparse == ')') {
  1283. X        FAIL("Unmatched ()");
  1284. X    } else
  1285. X        FAIL("Junk on end");    /* "Can't happen". */
  1286. X    /* NOTREACHED */
  1287. X    }
  1288. X
  1289. X    return(ret);
  1290. X}
  1291. X
  1292. X/*
  1293. X - regbranch - one alternative of an | operator
  1294. X *
  1295. X * Implements the concatenation operator.
  1296. X */
  1297. Xstatic char *
  1298. Xregbranch(flagp)
  1299. Xint *flagp;
  1300. X{
  1301. X    register char *ret;
  1302. X    register char *chain;
  1303. X    register char *latest;
  1304. X    int flags;
  1305. X
  1306. X    *flagp = WORST;        /* Tentatively. */
  1307. X
  1308. X    ret = regnode(BRANCH);
  1309. X    chain = NULL;
  1310. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  1311. X    latest = regpiece(&flags);
  1312. X    if (latest == NULL)
  1313. X        return(NULL);
  1314. X    *flagp |= flags&HASWIDTH;
  1315. X    if (chain == NULL)    /* First piece. */
  1316. X        *flagp |= flags&SPSTART;
  1317. X    else
  1318. X        regtail(chain, latest);
  1319. X    chain = latest;
  1320. X    }
  1321. X    if (chain == NULL)    /* Loop ran zero times. */
  1322. X    (void) regnode(NOTHING);
  1323. X
  1324. X    return(ret);
  1325. X}
  1326. X
  1327. X/*
  1328. X - regpiece - something followed by possible [*+?]
  1329. X *
  1330. X * Note that the branching code sequences used for ? and the general cases
  1331. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  1332. X * both the endmarker for their branch list and the body of the last branch.
  1333. X * It might seem that this node could be dispensed with entirely, but the
  1334. X * endmarker role is not redundant.
  1335. X */
  1336. Xstatic char *
  1337. Xregpiece(flagp)
  1338. Xint *flagp;
  1339. X{
  1340. X    register char *ret;
  1341. X    register char op;
  1342. X    register char *next;
  1343. X    int flags;
  1344. X
  1345. X    ret = regatom(&flags);
  1346. X    if (ret == NULL)
  1347. X    return(NULL);
  1348. X
  1349. X    op = *regparse;
  1350. X    if (!ISMULT(op)) {
  1351. X    *flagp = flags;
  1352. X    return(ret);
  1353. X    }
  1354. X
  1355. X    if (!(flags&HASWIDTH) && op != '?')
  1356. X    FAIL("*+ operand could be empty");
  1357. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  1358. X
  1359. X    if (op == '*' && (flags&SIMPLE))
  1360. X    reginsert(STAR, ret);
  1361. X    else if (op == '*') {
  1362. X    /* Emit x* as (x&|), where & means "self". */
  1363. X    reginsert(BRANCH, ret);            /* Either x */
  1364. X    regoptail(ret, regnode(BACK));        /* and loop */
  1365. X    regoptail(ret, ret);            /* back */
  1366. X    regtail(ret, regnode(BRANCH));        /* or */
  1367. X    regtail(ret, regnode(NOTHING));        /* null. */
  1368. X    } else if (op == '+' && (flags&SIMPLE))
  1369. X    reginsert(PLUS, ret);
  1370. X    else if (op == '+') {
  1371. X    /* Emit x+ as x(&|), where & means "self". */
  1372. X    next = regnode(BRANCH);            /* Either */
  1373. X    regtail(ret, next);
  1374. X    regtail(regnode(BACK), ret);        /* loop back */
  1375. X    regtail(next, regnode(BRANCH));        /* or */
  1376. X    regtail(ret, regnode(NOTHING));        /* null. */
  1377. X    } else if (op == '?') {
  1378. X    /* Emit x? as (x|) */
  1379. X    reginsert(BRANCH, ret);            /* Either x */
  1380. X    regtail(ret, regnode(BRANCH));        /* or */
  1381. X    next = regnode(NOTHING);        /* null. */
  1382. X    regtail(ret, next);
  1383. X    regoptail(ret, next);
  1384. X    }
  1385. X    regparse++;
  1386. X    if (ISMULT(*regparse))
  1387. X    FAIL("Nested *?+");
  1388. X
  1389. X    return(ret);
  1390. X}
  1391. X
  1392. X/*
  1393. X * This is called by regatom() for characters with no special meaning.
  1394. X */
  1395. Xstatic char *
  1396. Xregdefault(flagp)
  1397. Xint *flagp;
  1398. X{
  1399. X    register int len;
  1400. X    register char ender;
  1401. X    register char *ret;
  1402. X
  1403. X    len = strcspn(regparse, META);
  1404. X    if (len <= 0)
  1405. X    FAIL("Internal disaster");
  1406. X    ender = regparse[len];
  1407. X    if (len > 1 && ISMULT(ender))
  1408. X    len--;        /* Back off clear of ?+* operand. */
  1409. X    *flagp |= HASWIDTH;
  1410. X    if (len == 1)
  1411. X    *flagp |= SIMPLE;
  1412. X    ret = regnode(EXACTLY);
  1413. X    while (len > 0) {
  1414. X    regc(*regparse++);
  1415. X    len--;
  1416. X    }
  1417. X    regc('\0');
  1418. X    return ret;
  1419. X}
  1420. X
  1421. X/*
  1422. X - regatom - the lowest level
  1423. X *
  1424. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  1425. X * it can turn them into a single node, which is smaller to store and
  1426. X * faster to run.  Backslashed characters are exceptions, each becoming a
  1427. X * separate node; the code is simpler that way and it's not worth fixing.
  1428. X */
  1429. Xstatic char *
  1430. Xregatom(flagp)
  1431. Xint *flagp;
  1432. X{
  1433. X    register char *ret;
  1434. X    int flags;
  1435. X
  1436. X    *flagp = WORST;        /* Tentatively. */
  1437. X
  1438. X#if 0
  1439. X    if (Pn(P_regextype) == rt_TAGS)
  1440. X    {
  1441. X    switch (*regparse)
  1442. X    {
  1443. X        case '^':
  1444. X        case '$':
  1445. X        break;
  1446. X        case '\\':
  1447. X        switch (*++regparse)
  1448. X        {
  1449. X            case '^':
  1450. X            case '$':
  1451. X            ret = regnode(EXACTLY);
  1452. X            regc(*regparse);
  1453. X            regc('\0');
  1454. X            *flagp |= HASWIDTH|SIMPLE;
  1455. X            regparse++;
  1456. X            return ret;
  1457. X        }
  1458. X        break;
  1459. X        default:
  1460. X        return regdefault(flagp);
  1461. X    }
  1462. X    }
  1463. X#endif
  1464. X    switch (*regparse++) {
  1465. X    case '^':
  1466. X    ret = regnode(BOL);
  1467. X    break;
  1468. X    case '$':
  1469. X    ret = regnode(EOL);
  1470. X    break;
  1471. X    case '.':
  1472. X    ret = regnode(ANY);
  1473. X    *flagp |= HASWIDTH|SIMPLE;
  1474. X    break;
  1475. X    case '[':
  1476. X    {
  1477. X    register int class;
  1478. X    register int classend;
  1479. X
  1480. X    if (*regparse == '^') {    /* Complement of range. */
  1481. X        ret = regnode(ANYBUT);
  1482. X        regparse++;
  1483. X    } else
  1484. X        ret = regnode(ANYOF);
  1485. X    if (*regparse == ']' || *regparse == '-')
  1486. X        regc(*regparse++);
  1487. X    while (*regparse != '\0' && *regparse != ']') {
  1488. X        if (*regparse == '-') {
  1489. X        regparse++;
  1490. X        if (*regparse == ']' || *regparse == '\0')
  1491. X            regc('-');
  1492. X        else {
  1493. X            class = UCHARAT(regparse-2)+1;
  1494. X            classend = UCHARAT(regparse);
  1495. X            if (class > classend+1)
  1496. X            FAIL("Invalid [] range");
  1497. X            for (; class <= classend; class++)
  1498. X            regc(class);
  1499. X            regparse++;
  1500. X        }
  1501. X        } else
  1502. X        regc(*regparse++);
  1503. X    }
  1504. X    regc('\0');
  1505. X    if (*regparse != ']')
  1506. X        FAIL("Unmatched []");
  1507. X    regparse++;
  1508. X    *flagp |= HASWIDTH|SIMPLE;
  1509. X    }
  1510. X    break;
  1511. X    case '(':
  1512. X    ret = reg(1, &flags);
  1513. X    if (ret == NULL)
  1514. X        return(NULL);
  1515. X    *flagp |= flags&(HASWIDTH|SPSTART);
  1516. X    break;
  1517. X    case '\0':
  1518. X    case '|':
  1519. X    case ')':
  1520. X    FAIL("Internal urp");    /* Supposed to be caught earlier. */
  1521. X    break;
  1522. X    case '?':
  1523. X    case '+':
  1524. X    case '*':
  1525. X    FAIL("?+* follows nothing");
  1526. X    break;
  1527. X    case '\\':
  1528. X    switch (*regparse)
  1529. X    {
  1530. X        case '\0':
  1531. X        FAIL("Trailing \\");
  1532. X        case '<':
  1533. X        ret = regnode(BWORD);
  1534. X        break;
  1535. X        case '>':
  1536. X        ret = regnode(EWORD);
  1537. X        break;
  1538. X        default:
  1539. X        ret = regnode(EXACTLY);
  1540. X        regc(*regparse);
  1541. X        regc('\0');
  1542. X        *flagp |= HASWIDTH|SIMPLE;
  1543. X    }
  1544. X    regparse++;
  1545. X    break;
  1546. X    default:
  1547. X    regparse--;
  1548. X    ret = regdefault(flagp);
  1549. X    }
  1550. X
  1551. X    return(ret);
  1552. X}
  1553. X
  1554. X/*
  1555. X - regnode - emit a node
  1556. X */
  1557. Xstatic char *            /* Location. */
  1558. Xregnode(op)
  1559. Xint op;
  1560. X{
  1561. X    register char *ret;
  1562. X    register char *ptr;
  1563. X
  1564. X    ret = regcode;
  1565. X    if (ret == ®dummy) {
  1566. X    regsize += 3;
  1567. X    return(ret);
  1568. X    }
  1569. X
  1570. X    ptr = ret;
  1571. X    *ptr++ = op;
  1572. X    *ptr++ = '\0';        /* Null "next" pointer. */
  1573. X    *ptr++ = '\0';
  1574. X    regcode = ptr;
  1575. X
  1576. X    return(ret);
  1577. X}
  1578. X
  1579. X/*
  1580. X - regc - emit (if appropriate) a byte of code
  1581. X */
  1582. Xstatic void
  1583. Xregc(b)
  1584. Xint b;
  1585. X{
  1586. X    if (regcode != ®dummy)
  1587. X    *regcode++ = b;
  1588. X    else
  1589. X    regsize++;
  1590. X}
  1591. X
  1592. X/*
  1593. X - reginsert - insert an operator in front of already-emitted operand
  1594. X *
  1595. X * Means relocating the operand.
  1596. X */
  1597. Xstatic void
  1598. Xreginsert(op, opnd)
  1599. Xint op;
  1600. Xchar *opnd;
  1601. X{
  1602. X    register char *src;
  1603. X    register char *dst;
  1604. X    register char *place;
  1605. X
  1606. X    if (regcode == ®dummy) {
  1607. X    regsize += 3;
  1608. X    return;
  1609. X    }
  1610. X
  1611. X    src = regcode;
  1612. X    regcode += 3;
  1613. X    dst = regcode;
  1614. X    while (src > opnd)
  1615. X    *--dst = *--src;
  1616. X
  1617. X    place = opnd;        /* Op node, where operand used to be. */
  1618. X    *place++ = op;
  1619. X    *place++ = '\0';
  1620. X    *place++ = '\0';
  1621. X}
  1622. X
  1623. X/*
  1624. X - regtail - set the next-pointer at the end of a node chain
  1625. X */
  1626. Xstatic void
  1627. Xregtail(p, val)
  1628. Xchar *p;
  1629. Xchar *val;
  1630. X{
  1631. X    register char *scan;
  1632. X    register char *temp;
  1633. X    register int offset;
  1634. X
  1635. X    if (p == ®dummy)
  1636. X    return;
  1637. X
  1638. X    /* Find last node. */
  1639. X    scan = p;
  1640. X    for (;;) {
  1641. X    temp = regnext(scan);
  1642. X    if (temp == NULL)
  1643. X        break;
  1644. X    scan = temp;
  1645. X    }
  1646. X
  1647. X    if (OP(scan) == BACK)
  1648. X    offset = scan - val;
  1649. X    else
  1650. X    offset = val - scan;
  1651. X    *(scan+1) = (offset>>8)&0377;
  1652. X    *(scan+2) = offset&0377;
  1653. X}
  1654. X
  1655. X/*
  1656. X - regoptail - regtail on operand of first argument; nop if operandless
  1657. X */
  1658. Xstatic void
  1659. Xregoptail(p, val)
  1660. Xchar *p;
  1661. Xchar *val;
  1662. X{
  1663. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  1664. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  1665. X    return;
  1666. X    regtail(OPERAND(p), val);
  1667. X}
  1668. X
  1669. X/*
  1670. X * regexec and friends
  1671. X */
  1672. X
  1673. X/*
  1674. X * Global work variables for regexec().
  1675. X */
  1676. Xstatic char *reginput;        /* String-input pointer. */
  1677. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  1678. Xstatic char **regstartp;    /* Pointer to startp array. */
  1679. Xstatic char **regendp;        /* Ditto for endp. */
  1680. X
  1681. X/*
  1682. X * Forwards.
  1683. X */
  1684. XSTATIC    int    regtry P((regexp *prog, char *string));
  1685. XSTATIC    int    regmatch P((char *prog));
  1686. XSTATIC    int    regrepeat P((char *p));
  1687. X
  1688. X#ifdef DEBUG
  1689. X    int        regnarrate = 0;
  1690. X    void    regdump P((regexp *r));
  1691. X    STATIC char    *regprop P((char *op));
  1692. X#endif
  1693. X
  1694. X/*
  1695. X - regexec - match a regexp against a string
  1696. X */
  1697. Xint
  1698. Xregexec(prog, string, at_bol)
  1699. Xregister regexp *prog;
  1700. Xregister char *string;
  1701. Xint at_bol;
  1702. X{
  1703. X    register char *s;
  1704. X
  1705. X    /* Be paranoid... */
  1706. X    if (prog == NULL || string == NULL) {
  1707. X    regerror("NULL parameter");
  1708. X    return(0);
  1709. X    }
  1710. X
  1711. X    /* Check validity of program. */
  1712. X    if (UCHARAT(prog->program) != MAGIC) {
  1713. X    regerror("Corrupted program");
  1714. X    return(0);
  1715. X    }
  1716. X
  1717. X    /* If there is a "must appear" string, look for it. */
  1718. X    if (prog->regmust != NULL) {
  1719. X    s = string;
  1720. X    while ((s = cstrchr(s, prog->regmust[0])) != NULL) {
  1721. X        if (cstrncmp(s, prog->regmust, prog->regmlen) == 0)
  1722. X        break;    /* Found it. */
  1723. X        s++;
  1724. X    }
  1725. X    if (s == NULL)    /* Not present. */
  1726. X        return(0);
  1727. X    }
  1728. X
  1729. X    /* Mark beginning of line for ^ . */
  1730. X    if (at_bol)
  1731. X    regbol = string;    /* is possible to match bol */
  1732. X    else
  1733. X    regbol = NULL;        /* we aren't there, so don't match it */
  1734. X
  1735. X    /* Simplest case:  anchored match need be tried only once. */
  1736. X    if (prog->reganch)
  1737. X    return(regtry(prog, string));
  1738. X
  1739. X    /* Messy cases:     unanchored match. */
  1740. X    s = string;
  1741. X    if (prog->regstart != '\0')
  1742. X    /* We know what char it must start with. */
  1743. X    while ((s = cstrchr(s, prog->regstart)) != NULL) {
  1744. X        if (regtry(prog, s))
  1745. X        return(1);
  1746. X        s++;
  1747. X    }
  1748. X    else
  1749. X    /* We don't -- general case. */
  1750. X    do {
  1751. X        if (regtry(prog, s))
  1752. X        return(1);
  1753. X    } while (*s++ != '\0');
  1754. X
  1755. X    /* Failure. */
  1756. X    return(0);
  1757. X}
  1758. X
  1759. X/*
  1760. X - regtry - try match at specific point
  1761. X */
  1762. Xstatic int            /* 0 failure, 1 success */
  1763. Xregtry(prog, string)
  1764. Xregexp *prog;
  1765. Xchar *string;
  1766. X{
  1767. X    register int i;
  1768. X    register char **sp;
  1769. X    register char **ep;
  1770. X
  1771. X    reginput = string;
  1772. X    regstartp = prog->startp;
  1773. X    regendp = prog->endp;
  1774. X
  1775. X    sp = prog->startp;
  1776. X    ep = prog->endp;
  1777. X    for (i = NSUBEXP; i > 0; i--) {
  1778. X    *sp++ = NULL;
  1779. X    *ep++ = NULL;
  1780. X    }
  1781. X    if (regmatch(prog->program + 1)) {
  1782. X    prog->startp[0] = string;
  1783. X    prog->endp[0] = reginput;
  1784. X    return(1);
  1785. X    } else
  1786. X    return(0);
  1787. X}
  1788. X
  1789. X/*
  1790. X * A word is defined, for BWORD & EWORD, as any sequence of
  1791. X * alphanumeric characters and/or underscores.
  1792. X */
  1793. X#define inword(c)    (is_alnum(c) || (c) == '_')
  1794. X
  1795. X/*
  1796. X - regmatch - main matching routine
  1797. X *
  1798. X * Conceptually the strategy is simple:     check to see whether the current
  1799. X * node matches, call self recursively to see whether the rest matches,
  1800. X * and then act accordingly.  In practice we make some effort to avoid
  1801. X * recursion, in particular by going through "ordinary" nodes (that don't
  1802. X * need to know whether the rest of the match failed) by a loop instead of
  1803. X * by recursion.
  1804. X */
  1805. Xstatic int            /* 0 failure, 1 success */
  1806. Xregmatch(prog)
  1807. Xchar *prog;
  1808. X{
  1809. X    register char *scan;    /* Current node. */
  1810. X    char *next;        /* Next node. */
  1811. X
  1812. X    scan = prog;
  1813. X#ifdef DEBUG
  1814. X    if (scan != NULL && regnarrate)
  1815. X    fprintf(stderr, "%s(\n", regprop(scan));
  1816. X#endif
  1817. X    while (scan != NULL) {
  1818. X#ifdef DEBUG
  1819. X    if (regnarrate)
  1820. X        fprintf(stderr, "%s...\n", regprop(scan));
  1821. X#endif
  1822. X    next = regnext(scan);
  1823. X
  1824. X    switch (OP(scan)) {
  1825. X    case BOL:
  1826. X        if (reginput != regbol)
  1827. X        return(0);
  1828. X        break;
  1829. X    case EOL:
  1830. X        if (*reginput != '\0')
  1831. X        return(0);
  1832. X        break;
  1833. X    case BWORD:
  1834. X    {
  1835. X        register int    c;
  1836. X
  1837. X        /*
  1838. X         * Test for beginning of word.
  1839. X         */
  1840. X        if (
  1841. X        (c = *reginput) == '\0'
  1842. X        ||
  1843. X        !inword(c)
  1844. X        ||
  1845. X        (
  1846. X            reginput != regbol
  1847. X            &&
  1848. X            inword(reginput[-1])
  1849. X        )
  1850. X        )
  1851. X        return 0;
  1852. X        break;
  1853. X    }
  1854. X    case EWORD:
  1855. X    {
  1856. X        register int    c;
  1857. X
  1858. X        /*
  1859. X         * Test for end of word.
  1860. X         */
  1861. X        if (
  1862. X        (
  1863. X            (c = *reginput) != '\0'
  1864. X            &&
  1865. X            inword(c)
  1866. X        )
  1867. X        ||
  1868. X        reginput == regbol
  1869. X        ||
  1870. X        !inword(reginput[-1])
  1871. X        )
  1872. X        return 0;
  1873. X        break;
  1874. X    }
  1875. X    case ANY:
  1876. X        if (*reginput == '\0')
  1877. X        return(0);
  1878. X        reginput++;
  1879. X        break;
  1880. X    case EXACTLY:
  1881. X    {
  1882. X        register int len;
  1883. X        register char *opnd;
  1884. X
  1885. X        opnd = OPERAND(scan);
  1886. X        /* Inline the first character, for speed. */
  1887. X        if (mkup(*opnd) != mkup(*reginput))
  1888. X        return(0);
  1889. X        len = strlen(opnd);
  1890. X        if (len > 1
  1891. X        && cstrncmp(opnd, reginput, len) != 0)
  1892. X        return(0);
  1893. X        reginput += len;
  1894. X        break;
  1895. X    }
  1896. X    case ANYOF:
  1897. X        if (*reginput == '\0'
  1898. X        || strchr(OPERAND(scan), *reginput) == NULL)
  1899. X        return(0);
  1900. X        reginput++;
  1901. X        break;
  1902. X    case ANYBUT:
  1903. X        if (*reginput == '\0'
  1904. X        || strchr(OPERAND(scan), *reginput) != NULL)
  1905. X        return(0);
  1906. X        reginput++;
  1907. X        break;
  1908. X    case NOTHING:
  1909. X        break;
  1910. X    case BACK:
  1911. X        break;
  1912. X    case OPEN+1:
  1913. X    case OPEN+2:
  1914. X    case OPEN+3:
  1915. X    case OPEN+4:
  1916. X    case OPEN+5:
  1917. X    case OPEN+6:
  1918. X    case OPEN+7:
  1919. X    case OPEN+8:
  1920. X    case OPEN+9:
  1921. X    {
  1922. X        register int no;
  1923. X        register char *save;
  1924. X
  1925. X        no = OP(scan) - OPEN;
  1926. X        save = reginput;
  1927. X
  1928. X        if (regmatch(next)) {
  1929. X        /*
  1930. X         * Don't set startp if some later
  1931. X         * invocation of the same parentheses
  1932. X         * already has.
  1933. X         */
  1934. X        if (regstartp[no] == NULL)
  1935. X            regstartp[no] = save;
  1936. X        return(1);
  1937. X        } else
  1938. X        return(0);
  1939. X        break;
  1940. X    }
  1941. X    case CLOSE+1:
  1942. X    case CLOSE+2:
  1943. X    case CLOSE+3:
  1944. X    case CLOSE+4:
  1945. X    case CLOSE+5:
  1946. X    case CLOSE+6:
  1947. X    case CLOSE+7:
  1948. X    case CLOSE+8:
  1949. X    case CLOSE+9:
  1950. X    {
  1951. X        register int no;
  1952. X        register char *save;
  1953. X
  1954. X        no = OP(scan) - CLOSE;
  1955. X        save = reginput;
  1956. X
  1957. X        if (regmatch(next)) {
  1958. X        /*
  1959. X         * Don't set endp if some later
  1960. X         * invocation of the same parentheses
  1961. X         * already has.
  1962. X         */
  1963. X        if (regendp[no] == NULL)
  1964. X            regendp[no] = save;
  1965. X        return(1);
  1966. X        } else
  1967. X        return(0);
  1968. X        break;
  1969. X    }
  1970. X    case BRANCH:
  1971. X    {
  1972. X        register char *save;
  1973. X
  1974. X        if (OP(next) != BRANCH)        /* No choice. */
  1975. X        next = OPERAND(scan);
  1976. X            /* Avoid recursion. */
  1977. X        else {
  1978. X        do {
  1979. X            save = reginput;
  1980. X            if (regmatch(OPERAND(scan)))
  1981. X            return(1);
  1982. X            reginput = save;
  1983. X            scan = regnext(scan);
  1984. X        } while (scan != NULL
  1985. X             && OP(scan) == BRANCH);
  1986. X        return(0);
  1987. X        /* NOTREACHED */
  1988. X        }
  1989. X        break;
  1990. X    }
  1991. X    case STAR:
  1992. X    case PLUS:
  1993. X    {
  1994. X        register char nextch;
  1995. X        register int no;
  1996. X        register char *save;
  1997. X        register int min;
  1998. X
  1999. X        /*
  2000. X         * Lookahead to avoid useless match attempts
  2001. X         * when we know what character comes next.
  2002. X         */
  2003. X        nextch = '\0';
  2004. X        if (OP(next) == EXACTLY)
  2005. X        nextch = *OPERAND(next);
  2006. X        min = (OP(scan) == STAR) ? 0 : 1;
  2007. X        save = reginput;
  2008. X        no = regrepeat(OPERAND(scan));
  2009. X        while (no >= min) {
  2010. X        /* If it could work, try it. */
  2011. X        if (nextch == '\0' || *reginput == nextch)
  2012. X            if (regmatch(next))
  2013. X            return(1);
  2014. X        /* Couldn't or didn't -- back up. */
  2015. X        no--;
  2016. X        reginput = save + no;
  2017. X        }
  2018. X        return(0);
  2019. X        break;
  2020. X    }
  2021. X    case END:
  2022. X        return(1);    /* Success! */
  2023. X        break;
  2024. X    default:
  2025. X        regerror("Memory corruption");
  2026. X        return(0);
  2027. X        break;
  2028. X    }
  2029. X
  2030. X    scan = next;
  2031. X    }
  2032. X
  2033. X    /*
  2034. X     * We get here only if there's trouble -- normally "case END" is
  2035. X     * the terminating point.
  2036. X     */
  2037. X    regerror("Corrupted pointers");
  2038. X    return(0);
  2039. X}
  2040. X
  2041. X/*
  2042. X - regrepeat - repeatedly match something simple, report how many
  2043. X */
  2044. Xstatic int
  2045. Xregrepeat(p)
  2046. Xchar *p;
  2047. X{
  2048. X    register int count = 0;
  2049. X    register char *scan;
  2050. X    register char *opnd;
  2051. X
  2052. X    scan = reginput;
  2053. X    opnd = OPERAND(p);
  2054. X    switch (OP(p)) {
  2055. X    case ANY:
  2056. X    count = strlen(scan);
  2057. X    scan += count;
  2058. X    break;
  2059. X    case EXACTLY:
  2060. X    while (mkup(*opnd) == mkup(*scan)) {
  2061. X        count++;
  2062. X        scan++;
  2063. X    }
  2064. X    break;
  2065. X    case ANYOF:
  2066. X    while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  2067. X        count++;
  2068. X        scan++;
  2069. X    }
  2070. X    break;
  2071. X    case ANYBUT:
  2072. X    while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  2073. X        count++;
  2074. X        scan++;
  2075. X    }
  2076. X    break;
  2077. X    default:        /* Oh dear.  Called inappropriately. */
  2078. X    regerror("Internal foulup");
  2079. X    count = 0;    /* Best compromise. */
  2080. X    break;
  2081. X    }
  2082. X    reginput = scan;
  2083. X
  2084. X    return(count);
  2085. X}
  2086. X
  2087. X/*
  2088. X - regnext - dig the "next" pointer out of a node
  2089. X */
  2090. Xstatic char *
  2091. Xregnext(p)
  2092. Xregister char *p;
  2093. X{
  2094. X    register int offset;
  2095. X
  2096. X    if (p == ®dummy)
  2097. X    return(NULL);
  2098. X
  2099. X    offset = NEXT(p);
  2100. X    if (offset == 0)
  2101. X    return(NULL);
  2102. X
  2103. X    if (OP(p) == BACK)
  2104. X    return(p-offset);
  2105. X    else
  2106. X    return(p+offset);
  2107. X}
  2108. X
  2109. X#ifdef DEBUG
  2110. X
  2111. XSTATIC char *regprop();
  2112. X
  2113. X/*
  2114. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  2115. X */
  2116. Xvoid
  2117. Xregdump(r)
  2118. Xregexp *r;
  2119. X{
  2120. X    register char *s;
  2121. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  2122. X    register char *next;
  2123. X    extern char *strchr();
  2124. X
  2125. X
  2126. X    s = r->program + 1;
  2127. X    while (op != END) {    /* While that wasn't END last time... */
  2128. X    op = OP(s);
  2129. X    printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  2130. X    next = regnext(s);
  2131. X    if (next == NULL)        /* Next ptr. */
  2132. X        printf("(0)");
  2133. X    else
  2134. X        printf("(%d)", (s-r->program)+(next-s));
  2135. X    s += 3;
  2136. X    if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  2137. X        /* Literal string, where present. */
  2138. X        while (*s != '\0') {
  2139. X        putchar(*s);
  2140. X        s++;
  2141. X        }
  2142. X        s++;
  2143. X    }
  2144. X    putchar('\n');
  2145. X    }
  2146. X
  2147. X    /* Header fields of interest. */
  2148. X    if (r->regstart != '\0')
  2149. X    printf("start `%c' ", r->regstart);
  2150. X    if (r->reganch)
  2151. X    printf("anchored ");
  2152. X    if (r->regmust != NULL)
  2153. X    printf("must have \"%s\"", r->regmust);
  2154. X    printf("\n");
  2155. X}
  2156. X
  2157. X/*
  2158. X - regprop - printable representation of opcode
  2159. X */
  2160. Xstatic char *
  2161. Xregprop(op)
  2162. Xchar *op;
  2163. X{
  2164. X    register char *p;
  2165. X    static char buf[50];
  2166. X
  2167. X    (void) strcpy(buf, ":");
  2168. X
  2169. X    switch (OP(op)) {
  2170. X    case BOL:
  2171. X    p = "BOL";
  2172. X    break;
  2173. X    case EOL:
  2174. X    p = "EOL";
  2175. X    break;
  2176. X    case ANY:
  2177. X    p = "ANY";
  2178. X    break;
  2179. X    case ANYOF:
  2180. X    p = "ANYOF";
  2181. X    break;
  2182. X    case ANYBUT:
  2183. X    p = "ANYBUT";
  2184. X    break;
  2185. X    case BRANCH:
  2186. X    p = "BRANCH";
  2187. X    break;
  2188. X    case EXACTLY:
  2189. X    p = "EXACTLY";
  2190. X    break;
  2191. X    case NOTHING:
  2192. X    p = "NOTHING";
  2193. X    break;
  2194. X    case BACK:
  2195. X    p = "BACK";
  2196. X    break;
  2197. X    case END:
  2198. X    p = "END";
  2199. X    break;
  2200. X    case OPEN+1:
  2201. X    case OPEN+2:
  2202. X    case OPEN+3:
  2203. X    case OPEN+4:
  2204. X    case OPEN+5:
  2205. X    case OPEN+6:
  2206. X    case OPEN+7:
  2207. X    case OPEN+8:
  2208. X    case OPEN+9:
  2209. X    sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  2210. X    p = NULL;
  2211. X    break;
  2212. X    case CLOSE+1:
  2213. X    case CLOSE+2:
  2214. X    case CLOSE+3:
  2215. X    case CLOSE+4:
  2216. X    case CLOSE+5:
  2217. X    case CLOSE+6:
  2218. X    case CLOSE+7:
  2219. X    case CLOSE+8:
  2220. X    case CLOSE+9:
  2221. X    sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  2222. X    p = NULL;
  2223. X    break;
  2224. X    case STAR:
  2225. X    p = "STAR";
  2226. X    break;
  2227. X    case PLUS:
  2228. X    p = "PLUS";
  2229. X    break;
  2230. X    default:
  2231. X    regerror("Corrupted opcode");
  2232. X    break;
  2233. X    }
  2234. X    if (p != NULL)
  2235. X    (void) strcat(buf, p);
  2236. X    return(buf);
  2237. X}
  2238. X#endif
  2239. X
  2240. X/*
  2241. X * The following is provided for those people who do not have strcspn() in
  2242. X * their C libraries.  They should get off their butts and do something
  2243. X * about it; at least one public-domain implementation of those (highly
  2244. X * useful) string routines has been published on Usenet.
  2245. X */
  2246. X#ifdef STRCSPN
  2247. X/*
  2248. X * strcspn - find length of initial segment of s1 consisting entirely
  2249. X * of characters not from s2
  2250. X */
  2251. X
  2252. Xstatic int
  2253. Xstrcspn(s1, s2)
  2254. Xchar *s1;
  2255. Xchar *s2;
  2256. X{
  2257. X    register char *scan1;
  2258. X    register char *scan2;
  2259. X    register int count;
  2260. X
  2261. X    count = 0;
  2262. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  2263. X    for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  2264. X        if (*scan1 == *scan2++)
  2265. X        return(count);
  2266. X    count++;
  2267. X    }
  2268. X    return(count);
  2269. X}
  2270. X#endif
  2271. X
  2272. Xint
  2273. Xcstrncmp(s1, s2, n)
  2274. Xregister char    *s1, *s2;
  2275. Xregister int    n;
  2276. X{
  2277. X    if (!Pb(P_ignorecase)) {
  2278. X    return(strncmp(s1, s2, n));
  2279. X    }
  2280. X
  2281. X    while (
  2282. X        n > 0
  2283. X        &&
  2284. X        *s1 != '\0'
  2285. X        &&
  2286. X        *s2 != '\0'
  2287. X        &&
  2288. X        mkup(*s1) == mkup(*s2)
  2289. X    ) {
  2290. X    s1++;
  2291. X    s2++;
  2292. X    n--;
  2293. X    }
  2294. X    if (n == 0) {
  2295. X    return(0);
  2296. X    } else {
  2297. X    return(mkup(*s1) - mkup(*s2));
  2298. X    }
  2299. X}
  2300. X
  2301. Xchar *
  2302. Xcstrchr(s, c)
  2303. Xchar    *s;
  2304. Xint    c;
  2305. X{
  2306. X    register char    *p;
  2307. X    register int    uc;
  2308. X
  2309. X    uc = mkup(c);
  2310. X    for (p = s; *p != '\0'; p++) {
  2311. X    if (mkup(*p) == uc)
  2312. X        return(p);
  2313. X    }
  2314. X    return(NULL);
  2315. X}
  2316. END_OF_FILE
  2317.   if test 32150 -ne `wc -c <'xvi/src/regexp.c'`; then
  2318.     echo shar: \"'xvi/src/regexp.c'\" unpacked with wrong size!
  2319.   fi
  2320.   # end of 'xvi/src/regexp.c'
  2321. fi
  2322. echo shar: End of archive 7 \(of 18\).
  2323. cp /dev/null ark7isdone
  2324. MISSING=""
  2325. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
  2326.     if test ! -f ark${I}isdone ; then
  2327.     MISSING="${MISSING} ${I}"
  2328.     fi
  2329. done
  2330. if test "${MISSING}" = "" ; then
  2331.     echo You have unpacked all 18 archives.
  2332.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2333. else
  2334.     echo You still must unpack the following archives:
  2335.     echo "        " ${MISSING}
  2336. fi
  2337. exit 0
  2338. exit 0 # Just in case...
  2339.