home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / stevie.zoo / stevie.5 < prev    next >
Encoding:
Text File  |  1990-03-14  |  59.5 KB  |  2,587 lines

  1.  
  2. : This is a shar archive.  Extract with sh, not csh.
  3. : The rest of this file will extract:
  4. : search.c sentence.c tagcmd.c term.c undo.c version.c tos.c
  5. echo extracting - search.c
  6. sed 's/^X//' > search.c << '!EOR!'
  7. X/* $Header: /nw/tony/src/stevie/src/RCS/search.c,v 1.16 89/08/06 09:50:51 tony Exp $
  8. X *
  9. X * This file contains various searching-related routines. These fall into
  10. X * three groups: string searches (for /, ?, n, and N), character searches
  11. X * within a single line (for f, F, t, T, etc), and "other" kinds of searches
  12. X * like the '%' command, and 'word' searches.
  13. X */
  14. X
  15. X#include "stevie.h"
  16. X#include "regexp.h"    /* Henry Spencer's (modified) reg. exp. routines */
  17. X
  18. X/*
  19. X * String searches
  20. X *
  21. X * The actual searches are done using Henry Spencer's regular expression
  22. X * library.
  23. X */
  24. X
  25. X#define    BEGWORD    "([^a-zA-Z0-9_]|^)"    /* replaces "\<" in search strings */
  26. X#define    ENDWORD    "([^a-zA-Z0-9_]|$)"    /* likewise replaces "\>" */
  27. X
  28. X#define    BEGCHAR(c)    (islower(c) || isupper(c) || isdigit(c) || ((c) == '_'))
  29. X
  30. Xbool_t    begword;    /* does the search include a 'begin word' match */
  31. X
  32. X/*
  33. X * mapstring(s) - map special backslash sequences
  34. X */
  35. Xstatic char *
  36. Xmapstring(s)
  37. Xregister char    *s;
  38. X{
  39. X    static    char    ns[80];
  40. X    register char    *p;
  41. X
  42. X    begword = FALSE;
  43. X
  44. X    for (p = ns; *s ;s++) {
  45. X        if (*s != '\\') {    /* not an escape */
  46. X            *p++ = *s;
  47. X            continue;
  48. X        }
  49. X        switch (*++s) {
  50. X        case '/':
  51. X            *p++ = '/';
  52. X            break;
  53. X
  54. X        case '<':
  55. X            strcpy(p, BEGWORD);
  56. X            p += strlen(BEGWORD);
  57. X            begword = TRUE;
  58. X            break;
  59. X
  60. X        case '>':
  61. X            strcpy(p, ENDWORD);
  62. X            p += strlen(ENDWORD);
  63. X            break;
  64. X
  65. X        default:
  66. X            *p++ = '\\';
  67. X            *p++ = *s;
  68. X            break;
  69. X        }
  70. X    }
  71. X    *p++ = NUL;
  72. X
  73. X    return ns;
  74. X}
  75. X
  76. Xstatic char *laststr = NULL;
  77. Xstatic int lastsdir;
  78. X
  79. Xstatic LPTR *
  80. Xssearch(dir,str)
  81. Xint    dir;    /* FORWARD or BACKWARD */
  82. Xchar    *str;
  83. X{
  84. X    LPTR    *bcksearch(), *fwdsearch();
  85. X    LPTR    *pos;
  86. X    char    *old_ls = laststr;
  87. X
  88. X    reg_ic = P(P_IC);    /* tell the regexp routines how to search */
  89. X
  90. X    laststr = strsave(str);
  91. X    lastsdir = dir;
  92. X
  93. X    if (old_ls != NULL)
  94. X        free(old_ls);
  95. X
  96. X    if (dir == BACKWARD) {
  97. X        smsg("?%s", laststr);
  98. X        pos = bcksearch(mapstring(laststr));
  99. X    } else {
  100. X        smsg("/%s", laststr);
  101. X        pos = fwdsearch(mapstring(laststr));
  102. X    }
  103. X
  104. X    /*
  105. X     * This is kind of a kludge, but its needed to make
  106. X     * 'beginning of word' searches land on the right place.
  107. X     */
  108. X    if (pos != NULL && begword) {
  109. X        if (pos->index != 0 || !BEGCHAR(pos->linep->s[0]))
  110. X            pos->index += 1;
  111. X    }
  112. X    return pos;
  113. X}
  114. X
  115. Xbool_t
  116. Xdosearch(dir,str)
  117. Xint    dir;
  118. Xchar    *str;
  119. X{
  120. X    LPTR    *p;
  121. X
  122. X    if (str == NULL)
  123. X        str = laststr;
  124. X
  125. X    got_int = FALSE;
  126. X
  127. X    if ((p = ssearch(dir,str)) == NULL) {
  128. X        if (got_int)
  129. X            msg("Interrupt");
  130. X        else
  131. X            msg("Pattern not found");
  132. X
  133. X        got_int = FALSE;
  134. X        return FALSE;
  135. X    } else {
  136. X        LPTR savep;
  137. X
  138. X        cursupdate();
  139. X        /*
  140. X         * if we're backing up, we make sure the line we're on
  141. X         * is on the screen.
  142. X         */
  143. X        setpcmark();
  144. X        *Curschar = savep = *p;
  145. X        set_want_col = TRUE;
  146. X        cursupdate();
  147. X
  148. X        return TRUE;
  149. X    }
  150. X}
  151. X
  152. X#define    OTHERDIR(x)    (((x) == FORWARD) ? BACKWARD : FORWARD)
  153. X
  154. Xbool_t
  155. Xrepsearch(flag)
  156. Xint    flag;
  157. X{
  158. X    int    dir = lastsdir;
  159. X    bool_t    found;
  160. X
  161. X    if ( laststr == NULL ) {
  162. X        beep();
  163. X        return FALSE;
  164. X    }
  165. X
  166. X    found = dosearch(flag ? OTHERDIR(lastsdir) : lastsdir, laststr);
  167. X
  168. X    /*
  169. X     * We have to save and restore 'lastsdir' because it gets munged
  170. X     * by ssearch() and winds up saving the wrong direction from here
  171. X     * if 'flag' is true.
  172. X     */
  173. X    lastsdir = dir;
  174. X
  175. X    return found;
  176. X}
  177. X
  178. X/*
  179. X * regerror - called by regexp routines when errors are detected.
  180. X */
  181. Xvoid
  182. Xregerror(s)
  183. Xchar    *s;
  184. X{
  185. X    emsg(s);
  186. X}
  187. X
  188. Xstatic LPTR *
  189. Xfwdsearch(str)
  190. Xregister char    *str;
  191. X{
  192. X    static LPTR    infile;
  193. X    register LPTR    *p;
  194. X    regexp    *prog;
  195. X
  196. X    register char    *s;
  197. X    register int    i;
  198. X
  199. X    if ((prog = regcomp(str)) == NULL) {
  200. X        emsg("Invalid search string");
  201. X        return NULL;
  202. X    }
  203. X
  204. X    p = Curschar;
  205. X    i = Curschar->index + 1;
  206. X    do {
  207. X        s = p->linep->s + i;
  208. X
  209. X        if (regexec(prog, s, i == 0)) {        /* got a match */
  210. X            infile.linep = p->linep;
  211. X            infile.index = (int) (prog->startp[0] - p->linep->s);
  212. X            free((char *)prog);
  213. X            return (&infile);
  214. X        }
  215. X        i = 0;
  216. X
  217. X        if (got_int)
  218. X            goto fwdfail;
  219. X
  220. X    } while ((p = nextline(p)) != NULL);
  221. X
  222. X    /*
  223. X     * If wrapscan isn't set, then don't scan from the beginning
  224. X     * of the file. Just return failure here.
  225. X     */
  226. X    if (!P(P_WS))
  227. X        goto fwdfail;
  228. X
  229. X    /* search from the beginning of the file to Curschar */
  230. X    for (p = Filemem; p != NULL ;p = nextline(p)) {
  231. X        s = p->linep->s;
  232. X
  233. X        if (regexec(prog, s, TRUE)) {        /* got a match */
  234. X            infile.linep = p->linep;
  235. X            infile.index = (int) (prog->startp[0] - s);
  236. X            free((char *)prog);
  237. X            return (&infile);
  238. X        }
  239. X
  240. X        if (p->linep == Curschar->linep)
  241. X            break;
  242. X
  243. X        if (got_int)
  244. X            goto fwdfail;
  245. X    }
  246. X
  247. Xfwdfail:
  248. X    free((char *)prog);
  249. X    return NULL;
  250. X}
  251. X
  252. Xstatic LPTR *
  253. Xbcksearch(str)
  254. Xchar    *str;
  255. X{
  256. X    static LPTR    infile;
  257. X    register LPTR    *p = &infile;
  258. X    register char    *s;
  259. X    register int    i;
  260. X    register char    *match;
  261. X    regexp    *prog;
  262. X
  263. X    /* make sure str isn't empty */
  264. X    if (str == NULL || *str == NUL)
  265. X        return NULL;
  266. X
  267. X    if ((prog = regcomp(str)) == NULL) {
  268. X        emsg("Invalid search string");
  269. X        return NULL;
  270. X    }
  271. X
  272. X    *p = *Curschar;
  273. X    if (dec(p) == -1) {    /* already at start of file? */
  274. X        *p = *Fileend;
  275. X        p->index = strlen(p->linep->s) - 1;
  276. X    }
  277. X
  278. X    if (begword)        /* so we don't get stuck on one match */
  279. X        dec(p);
  280. X
  281. X    i = p->index;
  282. X
  283. X    do {
  284. X        s = p->linep->s;
  285. X
  286. X        if (regexec(prog, s, TRUE)) {    /* match somewhere on line */
  287. X
  288. X            /*
  289. X             * Now, if there are multiple matches on this line,
  290. X             * we have to get the last one. Or the last one
  291. X             * before the cursor, if we're on that line.
  292. X             */
  293. X            match = prog->startp[0];
  294. X
  295. X            while (regexec(prog, prog->endp[0], FALSE)) {
  296. X                if ((i >= 0) && ((prog->startp[0] - s) > i))
  297. X                    break;
  298. X                match = prog->startp[0];
  299. X            }
  300. X
  301. X            if ((i >= 0) && ((match - s) > i)) {
  302. X                i = -1;
  303. X                continue;
  304. X            }
  305. X
  306. X            infile.linep = p->linep;
  307. X            infile.index = (int) (match - s);
  308. X            free((char *)prog);
  309. X            return (&infile);
  310. X        }
  311. X        i = -1;
  312. X
  313. X        if (got_int)
  314. X            goto bckfail;
  315. X
  316. X    } while ((p = prevline(p)) != NULL);
  317. X
  318. X    /*
  319. X     * If wrapscan isn't set, bag the search now
  320. X     */
  321. X    if (!P(P_WS))
  322. X        goto bckfail;
  323. X
  324. X    /* search backward from the end of the file */
  325. X    p = prevline(Fileend);
  326. X    do {
  327. X        s = p->linep->s;
  328. X
  329. X        if (regexec(prog, s, TRUE)) {    /* match somewhere on line */
  330. X
  331. X            /*
  332. X             * Now, if there are multiple matches on this line,
  333. X             * we have to get the last one.
  334. X             */
  335. X            match = prog->startp[0];
  336. X
  337. X            while (regexec(prog, prog->endp[0], FALSE))
  338. X                match = prog->startp[0];
  339. X
  340. X            infile.linep = p->linep;
  341. X            infile.index = (int) (match - s);
  342. X            free((char *)prog);
  343. X            return (&infile);
  344. X        }
  345. X
  346. X        if (p->linep == Curschar->linep)
  347. X            break;
  348. X
  349. X        if (got_int)
  350. X            goto bckfail;
  351. X
  352. X    } while ((p = prevline(p)) != NULL);
  353. X
  354. Xbckfail:
  355. X    free((char *)prog);
  356. X    return NULL;
  357. X}
  358. X
  359. X/*
  360. X * dosub(lp, up, cmd)
  361. X *
  362. X * Perform a substitution from line 'lp' to line 'up' using the
  363. X * command pointed to by 'cmd' which should be of the form:
  364. X *
  365. X * /pattern/substitution/g
  366. X *
  367. X * The trailing 'g' is optional and, if present, indicates that multiple
  368. X * substitutions should be performed on each line, if applicable.
  369. X * The usual escapes are supported as described in the regexp docs.
  370. X */
  371. Xvoid
  372. Xdosub(lp, up, cmd)
  373. XLPTR    *lp, *up;
  374. Xchar    *cmd;
  375. X{
  376. X    LINE    *cp;
  377. X    char    *pat, *sub;
  378. X    regexp    *prog;
  379. X    int    nsubs;
  380. X    bool_t    do_all;        /* do multiple substitutions per line */
  381. X
  382. X    /*
  383. X     * If no range was given, do the current line. If only one line
  384. X     * was given, just do that one.
  385. X     */
  386. X    if (lp->linep == NULL)
  387. X        *up = *lp = *Curschar;
  388. X    else {
  389. X        if (up->linep == NULL)
  390. X            *up = *lp;
  391. X    }
  392. X
  393. X    pat = ++cmd;        /* skip the initial '/' */
  394. X
  395. X    while (*cmd) {
  396. X        if (*cmd == '\\')    /* next char is quoted */
  397. X            cmd += 2;
  398. X        else if (*cmd == '/') {    /* delimiter */
  399. X            *cmd++ = NUL;
  400. X            break;
  401. X        } else
  402. X            cmd++;        /* regular character */
  403. X    }
  404. X
  405. X    if (*pat == NUL) {
  406. X        emsg("NULL pattern specified");
  407. X        return;
  408. X    }
  409. X
  410. X    sub = cmd;
  411. X
  412. X    do_all = FALSE;
  413. X
  414. X    while (*cmd) {
  415. X        if (*cmd == '\\')    /* next char is quoted */
  416. X            cmd += 2;
  417. X        else if (*cmd == '/') {    /* delimiter */
  418. X            do_all = (cmd[1] == 'g');
  419. X            *cmd++ = NUL;
  420. X            break;
  421. X        } else
  422. X            cmd++;        /* regular character */
  423. X    }
  424. X
  425. X    reg_ic = P(P_IC);    /* set "ignore case" flag appropriately */
  426. X
  427. X    if ((prog = regcomp(pat)) == NULL) {
  428. X        emsg("Invalid search string");
  429. X        return;
  430. X    }
  431. X
  432. X    nsubs = 0;
  433. X
  434. X    for (cp = lp->linep; cp != NULL ;cp = cp->next) {
  435. X        if (regexec(prog, cp->s, TRUE)) { /* a match on this line */
  436. X            char    *ns, *sns, *p;
  437. X
  438. X            /*
  439. X             * Get some space for a temporary buffer
  440. X             * to do the substitution into.
  441. X             */
  442. X            sns = ns = alloc(2048);
  443. X            if (!sns)  return;
  444. X            *sns = NUL;
  445. X
  446. X            p = cp->s;
  447. X
  448. X            do {
  449. X                for (ns = sns; *ns ;ns++)
  450. X                    ;
  451. X                /*
  452. X                 * copy up to the part that matched
  453. X                 */
  454. X                while (p < prog->startp[0])
  455. X                    *ns++ = *p++;
  456. X
  457. X                regsub(prog, sub, ns);
  458. X
  459. X                /*
  460. X                 * continue searching after the match
  461. X                 */
  462. X                p = prog->endp[0];
  463. X
  464. X            } while (regexec(prog, p, FALSE) && do_all);
  465. X
  466. X            for (ns = sns; *ns ;ns++)
  467. X                ;
  468. X
  469. X            /*
  470. X             * copy the rest of the line, that didn't match
  471. X             */
  472. X            while (*p)
  473. X                *ns++ = *p++;
  474. X
  475. X            *ns = NUL;
  476. X
  477. X            free(cp->s);        /* free the original line */
  478. X            cp->s = strsave(sns);    /* and save the modified str */
  479. X            cp->size = strlen(cp->s) + 1;
  480. X            free(sns);        /* free the temp buffer */
  481. X            nsubs++;
  482. X            CHANGED;
  483. X        }
  484. X        if (cp == up->linep)
  485. X            break;
  486. X    }
  487. X
  488. X    if (nsubs) {
  489. X        updatescreen();
  490. X        if (nsubs >= P(P_RP))
  491. X            smsg("%d substitution%c", nsubs, (nsubs>1) ? 's' : ' ');
  492. X    } else
  493. X        msg("No match");
  494. X
  495. X    free((char *)prog);
  496. X}
  497. X
  498. X/*
  499. X * doglob(cmd)
  500. X *
  501. X * Execute a global command of the form:
  502. X *
  503. X * g/pattern/X
  504. X *
  505. X * where 'x' is a command character, currently one of the following:
  506. X *
  507. X * d    Delete all matching lines
  508. X * p    Print all matching lines
  509. X *
  510. X * The command character (as well as the trailing slash) is optional, and
  511. X * is assumed to be 'p' if missing.
  512. X */
  513. Xvoid
  514. Xdoglob(lp, up, cmd)
  515. XLPTR    *lp, *up;
  516. Xchar    *cmd;
  517. X{
  518. X    LINE    *cp;
  519. X    char    *pat;
  520. X    regexp    *prog;
  521. X    int    ndone;
  522. X    char    cmdchar = NUL;    /* what to do with matching lines */
  523. X
  524. X    /*
  525. X     * If no range was given, do every line. If only one line
  526. X     * was given, just do that one.
  527. X     */
  528. X    if (lp->linep == NULL) {
  529. X        *lp = *Filemem;
  530. X        *up = *Fileend;
  531. X    } else {
  532. X        if (up->linep == NULL)
  533. X            *up = *lp;
  534. X    }
  535. X
  536. X    pat = ++cmd;        /* skip the initial '/' */
  537. X
  538. X    while (*cmd) {
  539. X        if (*cmd == '\\')    /* next char is quoted */
  540. X            cmd += 2;
  541. X        else if (*cmd == '/') {    /* delimiter */
  542. X            cmdchar = cmd[1];
  543. X            *cmd++ = NUL;
  544. X            break;
  545. X        } else
  546. X            cmd++;        /* regular character */
  547. X    }
  548. X    if (cmdchar == NUL)
  549. X        cmdchar = 'p';
  550. X
  551. X    reg_ic = P(P_IC);    /* set "ignore case" flag appropriately */
  552. X
  553. X    if (cmdchar != 'd' && cmdchar != 'p') {
  554. X        emsg("Invalid command character");
  555. X        return;
  556. X    }
  557. X
  558. X    if ((prog = regcomp(pat)) == NULL) {
  559. X        emsg("Invalid search string");
  560. X        return;
  561. X    }
  562. X
  563. X    msg("");
  564. X    ndone = 0;
  565. X    got_int = FALSE;
  566. X
  567. X    for (cp = lp->linep; cp != NULL && !got_int ;cp = cp->next) {
  568. X        if (regexec(prog, cp->s, TRUE)) { /* a match on this line */
  569. X            switch (cmdchar) {
  570. X
  571. X            case 'd':        /* delete the line */
  572. X                if (Curschar->linep != cp) {
  573. X                    LPTR    savep;
  574. X
  575. X                    savep = *Curschar;
  576. X                    Curschar->linep = cp;
  577. X                    Curschar->index = 0;
  578. X                    delline(1, FALSE);
  579. X                    *Curschar = savep;
  580. X                } else
  581. X                    delline(1, FALSE);
  582. X                break;
  583. X
  584. X            case 'p':        /* print the line */
  585. X                prt_line(cp->s);
  586. X                outstr("\r\n");
  587. X                break;
  588. X            }
  589. X            ndone++;
  590. X        }
  591. X        if (cp == up->linep)
  592. X            break;
  593. X    }
  594. X
  595. X    if (ndone) {
  596. X        switch (cmdchar) {
  597. X
  598. X        case 'd':
  599. X            updatescreen();
  600. X            if (ndone >= P(P_RP) || got_int)
  601. X                smsg("%s%d fewer line%c",
  602. X                    got_int ? "Interrupt: " : "",
  603. X                    ndone,
  604. X                    (ndone > 1) ? 's' : ' ');
  605. X            break;
  606. X
  607. X        case 'p':
  608. X            wait_return();
  609. X            break;
  610. X        }
  611. X    } else {
  612. X        if (got_int)
  613. X            msg("Interrupt");
  614. X        else
  615. X            msg("No match");
  616. X    }
  617. X
  618. X    got_int = FALSE;
  619. X    free((char *)prog);
  620. X}
  621. X
  622. X/*
  623. X * Character Searches
  624. X */
  625. X
  626. Xstatic char lastc = NUL;    /* last character searched for */
  627. Xstatic int  lastcdir;        /* last direction of character search */
  628. Xstatic int  lastctype;        /* last type of search ("find" or "to") */
  629. X
  630. X/*
  631. X * searchc(c, dir, type)
  632. X *
  633. X * Search for character 'c', in direction 'dir'. If type is 0, move to
  634. X * the position of the character, otherwise move to just before the char.
  635. X */
  636. Xbool_t
  637. Xsearchc(c, dir, type)
  638. Xchar    c;
  639. Xint    dir;
  640. Xint    type;
  641. X{
  642. X    LPTR    save;
  643. X
  644. X    save = *Curschar;    /* save position in case we fail */
  645. X    lastc = c;
  646. X    lastcdir = dir;
  647. X    lastctype = type;
  648. X
  649. X    /*
  650. X     * On 'to' searches, skip one to start with so we can repeat
  651. X     * searches in the same direction and have it work right.
  652. X     */
  653. X    if (type)
  654. X        (dir == FORWARD) ? oneright() : oneleft();
  655. X
  656. X    while ( (dir == FORWARD) ? oneright() : oneleft() ) {
  657. X        if (gchar(Curschar) == c) {
  658. X            if (type)
  659. X                (dir == FORWARD) ? oneleft() : oneright();
  660. X            return TRUE;
  661. X        }
  662. X    }
  663. X    *Curschar = save;
  664. X    return FALSE;
  665. X}
  666. X
  667. Xbool_t
  668. Xcrepsearch(flag)
  669. Xint    flag;
  670. X{
  671. X    int    dir = lastcdir;
  672. X    int    rval;
  673. X
  674. X    if (lastc == NUL)
  675. X        return FALSE;
  676. X
  677. X    rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype);
  678. X
  679. X    lastcdir = dir;        /* restore dir., since it may have changed */
  680. X
  681. X    return rval;
  682. X}
  683. X
  684. X/*
  685. X * "Other" Searches
  686. X */
  687. X
  688. X/*
  689. X * showmatch - move the cursor to the matching paren or brace
  690. X */
  691. XLPTR *
  692. Xshowmatch()
  693. X{
  694. X    static    LPTR    pos;
  695. X    int    (*move)(), inc(), dec();
  696. X    char    initc = gchar(Curschar);    /* initial char */
  697. X    char    findc;                /* terminating char */
  698. X    char    c;
  699. X    int    count = 0;
  700. X
  701. X    pos = *Curschar;        /* set starting point */
  702. X
  703. X    switch (initc) {
  704. X
  705. X    case '(':
  706. X        findc = ')';
  707. X        move = inc;
  708. X        break;
  709. X    case ')':
  710. X        findc = '(';
  711. X        move = dec;
  712. X        break;
  713. X    case '{':
  714. X        findc = '}';
  715. X        move = inc;
  716. X        break;
  717. X    case '}':
  718. X        findc = '{';
  719. X        move = dec;
  720. X        break;
  721. X    case '[':
  722. X        findc = ']';
  723. X        move = inc;
  724. X        break;
  725. X    case ']':
  726. X        findc = '[';
  727. X        move = dec;
  728. X        break;
  729. X    default:
  730. X        return (LPTR *) NULL;
  731. X    }
  732. X
  733. X    while ((*move)(&pos) != -1) {        /* until end of file */
  734. X        c = gchar(&pos);
  735. X        if (c == initc)
  736. X            count++;
  737. X        else if (c == findc) {
  738. X            if (count == 0)
  739. X                return &pos;
  740. X            count--;
  741. X        }
  742. X    }
  743. X    return (LPTR *) NULL;            /* never found it */
  744. X}
  745. X
  746. X
  747. X/*
  748. X * The following routines do the word searches performed by the
  749. X * 'w', 'W', 'b', 'B', 'e', and 'E' commands.
  750. X */
  751. X
  752. X/*
  753. X * To perform these searches, characters are placed into one of three
  754. X * classes, and transitions between classes determine word boundaries.
  755. X *
  756. X * The classes are:
  757. X *
  758. X * 0 - white space
  759. X * 1 - letters, digits, and underscore
  760. X * 2 - everything else
  761. X */
  762. X
  763. Xstatic    int    stype;        /* type of the word motion being performed */
  764. X
  765. X#define    C0(c)    (((c) == ' ') || ((c) == '\t') || ((c) == NUL))
  766. X#define    C1(c)    (isalpha(c) || isdigit(c) || ((c) == '_'))
  767. X
  768. X/*
  769. X * cls(c) - returns the class of character 'c'
  770. X *
  771. X * The 'type' of the current search modifies the classes of characters
  772. X * if a 'W', 'B', or 'E' motion is being done. In this case, chars. from
  773. X * class 2 are reported as class 1 since only white space boundaries are
  774. X * of interest.
  775. X */
  776. Xstatic    int
  777. Xcls(c)
  778. Xchar    c;
  779. X{
  780. X    if (C0(c))
  781. X        return 0;
  782. X
  783. X    if (C1(c))
  784. X        return 1;
  785. X
  786. X    /*
  787. X     * If stype is non-zero, report these as class 1.
  788. X     */
  789. X    return (stype == 0) ? 2 : 1;
  790. X}
  791. X
  792. X
  793. X/*
  794. X * fwd_word(pos, type) - move forward one word
  795. X *
  796. X * Returns the resulting position, or NULL if EOF was reached.
  797. X */
  798. XLPTR *
  799. Xfwd_word(p, type)
  800. XLPTR    *p;
  801. Xint    type;
  802. X{
  803. X    static    LPTR    pos;
  804. X    int    sclass = cls(gchar(p));        /* starting class */
  805. X
  806. X    pos = *p;
  807. X
  808. X    stype = type;
  809. X
  810. X    /*
  811. X     * We always move at least one character.
  812. X     */
  813. X    if (inc(&pos) == -1)
  814. X        return NULL;
  815. X
  816. X    if (sclass != 0) {
  817. X        while (cls(gchar(&pos)) == sclass) {
  818. X            if (inc(&pos) == -1)
  819. X                return NULL;
  820. X        }
  821. X        /*
  822. X         * If we went from 1 -> 2 or 2 -> 1, return here.
  823. X         */
  824. X        if (cls(gchar(&pos)) != 0)
  825. X            return &pos;
  826. X    }
  827. X
  828. X    /* We're in white space; go to next non-white */
  829. X
  830. X    while (cls(gchar(&pos)) == 0) {
  831. X        /*
  832. X         * We'll stop if we land on a blank line
  833. X         */
  834. X        if (pos.index == 0 && pos.linep->s[0] == NUL)
  835. X            break;
  836. X
  837. X        if (inc(&pos) == -1)
  838. X            return NULL;
  839. X    }
  840. X
  841. X    return &pos;
  842. X}
  843. X
  844. X/*
  845. X * bck_word(pos, type) - move backward one word
  846. X *
  847. X * Returns the resulting position, or NULL if EOF was reached.
  848. X */
  849. XLPTR *
  850. Xbck_word(p, type)
  851. XLPTR    *p;
  852. Xint    type;
  853. X{
  854. X    static    LPTR    pos;
  855. X    int    sclass = cls(gchar(p));        /* starting class */
  856. X
  857. X    pos = *p;
  858. X
  859. X    stype = type;
  860. X
  861. X    if (dec(&pos) == -1)
  862. X        return NULL;
  863. X
  864. X    /*
  865. X     * If we're in the middle of a word, we just have to
  866. X     * back up to the start of it.
  867. X     */
  868. X    if (cls(gchar(&pos)) == sclass && sclass != 0) {
  869. X        /*
  870. X         * Move backward to start of the current word
  871. X         */
  872. X        while (cls(gchar(&pos)) == sclass) {
  873. X            if (dec(&pos) == -1)
  874. X                return NULL;
  875. X        }
  876. X        inc(&pos);            /* overshot - forward one */
  877. X        return &pos;
  878. X    }
  879. X
  880. X    /*
  881. X     * We were at the start of a word. Go back to the start
  882. X     * of the prior word.
  883. X     */
  884. X
  885. X    while (cls(gchar(&pos)) == 0) {        /* skip any white space */
  886. X        /*
  887. X         * We'll stop if we land on a blank line
  888. X         */
  889. X        if (pos.index == 0 && pos.linep->s[0] == NUL)
  890. X            return &pos;
  891. X
  892. X        if (dec(&pos) == -1)
  893. X            return NULL;
  894. X    }
  895. X
  896. X    sclass = cls(gchar(&pos));
  897. X
  898. X    /*
  899. X     * Move backward to start of this word.
  900. X     */
  901. X    while (cls(gchar(&pos)) == sclass) {
  902. X        if (dec(&pos) == -1)
  903. X            return NULL;
  904. X    }
  905. X    inc(&pos);            /* overshot - forward one */
  906. X
  907. X    return &pos;
  908. X}
  909. X
  910. X/*
  911. X * end_word(pos, type, in_change) - move to the end of the word
  912. X *
  913. X * There is an apparent bug in the 'e' motion of the real vi. At least
  914. X * on the System V Release 3 version for the 80386. Unlike 'b' and 'w',
  915. X * the 'e' motion crosses blank lines. When the real vi crosses a blank
  916. X * line in an 'e' motion, the cursor is placed on the FIRST character
  917. X * of the next non-blank line. The 'E' command, however, works correctly.
  918. X * Since this appears to be a bug, I have not duplicated it here.
  919. X *
  920. X * There's a strange special case here that the 'in_change' parameter
  921. X * helps us deal with. Vi effectively turns 'cw' into 'ce'. If we're on
  922. X * a word with only one character, we need to stick at the current
  923. X * position so we don't change two words.
  924. X *
  925. X * Returns the resulting position, or NULL if EOF was reached.
  926. X */
  927. XLPTR *
  928. Xend_word(p, type, in_change)
  929. XLPTR    *p;
  930. Xint    type;
  931. Xbool_t    in_change;
  932. X{
  933. X    static    LPTR    pos;
  934. X    int    sclass = cls(gchar(p));        /* starting class */
  935. X
  936. X    pos = *p;
  937. X
  938. X    stype = type;
  939. X
  940. X    if (inc(&pos) == -1)
  941. X        return NULL;
  942. X
  943. X    /*
  944. X     * If we're in the middle of a word, we just have to
  945. X     * move to the end of it.
  946. X     */
  947. X    if (cls(gchar(&pos)) == sclass && sclass != 0) {
  948. X        /*
  949. X         * Move forward to end of the current word
  950. X         */
  951. X        while (cls(gchar(&pos)) == sclass) {
  952. X            if (inc(&pos) == -1)
  953. X                return NULL;
  954. X        }
  955. X        dec(&pos);            /* overshot - forward one */
  956. X        return &pos;
  957. X    }
  958. X
  959. X    /*
  960. X     * We were at the end of a word. Go to the end of the next
  961. X     * word, unless we're doing a change. In that case we stick
  962. X     * at the end of the current word.
  963. X     */
  964. X    if (in_change)
  965. X        return p;
  966. X
  967. X    while (cls(gchar(&pos)) == 0) {        /* skip any white space */
  968. X        if (inc(&pos) == -1)
  969. X            return NULL;
  970. X    }
  971. X
  972. X    sclass = cls(gchar(&pos));
  973. X
  974. X    /*
  975. X     * Move forward to end of this word.
  976. X     */
  977. X    while (cls(gchar(&pos)) == sclass) {
  978. X        if (inc(&pos) == -1)
  979. X            return NULL;
  980. X    }
  981. X    dec(&pos);            /* overshot - forward one */
  982. X
  983. X    return &pos;
  984. X}
  985. !EOR!
  986. echo extracting - sentence.c
  987. sed 's/^X//' > sentence.c << '!EOR!'
  988. X/*    Find the NEXT/PREVIOUS:
  989. X *    - SENTENCE    findsent (dir)
  990. X *    - PARAGRAPH    findpara (dir)
  991. X *    - FUNCTION    findfunc (dir)
  992. X *
  993. X *    I've split these off from SEARCH.C, because they're alike and
  994. X *    SEARCH.C is a big file already.  findfunc() was already there.
  995. X *    I added findsent() and findpara().  -  Dave Tutelman
  996. X */
  997. X
  998. X#include "stevie.h"
  999. X#include "ops.h"
  1000. X
  1001. X/* We'll be doing some classification of input characters, into: */
  1002. X#define    BLANK    0    /* Whitespace */
  1003. X#define    DOT    1    /* Period, exclamation, q-mark */
  1004. X#define    EOL    2    /* End-of-line */
  1005. X#define    OTHER    3    /* Any other non-blank stuff */
  1006. X
  1007. Xextern    int    operator;    /* From normal.c, is there an operator
  1008. X                 * pending?
  1009. X                 */
  1010. X
  1011. Xint
  1012. Xinclass (c)
  1013. X  char c;
  1014. X{
  1015. X    switch (c) {
  1016. X      case ' ':
  1017. X      case '\t':
  1018. X        return BLANK;
  1019. X      case '.':
  1020. X      case '!':
  1021. X      case '?':
  1022. X        return DOT;
  1023. X      case '\n':
  1024. X      case '\r':
  1025. X      case '\0':
  1026. X        return EOL;
  1027. X      default:
  1028. X        if (c<' ' || c>'~')    return EOL;
  1029. X        else            return OTHER;
  1030. X    }
  1031. X}
  1032. X
  1033. X/* We'll also need to (1) tell if a line is just blanks, and
  1034. X *                    (2) skip to the next OTHER character.
  1035. X * Here are a couple of functions to do it.
  1036. X */
  1037. X
  1038. Xbool_t
  1039. Xblankline (line)
  1040. X  LPTR *line;
  1041. X{
  1042. X    char    *p;
  1043. X    int    class;
  1044. X
  1045. X    if (! line)    return TRUE;
  1046. X    for (p = line->linep->s; (class=inclass(*p))!=EOL; p++)
  1047. X        if (class!=BLANK)    return FALSE;
  1048. X    return TRUE;
  1049. X}
  1050. X
  1051. X
  1052. XLPTR *
  1053. Xskiptotext (lp, dir)
  1054. X  LPTR *lp;
  1055. X  int  dir;
  1056. X{
  1057. X    LPTR *lpp;
  1058. X
  1059. X    lpp = lp;
  1060. X    while (inclass( CHAR( lpp )) != OTHER) {
  1061. X        lpp = (dir==FORWARD) ? nextchar (lpp) : prevchar (lpp);
  1062. X        if (!lpp) return (lp);        /* hit the end */
  1063. X    }
  1064. X    return (lpp);
  1065. X}
  1066. X
  1067. X
  1068. X/*
  1069. X * findsent (dir) - Find the next sentence in direction 'dir'
  1070. X *
  1071. X * Return TRUE if a sentence was found.
  1072. X *
  1073. X * Algorithm: found end of a sentence if:
  1074. X *   FWD - current char is BLANK | EOL and last is DOT.
  1075. X *   BKWD- current char is DOT and last is BLANK | EOL.
  1076. X * In either case, we then have to skip to text at beginning of next sentence.
  1077. X *
  1078. X */
  1079. Xbool_t
  1080. Xfindsent (dir)
  1081. Xint    dir;
  1082. X{
  1083. X    LPTR    *curr, *last;    /* LPTR for current & last characters */
  1084. X    int    ccurr, clast;    /* class of curr and last characters */
  1085. X    int    oldindex;    /* need to keep in case search fails */
  1086. X
  1087. X    curr  = Curschar;
  1088. X    oldindex = curr->index;
  1089. X    /* Get INTO most recent sentence sentence. */
  1090. X    if (dir==BACKWARD)
  1091. X        curr = prevchar (curr);
  1092. X    curr = skiptotext (curr, BACKWARD);
  1093. X    ccurr = OTHER;
  1094. X
  1095. X
  1096. X    do {
  1097. X        /* Take a step */
  1098. X        last = curr; clast = ccurr;
  1099. X
  1100. X        curr = (dir == FORWARD) ? nextchar(curr) : prevchar(curr);
  1101. X        ccurr = inclass (CHAR( curr ));
  1102. X
  1103. X        /* Test halting condition */
  1104. X        if (dir==FORWARD &&
  1105. X            (ccurr==BLANK || ccurr==EOL) && clast==DOT) {
  1106. X            setpcmark();
  1107. X            last = skiptotext (last, FORWARD);
  1108. X            *Curschar = *last;
  1109. X            return TRUE;
  1110. X        }
  1111. X        else if (dir==BACKWARD &&
  1112. X             ccurr==DOT && (clast==BLANK || clast==EOL)) {
  1113. X            setpcmark();
  1114. X            last = skiptotext (last, FORWARD);
  1115. X            *Curschar = *last;
  1116. X            return TRUE;
  1117. X        }
  1118. X    } while (curr != NULL);
  1119. X
  1120. X    Curschar->index = oldindex;    /* restore if search failed */
  1121. X    return FALSE;
  1122. X}
  1123. X
  1124. X
  1125. X/*
  1126. X * findpara(dir) - Find the next paragraph in direction 'dir'
  1127. X *
  1128. X * Return TRUE if a paragraph was found.
  1129. X *
  1130. X * Algorithm: found beginning of paragraph if:
  1131. X *   FWD - current line is non-blank and last is blank.
  1132. X *   BKWD- current line is blank and last is non-blank.
  1133. X * Then we skip to the first non-blank, non-dot text.
  1134. X *
  1135. X */
  1136. Xbool_t
  1137. Xfindpara(dir)
  1138. Xint    dir;
  1139. X{
  1140. X    LPTR    *curr, *last;    /* current & last lines */
  1141. X    LPTR    *marker;    /* end of current para */
  1142. X    bool_t    bcurr, blast;    /* "blankness" value for lines */
  1143. X
  1144. X    curr  = Curschar;
  1145. X    bcurr = (dir==FORWARD) ? FALSE : TRUE;    /* keeps us from passing the
  1146. X                         * text initially. */
  1147. X
  1148. X    do {
  1149. X        /* Take a step */
  1150. X        last = curr; blast = bcurr;
  1151. X        curr = (dir == FORWARD) ? nextline(curr) : prevline(curr);
  1152. X        bcurr = blankline (curr);
  1153. X
  1154. X        /* Test halting condition */
  1155. X        if (dir==FORWARD && bcurr && !blast) {
  1156. X            setpcmark();
  1157. X            curr = skiptotext (curr, FORWARD);
  1158. X            *Curschar = *curr;
  1159. X            return TRUE;
  1160. X        }
  1161. X        else if (dir==BACKWARD && bcurr && !blast) {
  1162. X            setpcmark();
  1163. X            last = skiptotext (last, FORWARD);
  1164. X            *Curschar = *last;
  1165. X            return TRUE;
  1166. X        }
  1167. X    } while (curr != NULL);
  1168. X
  1169. X    return FALSE;
  1170. X}
  1171. X
  1172. X
  1173. X/*
  1174. X * findfunc(dir) - Find the next function in direction 'dir'
  1175. X *
  1176. X * Return TRUE if a function was found.
  1177. X *
  1178. X * Algorithm depends on a style of C coding in which the ONLY '{'
  1179. X * in the first column occurs at the beginning of a function definition.
  1180. X * This is a good and common style, but not syntactically required by C.
  1181. X */
  1182. Xbool_t
  1183. Xfindfunc(dir)
  1184. Xint    dir;
  1185. X{
  1186. X    LPTR    *curr;
  1187. X
  1188. X    curr = Curschar;
  1189. X
  1190. X    do {
  1191. X        curr = (dir == FORWARD) ? nextline(curr) : prevline(curr);
  1192. X
  1193. X        if (curr != NULL && curr->linep->s[0] == '{') {
  1194. X            setpcmark();
  1195. X            *Curschar = *curr;
  1196. X            return TRUE;
  1197. X        }
  1198. X    } while (curr != NULL);
  1199. X
  1200. X    return FALSE;
  1201. X}
  1202. X
  1203. !EOR!
  1204. echo extracting - tagcmd.c
  1205. sed 's/^X//' > tagcmd.c << '!EOR!'
  1206. X/* #Header: /?????
  1207. X *
  1208. X * Routines to implement tags, and, especially, tag stacking.
  1209. X * Added by Dave Tutelman - 12/89.
  1210. X * The dotag() routine is a modification of the posted
  1211. X * version by Tony Andrews.
  1212. X * The untag() routine is new.
  1213. X */
  1214. X
  1215. X#include "stevie.h"
  1216. X
  1217. X#define    LSIZE    256    /* max. size of a line in the tags file */
  1218. X
  1219. X#ifdef TAGSTACK
  1220. X/*  We build a stack of file records, on which we push info about
  1221. X *  current file when dotag() is called.
  1222. X */
  1223. X#define    TAGSTACKSIZE    12        /* how many tag calls can we stack? */
  1224. Xstatic    struct filerecord {
  1225. X        char    *name;        /* file name pointer */
  1226. X        int    linenum;    /* line number when we left */
  1227. X} tagstack [TAGSTACKSIZE];
  1228. Xstatic    int    stackindex = 0;        /* here's how we keep track */
  1229. X#endif
  1230. X
  1231. Xextern    char    **files;
  1232. Xextern    int    curfile;
  1233. Xstatic    void    pushtags(), poptags();
  1234. X
  1235. X
  1236. X/*
  1237. X * dotag(tag, force) - goto tag.  If force=TRUE, dump pending changes.
  1238. X */
  1239. Xvoid
  1240. Xdotag(tag, force)
  1241. Xchar    *tag;
  1242. Xbool_t    force;
  1243. X{
  1244. X    FILE    *tp, *fopen();
  1245. X    char    lbuf[LSIZE];        /* line buffer */
  1246. X    char    pbuf[LSIZE];        /* search pattern buffer */
  1247. X    register char    *fname, *str;
  1248. X    register char    *p;
  1249. X
  1250. X    if ((tp = fopen("tags", "r")) == NULL) {
  1251. X        emsg("Can't open tags file");
  1252. X        return;
  1253. X    }
  1254. X
  1255. X    while (fgets(lbuf, LSIZE, tp) != NULL) {
  1256. X    
  1257. X        if ((fname = strchr(lbuf, TAB)) == NULL) {
  1258. X            emsg("Format error in tags file");
  1259. X            return;
  1260. X        }
  1261. X        *fname++ = '\0';
  1262. X        if ((str = strchr(fname, TAB)) == NULL) {
  1263. X            emsg("Format error in tags file");
  1264. X            return;
  1265. X        }
  1266. X        *str++ = '\0';
  1267. X
  1268. X        if (strcmp(lbuf, tag) == 0) {
  1269. X
  1270. X            /*
  1271. X             * Scan through the search string. If we see a magic
  1272. X             * char, we have to quote it. This lets us use "real"
  1273. X             * implementations of ctags.
  1274. X             */
  1275. X            p = pbuf;
  1276. X            *p++ = *str++;        /* copy the '/' or '?' */
  1277. X            *p++ = *str++;        /* copy the '^' */
  1278. X
  1279. X            for (; *str != NUL ;str++) {
  1280. X                if (*str == '\\') {
  1281. X                    *p++ = *str++;
  1282. X                    *p++ = *str;
  1283. X                } else if (strchr("/?", *str) != NULL) {
  1284. X                    if (str[1] != '\n') {
  1285. X                        *p++ = '\\';
  1286. X                        *p++ = *str;
  1287. X                    } else
  1288. X                        *p++ = *str;
  1289. X                } else if (strchr("^()*.", *str) != NULL) {
  1290. X                    *p++ = '\\';
  1291. X                    *p++ = *str;
  1292. X                } else
  1293. X                    *p++ = *str;
  1294. X            }
  1295. X            *p = NUL;
  1296. X
  1297. X#ifdef TAGSTACK
  1298. X            /* Push current position onto stack, unless this
  1299. X             * is a startup call using '-t' option. */
  1300. X            if (Filename!=NULL && *Filename!='\0')
  1301. X                pushtags ();
  1302. X#endif
  1303. X
  1304. X            /*
  1305. X             * This looks out of order, but by calling stuffin()
  1306. X             * before doecmd() we keep an extra screen update
  1307. X             * from occuring. This stuffins() have no effect
  1308. X             * until we get back to the main loop, anyway.
  1309. X             */
  1310. X
  1311. X            stuffin(pbuf);        /* str has \n at end */
  1312. X            stuffin("\007");    /* CTRL('g') */
  1313. X
  1314. X            if (doecmd(fname, force)) {
  1315. X                fclose(tp);
  1316. X                return;
  1317. X            } else {
  1318. X#ifdef TAGSTACK
  1319. X                poptags ();    /* cancel stack entry */
  1320. X#endif
  1321. X                stuffin(NULL);    /* clear the input */
  1322. X            }
  1323. X        }
  1324. X    }
  1325. X    emsg("tag not found");
  1326. X    fclose(tp);
  1327. X}
  1328. X
  1329. X/*
  1330. X * dountag (spec) - undo the last ':ta' command, popping the tag stack.
  1331. X *    spec is the appended character, giving specifics:
  1332. X *      '!'    dump pending changes.
  1333. X *      'e'    came from K_CCIRCM "shortcut".  do :e# if stack empty.
  1334. X *      ' '    do normal untag.
  1335. X *      else    bad command.
  1336. X */
  1337. X
  1338. Xvoid
  1339. Xdountag (spec)
  1340. X  char spec;
  1341. X{
  1342. X#ifndef TAGSTACK
  1343. X    badcmd();    /* complain & return */
  1344. X}
  1345. X#else
  1346. X
  1347. X    char    force=0, shortcut=0;
  1348. X    char    *newfile;
  1349. X    char    buf [LSIZE];
  1350. X
  1351. X    switch (spec) {
  1352. X      case '!':
  1353. X        force++;
  1354. X        break;
  1355. X      case 'e':
  1356. X        shortcut++;
  1357. X        break;
  1358. X      case ' ':
  1359. X      case '\n':
  1360. X      case '\r':
  1361. X      case '\0':
  1362. X        break;
  1363. X      default:
  1364. X        badcmd();
  1365. X        return;
  1366. X    }
  1367. X
  1368. X    /* Check the stack.  If empty, don't pop */
  1369. X    if (!stackindex) {
  1370. X        if (shortcut)        /* just edit altfile */
  1371. X            stuffin(":e #\n");
  1372. X        else
  1373. X            emsg("Tags stack empty");
  1374. X        return;
  1375. X    }
  1376. X
  1377. X    /* Get the top of the stack, and do the implied edit.
  1378. X     * If it succeeds, switch; if not, back off */
  1379. X    newfile = tagstack [stackindex-1].name;
  1380. X    if (doecmd (newfile, force)) {
  1381. X        sprintf (buf, "%dG:f\n", tagstack [stackindex-1].linenum);
  1382. X        stuffin(buf);
  1383. X        poptags ();
  1384. X        return;
  1385. X    }
  1386. X    else
  1387. X        stuffin(NULL);
  1388. X}
  1389. X
  1390. X/*
  1391. X * pushtags () - push the current state onto the tagstack.
  1392. X */
  1393. X
  1394. Xstatic void
  1395. Xpushtags ()
  1396. X{
  1397. X    int    i;
  1398. X
  1399. X    /* If stack full, throw away oldest and push the rest.
  1400. X     * This is clearly the best and most transparent way to behave,
  1401. X     * much preferable to either complaining or losing new entry.
  1402. X     */
  1403. X    if (stackindex >= TAGSTACKSIZE) {
  1404. X        for (i=0; i<TAGSTACKSIZE-1; i++) {
  1405. X            tagstack[i].name    = tagstack[i+1].name;
  1406. X            tagstack[i].linenum = tagstack[i+1].linenum;
  1407. X        }
  1408. X        stackindex--;
  1409. X    }
  1410. X
  1411. X    /* Get current state, and put it in stack.
  1412. X     * Right now, the state is file name & line number.
  1413. X     * This is less than perfect, in that line numbers may change if
  1414. X     * you edit elsewhere in the file.  Eventually, I'd like to base
  1415. X     * it on "hidden" marks, if I can implement them.  DMT
  1416. X     */
  1417. X    tagstack [stackindex].name    = strsave (Filename);
  1418. X    tagstack [stackindex].linenum = cntllines (Filemem, Curschar);
  1419. X    stackindex++;
  1420. X}
  1421. X
  1422. X/*
  1423. X * poptags () - pop the tag stack.
  1424. X */
  1425. X
  1426. Xstatic void
  1427. Xpoptags ()
  1428. X{
  1429. X    if (!stackindex) {
  1430. X        emsg("Tags stack empty");
  1431. X        return;
  1432. X    }
  1433. X
  1434. X    stackindex--;
  1435. X    free (tagstack [stackindex].name);
  1436. X}
  1437. X
  1438. X#endif
  1439. X
  1440. X
  1441. !EOR!
  1442. echo extracting - term.c
  1443. sed 's/^X//' > term.c << '!EOR!'
  1444. X/* $Header: /nw/tony/src/stevie/src/RCS/term.c,v 1.4 89/03/11 22:43:55 tony Exp $
  1445. X *
  1446. X * Termcap initialization (optional).
  1447. X */
  1448. X
  1449. X#include <stdio.h>
  1450. X#include "stevie.h"
  1451. X
  1452. X#ifdef    TERMCAP
  1453. X
  1454. Xstatic    char    buf[1024];    /* termcap entry read here */
  1455. Xstatic    char    cap[256];    /* capability strings go in here */
  1456. X
  1457. Xchar    *T_EL;        /* erase the entire current line */
  1458. Xchar    *T_IL;        /* insert one line */
  1459. Xchar    *T_DL;        /* delete one line */
  1460. Xchar    *T_SC;        /* save the cursor position */
  1461. Xchar    *T_ED;        /* erase display (may optionally home cursor) */
  1462. Xchar    *T_RC;        /* restore the cursor position */
  1463. Xchar    *T_CI;        /* invisible cursor (very optional) */
  1464. Xchar    *T_CV;        /* visible cursor (very optional) */
  1465. X
  1466. Xchar    *T_CM;        /* cursor motion string */
  1467. X
  1468. Xextern    int    tgetent(), tgetnum();
  1469. Xextern    char    *tgetstr();
  1470. Xextern    char    *getenv();
  1471. X
  1472. Xint
  1473. Xt_init()
  1474. X{
  1475. X    char    *term;
  1476. X    int    n;
  1477. X    char    *cp = cap;
  1478. X
  1479. X    if ((term = getenv("TERM")) == NULL)
  1480. X        return 0;
  1481. X
  1482. X    if (tgetent(buf, term) != 1)
  1483. X        return 0;
  1484. X
  1485. X    if ((n = tgetnum("li")) == -1)
  1486. X        return 0;
  1487. X    else
  1488. X        P(P_LI) = Rows = n;
  1489. X
  1490. X    if ((n = tgetnum("co")) == -1)
  1491. X        return 0;
  1492. X    else
  1493. X        Columns = n;
  1494. X
  1495. X    /*
  1496. X     * Get mandatory capability strings.
  1497. X     */
  1498. X    if ((T_CM = tgetstr("cm", &cp)) == NULL)
  1499. X        return 0;
  1500. X
  1501. X    if ((T_EL = tgetstr("ce", &cp)) == NULL)
  1502. X        return 0;
  1503. X
  1504. X    if ((T_ED = tgetstr("cl", &cp)) == NULL)
  1505. X        return 0;
  1506. X
  1507. X    /*
  1508. X     * Optional capabilities.
  1509. X     */
  1510. X    if ((T_IL = tgetstr("al", &cp)) == NULL)
  1511. X        T_IL = "";
  1512. X
  1513. X    if ((T_DL = tgetstr("dl", &cp)) == NULL)
  1514. X        T_DL = "";
  1515. X
  1516. X    if ((T_SC = tgetstr("sc", &cp)) == NULL)
  1517. X        T_SC = "";
  1518. X
  1519. X    if ((T_RC = tgetstr("rc", &cp)) == NULL)
  1520. X        T_RC = "";
  1521. X
  1522. X    if ((T_CI = tgetstr("vi", &cp)) == NULL)
  1523. X        T_CI = "";
  1524. X
  1525. X    if ((T_CV = tgetstr("ve", &cp)) == NULL)
  1526. X        T_CV = "";
  1527. X
  1528. X    return 1;
  1529. X}
  1530. X
  1531. X#endif
  1532. !EOR!
  1533. echo extracting - undo.c
  1534. sed 's/^X//' > undo.c << '!EOR!'
  1535. X/* $Header: /nw/tony/src/stevie/src/RCS/undo.c,v 1.7 89/08/06 09:51:06 tony Exp $
  1536. X *
  1537. X * Undo facility
  1538. X *
  1539. X * The routines in this file comprise a general undo facility for use
  1540. X * throughout the rest of the editor. The routine u_save() is called
  1541. X * before each edit operation to save the current contents of the lines
  1542. X * to be editted. Later, u_undo() can be called to return those lines
  1543. X * to their original state. The routine u_clear() should be called
  1544. X * whenever a new file is going to be editted to clear the undo buffer.
  1545. X */
  1546. X
  1547. X#include "stevie.h"
  1548. X
  1549. X/*
  1550. X * The next two variables mark the boundaries of the changed section
  1551. X * of the file. Lines BETWEEN the lower and upper bounds are changed
  1552. X * and originally contained the lines pointed to by u_lines. To undo
  1553. X * the last change, insert the lines in u_lines between the lower and
  1554. X * upper bounds.
  1555. X */
  1556. Xstatic    LINE    *u_lbound = NULL; /* line just prior to first changed line */
  1557. Xstatic    LINE    *u_ubound = NULL; /* line just after the last changed line */
  1558. X
  1559. Xstatic    LINE    *u_lline  = NULL; /* bounds of the saved lines */
  1560. Xstatic    LINE    *u_uline  = NULL;
  1561. X
  1562. Xstatic    int    u_col;
  1563. Xstatic    bool_t    u_valid = FALSE;  /* is the undo buffer valid */
  1564. X
  1565. X/*
  1566. X * Local forward declarations
  1567. X */
  1568. Xstatic    LINE    *copyline();
  1569. Xstatic    void    u_lsave();
  1570. Xstatic    void    u_lfree();
  1571. X
  1572. X/*
  1573. X * u_save(l, u) - save the current contents of part of the file
  1574. X *
  1575. X * The lines between 'l' and 'u' are about to be changed. This routine
  1576. X * saves their current contents into the undo buffer. The range l to u
  1577. X * is not inclusive because when we do an open, for example, there aren't
  1578. X * any lines in between. If no lines are to be saved, then l->next == u.
  1579. X */
  1580. Xvoid
  1581. Xu_save(l, u)
  1582. XLINE    *l, *u;
  1583. X{
  1584. X    LINE    *nl;            /* copy of the current line */
  1585. X
  1586. X    /*
  1587. X     * If l or u is null, there's an error. We don't return an
  1588. X     * indication to the caller. They should find the problem
  1589. X     * while trying to perform whatever edit is being requested
  1590. X     * (e.g. a join on the last line).
  1591. X     */
  1592. X    if (l == NULL || u == NULL)
  1593. X        return;
  1594. X
  1595. X    u_clear();            /* clear the buffer, first */
  1596. X
  1597. X    u_lsave(l, u);        /* save to the "line undo" buffer, if needed */
  1598. X
  1599. X    u_lbound = l;
  1600. X    u_ubound = u;
  1601. X
  1602. X    if (l->next != u) {        /* there are lines in the middle */
  1603. X        l = l->next;
  1604. X        u = u->prev;
  1605. X
  1606. X        u_lline = nl = copyline(l);    /* copy the first line */
  1607. X        while (l != u) {
  1608. X            nl->next = copyline(l->next);
  1609. X            nl->next->prev = nl;
  1610. X            l = l->next;
  1611. X            nl = nl->next;
  1612. X        }
  1613. X        u_uline = nl;
  1614. X    } else
  1615. X        u_lline = u_uline = NULL;
  1616. X
  1617. X    u_valid = TRUE;
  1618. X    u_col = Cursvcol;
  1619. X}
  1620. X
  1621. X/*
  1622. X * u_saveline() - save the current line in the undo buffer
  1623. X */
  1624. Xvoid
  1625. Xu_saveline()
  1626. X{
  1627. X    u_save(Curschar->linep->prev, Curschar->linep->next);
  1628. X}
  1629. X
  1630. X/*
  1631. X * u_undo() - effect an 'undo' operation
  1632. X *
  1633. X * The last edit is undone by restoring the modified section of the file
  1634. X * to its original state. The lines we're going to trash are copied to
  1635. X * the undo buffer so that even an 'undo' can be undone. Rings the bell
  1636. X * if the undo buffer is empty.
  1637. X */
  1638. Xvoid
  1639. Xu_undo()
  1640. X{
  1641. X    LINE    *tl, *tu;
  1642. X
  1643. X    if (!u_valid) {
  1644. X        beep();
  1645. X        return;
  1646. X    }
  1647. X
  1648. X    /*
  1649. X     * Get the first line of the thing we're undoing on the screen.
  1650. X     */
  1651. X    Curschar->linep = u_lbound->next;
  1652. X    Curschar->index = 0;            /* for now */
  1653. X    if (Curschar->linep == Fileend->linep)
  1654. X        Curschar->linep = Curschar->linep->prev;
  1655. X    cursupdate();
  1656. X
  1657. X    /*
  1658. X     * Save pointers to what's in the file now.
  1659. X     */
  1660. X    if (u_lbound->next != u_ubound) {    /* there are lines to get */
  1661. X        tl = u_lbound->next;
  1662. X        tu = u_ubound->prev;
  1663. X        tl->prev = NULL;
  1664. X        tu->next = NULL;
  1665. X    } else
  1666. X        tl = tu = NULL;            /* no lines between bounds */
  1667. X
  1668. X    /*
  1669. X     * Link the undo buffer into the right place in the file.
  1670. X     */
  1671. X    if (u_lline != NULL) {        /* there are lines in the undo buf */
  1672. X
  1673. X        /*
  1674. X         * If the top line of the screen is being undone, we need to
  1675. X         * fix up Topchar to point to the new line that will be there.
  1676. X         */
  1677. X        if (u_lbound->next == Topchar->linep)
  1678. X            Topchar->linep = u_lline;
  1679. X
  1680. X        u_lbound->next = u_lline;
  1681. X        u_lline->prev  = u_lbound;
  1682. X        u_ubound->prev = u_uline;
  1683. X        u_uline->next  = u_ubound;
  1684. X    } else {            /* no lines... link the bounds */
  1685. X        if (u_lbound->next == Topchar->linep)
  1686. X            Topchar->linep = u_ubound;
  1687. X        if (u_lbound == Filetop->linep)
  1688. X            Topchar->linep = u_ubound;
  1689. X            
  1690. X        u_lbound->next = u_ubound;
  1691. X        u_ubound->prev = u_lbound;
  1692. X    }
  1693. X
  1694. X    /*
  1695. X     * If we swapped the top line, patch up Filemem appropriately.
  1696. X     */
  1697. X    if (u_lbound == Filetop->linep)
  1698. X        Filemem->linep = Filetop->linep->next;
  1699. X
  1700. X    /*
  1701. X     * Now save the old stuff in the undo buffer.
  1702. X     */
  1703. X    u_lline = tl;
  1704. X    u_uline = tu;
  1705. X
  1706. X    renum();        /* have to renumber everything */
  1707. X
  1708. X    /*
  1709. X     * Put the cursor on the first line of the 'undo' region.
  1710. X     */
  1711. X    Curschar->linep = u_lbound->next;
  1712. X    Curschar->index = 0;
  1713. X    if (Curschar->linep == Fileend->linep)
  1714. X        Curschar->linep = Curschar->linep->prev;
  1715. X    *Curschar = *coladvance(Curschar, u_col);
  1716. X    cursupdate();
  1717. X    updatescreen();        /* now show the change */
  1718. X
  1719. X    u_lfree();        /* clear the "line undo" buffer */
  1720. X}
  1721. X
  1722. X/*
  1723. X * u_clear() - clear the undo buffer
  1724. X *
  1725. X * This routine is called to clear the undo buffer at times when the
  1726. X * pointers are about to become invalid, such as when a new file is
  1727. X * about to be editted.
  1728. X */
  1729. Xvoid
  1730. Xu_clear()
  1731. X{
  1732. X    LINE    *l, *nextl;
  1733. X
  1734. X    if (!u_valid)        /* nothing to do */
  1735. X        return;
  1736. X
  1737. X    for (l = u_lline; l != NULL ;l = nextl) {
  1738. X        nextl = l->next;
  1739. X        free(l->s);
  1740. X        free((char *)l);
  1741. X    }
  1742. X
  1743. X    u_lbound = u_ubound = u_lline = u_uline = NULL;
  1744. X    u_valid = FALSE;
  1745. X}
  1746. X
  1747. X/*
  1748. X * The following functions and data implement the "line undo" feature
  1749. X * performed by the 'U' command.
  1750. X */
  1751. X
  1752. Xstatic    LINE    *u_line;        /* pointer to the line we last saved */
  1753. Xstatic    LINE    *u_lcopy = NULL;    /* local copy of the original line */
  1754. X
  1755. X/*
  1756. X * u_lfree() - free the line save buffer
  1757. X */
  1758. Xstatic    void
  1759. Xu_lfree()
  1760. X{
  1761. X    if (u_lcopy != NULL) {
  1762. X        free(u_lcopy->s);
  1763. X        free((char *)u_lcopy);
  1764. X        u_lcopy = NULL;
  1765. X    }
  1766. X    u_line = NULL;
  1767. X}
  1768. X
  1769. X/*
  1770. X * u_lsave() - save the current line if necessary
  1771. X */
  1772. Xstatic    void
  1773. Xu_lsave(l, u)
  1774. XLINE    *l, *u;
  1775. X{
  1776. X
  1777. X    if (l->next != u->prev) {    /* not changing exactly one line */
  1778. X        u_lfree();
  1779. X        return;
  1780. X    }
  1781. X
  1782. X    if (l->next == u_line)        /* more edits on the same line */
  1783. X        return;
  1784. X
  1785. X    u_lfree();
  1786. X    u_line = l->next;
  1787. X    u_lcopy = copyline(l->next);
  1788. X}
  1789. X
  1790. X/*
  1791. X * u_lundo() - undo the current line (the 'U' command)
  1792. X */
  1793. Xvoid
  1794. Xu_lundo()
  1795. X{
  1796. X    if (u_lcopy != NULL) {
  1797. X        free(Curschar->linep->s);
  1798. X        Curschar->linep->s = u_lcopy->s;
  1799. X        Curschar->linep->size = u_lcopy->size;
  1800. X        free((char *)u_lcopy);
  1801. X    } else
  1802. X        beep();
  1803. X    Curschar->index = 0;
  1804. X
  1805. X    cursupdate();
  1806. X    updatescreen();        /* now show the change */
  1807. X
  1808. X    u_lcopy = NULL;    /* can't undo this kind of undo */
  1809. X    u_line = NULL;
  1810. X}
  1811. X
  1812. X/*
  1813. X * u_lcheck() - clear the "line undo" buffer if we've moved to a new line
  1814. X */
  1815. Xvoid
  1816. Xu_lcheck()
  1817. X{
  1818. X    if (Curschar->linep != u_line)
  1819. X        u_lfree();
  1820. X}
  1821. X
  1822. X/*
  1823. X * copyline(l) - copy the given line, and return a pointer to the copy
  1824. X */
  1825. Xstatic LINE *
  1826. Xcopyline(l)
  1827. XLINE    *l;
  1828. X{
  1829. X    LINE    *nl;        /* the new line */
  1830. X
  1831. X    nl = newline(strlen(l->s));
  1832. X    strcpy(nl->s, l->s);
  1833. X
  1834. X    return nl;
  1835. X}
  1836. !EOR!
  1837. echo extracting - version.c
  1838. sed 's/^X//' > version.c << '!EOR!'
  1839. Xstatic    char    RCSid[] =
  1840. X"$Header: /nw/tony/src/stevie/src/RCS/version.c,v 3.69 89/08/13 11:41:58 tony Exp $";
  1841. X
  1842. X/*
  1843. X * Contains the declaration of the global version number variable.
  1844. X *
  1845. X * $Log:    version.c,v $
  1846. X *
  1847. X * Revision 3.69a  90/02/04            dave
  1848. X * A couple of minor bugfixes, and a whole load of enhancements:
  1849. X *   -    Added tag-stacking.
  1850. X *   -    Added searches for sentences and paragraphs.
  1851. X *   -    Enhancements to "help" command:
  1852. X *     . Navigation of help screens, not just next-screen.
  1853. X *     . Index of help screens.
  1854. X *     . Screen for MSDOS-specific features.
  1855. X *     . Screen for :set commands.
  1856. X *     . A little context-sensitivity.
  1857. X *   -    File mode is preserved (it wasn't in previous versions).
  1858. X *   -    UNIX-like specifications of environments variables are expanded
  1859. X *    in file names.  (E.g.- you can say  :e $HOME/autoexec.bat)
  1860. X *   -    PC keys for Insert & Delete now work.
  1861. X *   -    Ported to Turbo C for the PC.
  1862. X *   -    Integrated Larry Shurr's BIOS option for the PC.
  1863. X *   -    Added color and multi-line options for the PC, and hooks for them
  1864. X *    in other systems.
  1865. X *   -    Made "ctags" a little more general.
  1866. X *
  1867. X * Revision 3.69  89/08/13  11:41:58  tony
  1868. X * Fixed a bug that caused messages from fileinfo() (in misccmds.c) to get
  1869. X * screwed up. The routine smsg() which uses the kludge approach to varargs
  1870. X * didn't have enough parameters for some of the calls made to it.
  1871. X *
  1872. X * Revision 3.68  89/08/06  09:51:20  tony
  1873. X * Misc. minor changes to make lint happier before posting to USENET.
  1874. X * 
  1875. X * Revision 3.67  89/08/03  13:08:52  tony
  1876. X * There was some code in ops.c that was duplicating the function of the
  1877. X * getcmdln() routine in cmdline.c. I modified getcmdln() to be slightly
  1878. X * more general, and changed dofilter() in ops.c to use it.
  1879. X * 
  1880. X * Revision 3.66  89/08/02  20:00:12  tony
  1881. X * Fixed some problems with mode lines. There were still extra screen
  1882. X * redraws that needed to be avoided. There was also a problem involving
  1883. X * nested calls to docmdln() that can occur when mode lines are used.
  1884. X * 
  1885. X * Revision 3.65  89/08/02  15:50:03  tony
  1886. X * Finally got around to providing full support for the "change" operator.
  1887. X * Multi-line changes (like "cL" or "3cc") now work correctly. Also fixed
  1888. X * a small problem with multi-line character-oriented deletes leaving the
  1889. X * cursor in the wrong location (off by one character). This is mainly
  1890. X * useful for multi-line changes (such as "c%") so the insert starts in
  1891. X * the right place.
  1892. X * 
  1893. X * Revision 3.64  89/08/02  12:47:04  tony
  1894. X * This message intentionally left blank.
  1895. X * 
  1896. X * Revision 3.63  89/08/02  12:43:44  tony
  1897. X * I just noticed that I had used the RCS cookie for log messages in one
  1898. X * of my prior version messages. This caused these version update messages
  1899. X * to be duplicated in this file. I just removed that string, and the
  1900. X * extra message copies that had been generated.
  1901. X * 
  1902. X * Revision 3.62  89/08/02  12:26:20  tony
  1903. X * The ^G command now shows where you are in the file list, if more than one
  1904. X * file is being edited. Also, the commands ":e#" and ":e!#" (note the lack
  1905. X * of a space between the command and file name) will now work.
  1906. X *
  1907. X * Revision 3.61  89/08/02  11:03:16  tony
  1908. X * Misc. cleanups regarding tags. Also added support for the "terse" option.
  1909. X * This is ignored, but improves compatibility with vi, since we no longer
  1910. X * complain about an unknown option if "terse" is used.
  1911. X * 
  1912. X * Revision 3.60  89/08/02  09:26:39  tony
  1913. X * Added code to avoid screen redraws when input is being read from the
  1914. X * "stuffin" buffer. This avoids extra redraws when switching to the
  1915. X * alternate file, or when invoking the editor with one of the "+" options,
  1916. X * or when using tags.
  1917. X *
  1918. X * Revision 3.59  89/08/01  16:28:31  tony
  1919. X * Added better support for counts on several cursor motion commands. These
  1920. X * include ^F, ^B, f, F, t, T, as well as the repeated character search
  1921. X * commands (command and semi-colon).
  1922. X *
  1923. X * Revision 3.58  89/07/19  08:08:23  tony
  1924. X * Added the ability for '~' to be an operator. If enabled (by defined TILDEOP
  1925. X * in env.h), the parameter "tildeop" (or "to") may be set to turn tilde into
  1926. X * an operator.
  1927. X * 
  1928. X * Revision 3.57  89/07/13  22:47:05  tony
  1929. X * Made some generic speed improvements in screen.c and some TOS-specific
  1930. X * improvements in tos.c. The TOS version is now much faster at screen
  1931. X * updates than before.
  1932. X * 
  1933. X * Revision 3.56  89/07/13  14:52:03  tony
  1934. X * Minor cleanups in normal.c
  1935. X * 
  1936. X * Revision 3.55  89/07/13  14:19:12  tony
  1937. X * Cleaned up the logic in getcmdln() A LOT. The routine docmdln() needs a
  1938. X * similar overhaul.
  1939. X *
  1940. X * Revision 3.54  89/07/12  21:40:01  tony
  1941. X * Lots of misc. cleanup in normal.c and cmdline.c, but nothing much in the
  1942. X * way of functional improvements. One change is that things like d/foo<CR>
  1943. X * will now work since searches are less of a special case now.
  1944. X * 
  1945. X * Revision 3.53  89/07/11  16:16:08  tony
  1946. X * Added general support for interrupt-handling for those environments that
  1947. X * can actually generate them. Basically, long-running operations are now
  1948. X * able to terminate early if an error occurs. These operations are: string
  1949. X * searches, the global command (":g/.../"), and file reads. File writes
  1950. X * should probably be done as well, but this is more dangerous. In all cases,
  1951. X * the user is given an indication on the status line that the operation
  1952. X * terminated due to an interrupt.
  1953. X * 
  1954. X * Revision 3.52  89/07/11  12:35:09  tony
  1955. X * Improved the code in dosub() and doglob() that detects quoted characters
  1956. X * and delimiters in search strings and replacement patterns. The current
  1957. X * code didn't allow certain valid strings to be used. The delimiter is still
  1958. X * required to be '/', but it can be quoted reliably now with backslash.
  1959. X * 
  1960. X * Revision 3.51  89/07/10  14:01:58  tony
  1961. X * Removed the function addtobuff() since it was rarely used and could be
  1962. X * replaced by calls to other library functions. Also removed some other
  1963. X * obsolete code that was already ifdef'd out anyway.
  1964. X * 
  1965. X * Revision 3.50  89/07/10  13:10:32  tony
  1966. X * Added a workaround in normal.c to avoid problems with broken versions of
  1967. X * strncpy() that don't properly deal with a count of zero.
  1968. X *
  1969. X * Revision 3.49  89/07/07  16:28:37  tony
  1970. X * Fixed a long-standing bug with 'cw' when the cursor is positioned on a
  1971. X * word with only one character. Also fixed a problems with zero-length files
  1972. X * and reverse searches.
  1973. X *
  1974. X * Revision 3.48  89/03/22  10:26:58  tony
  1975. X * Fixed some outdated uses of the ":p" command (which has been changed to
  1976. X * ":N" in os2.c and dos.c. Also added macros (F7 and F8) for dos and os/2
  1977. X * to use the "cdecl" program to convert lines to and from a pseudo-english
  1978. X * form. Use F7 to "explain" the declaration on the current line, and F8 to
  1979. X * convert an english-style declaration to the C form. In both cases, the
  1980. X * new form is placed on the next line, leaving the original line intact.
  1981. X * 
  1982. X * Revision 3.47  89/03/11  22:44:14  tony
  1983. X * General cleanup. Removed the static "rcsid" variables and the log
  1984. X * strings (except in version.c). Fixed some coding style inconsistencies
  1985. X * and added a few register declarations.
  1986. X * 
  1987. X * Revision 3.46  89/02/14  09:52:07  tony
  1988. X * Made a first pass at adding Robert Regn's changes, starting with the
  1989. X * more portable ones. Added better support for '#' and '%' in colon
  1990. X * commands, support for a configurable temp directory, and made the
  1991. X * termcap code less picky about capabilities.
  1992. X * 
  1993. X * Revision 3.45  88/11/10  09:00:06  tony
  1994. X * Added support for mode lines. Strings like "vi:stuff:" or "ex:stuff:"
  1995. X * occurring in the first or last 5 lines of a file cause the editor to
  1996. X * pretend that "stuff" was types as a colon command. This examination
  1997. X * is done only if the parameter "modelines" (or "ml") is set. This is
  1998. X * not enabled, by default, because of the security implications involved.
  1999. X * 
  2000. X * Revision 3.44  88/11/01  21:34:11  tony
  2001. X * Fixed a couple of minor points for Minix, and improved the speed of
  2002. X * the 'put' command dramatically.
  2003. X * 
  2004. X * Revision 3.43  88/10/31  13:11:33  tony
  2005. X * Added optional support for termcap. Initialization is done in term.c
  2006. X * and also affects the system-dependent files. To enable termcap in those
  2007. X * environments that support it, define the symbol "TERMCAP" in env.h
  2008. X *
  2009. X * Revision 3.42  88/10/27  18:30:19  tony
  2010. X * Removed support for Megamax. Added '%' as an alias for '1,$'. Made the
  2011. X * 'r' command more robust. Now prints the string on repeated searches.
  2012. X * The ':=" command now works. Some pointer operations are now safer.
  2013. X * The ":!" and ":sh" now work correctly. Re-organized the help screens
  2014. X * a little.
  2015. X * 
  2016. X * Revision 3.41  88/10/06  10:15:00  tony
  2017. X * Fixed a bug involving ^Y that occurs when the cursor is on the last
  2018. X * line, and the line above the screen is long. Also hacked up fileio.c
  2019. X * to pass pathnames off to fixname() for system-dependent processing.
  2020. X * Used under DOS & OS/2 to trim parts of the name appropriately.
  2021. X * 
  2022. X * Revision 3.40  88/09/16  08:37:36  tony
  2023. X * No longer beeps when repeated searches fail.
  2024. X *
  2025. X * Revision 3.39  88/09/06  06:51:07  tony
  2026. X * Fixed a bug with shifts that was introduced when replace mode was added.
  2027. X * 
  2028. X * Revision 3.38  88/08/31  20:48:28  tony
  2029. X * Made another fix in search.c related to repeated searches.
  2030. X * 
  2031. X * Revision 3.37  88/08/30  20:37:16  tony
  2032. X * After much prodding from Mark, I finally added support for replace mode.
  2033. X * 
  2034. X * Revision 3.36  88/08/26  13:46:34  tony
  2035. X * Added support for the '!' (filter) operator.
  2036. X * 
  2037. X * Revision 3.35  88/08/26  08:46:01  tony
  2038. X * Misc. changes to make lint happy.
  2039. X * 
  2040. X * Revision 3.34  88/08/25  15:13:36  tony
  2041. X * Fixed a bug where the cursor didn't land on the right place after
  2042. X * "beginning-of-word" searches if the word was preceded by the start
  2043. X * of the line and a single character.
  2044. X * 
  2045. X * Revision 3.33  88/08/23  12:53:08  tony
  2046. X * Fixed a bug in ssearch() where repeated searches ('n' or 'N') resulted
  2047. X * in dynamic memory being referenced after it was freed.
  2048. X * 
  2049. X * Revision 3.32  88/08/17  07:37:07  tony
  2050. X * Fixed a general problem in u_save() by checking both parameters for
  2051. X * null values. The specific symptom was that a join on the last line of
  2052. X * the file would crash the editor.
  2053. X * 
  2054. X * Revision 3.31  88/07/09  20:39:38  tony
  2055. X * Implemented the "line undo" command (i.e. 'U').
  2056. X * 
  2057. X * Revision 3.30  88/06/28  07:54:22  tony
  2058. X * Fixed a bug involving redo's of the '~' command. The redo would just
  2059. X * repeat the replacement last performed instead of switching the case of
  2060. X * the current character.
  2061. X * 
  2062. X * Revision 3.29  88/06/26  14:53:19  tony
  2063. X * Added support for a simple form of the "global" command. It supports
  2064. X * commands of the form "g/pat/d" or "g/pat/p", to delete or print lines
  2065. X * that match the given pattern. A range spec may be used to limit the
  2066. X * lines to be searched.
  2067. X * 
  2068. X * Revision 3.28  88/06/25  21:44:22  tony
  2069. X * Fixed a problem in the processing of colon commands that caused
  2070. X * substitutions of patterns containing white space to fail.
  2071. X * 
  2072. X * Revision 3.27  88/06/20  14:52:21  tony
  2073. X * Merged in changes for BSD Unix sent in by Michael Lichter.
  2074. X * 
  2075. X * Revision 3.26  88/06/10  13:44:06  tony
  2076. X * Fixed a bug involving writing out files with long pathnames. A small
  2077. X * fixed size buffer was being used. The space for the backup file name
  2078. X * is now allocated dynamically.
  2079. X * 
  2080. X * Revision 3.25  88/05/04  08:29:02  tony
  2081. X * Fixed a minor incompatibility with vi involving the 'G' command. Also
  2082. X * changed the RCS version number of version.c to match the actual version
  2083. X * of the editor.
  2084. X * 
  2085. X * Revision 1.12  88/05/03  14:39:52  tony
  2086. X * Changed the screen representation of the ascii character DELETE to be
  2087. X * compatible with vi. Also merged in support for DOS.
  2088. X * 
  2089. X * Revision 1.11  88/05/02  21:38:21  tony
  2090. X * The code that reads files now handles boundary/error conditions much
  2091. X * better, and generates status/error messages that are compatible with
  2092. X * the real vi. Also fixed a bug in repeated reverse searches that got
  2093. X * inserted in the recent changes to search.c.
  2094. X * 
  2095. X * Revision 1.10  88/05/02  07:35:41  tony
  2096. X * Fixed a bug in the routine plines() that was introduced during changes
  2097. X * made for the last version.
  2098. X * 
  2099. X * Revision 1.9  88/05/01  20:10:19  tony
  2100. X * Fixed some problems with auto-indent, and added support for the "number"
  2101. X * parameter.
  2102. X * 
  2103. X * Revision 1.8  88/04/30  20:00:49  tony
  2104. X * Added support for the auto-indent feature.
  2105. X * 
  2106. X * Revision 1.7  88/04/29  14:50:11  tony
  2107. X * Fixed a class of bugs involving commands like "ct)" where the cursor
  2108. X * motion part of the operator can fail. If the motion failed, the operator
  2109. X * was continued, with the cursor position unchanged. Cases like this were
  2110. X * modified to abort the operation if the motion fails.
  2111. X * 
  2112. X * Revision 1.6  88/04/28  08:19:35  tony
  2113. X * Modified Henry Spencer's regular expression library to support new
  2114. X * features that couldn't be done easily with the existing interface.
  2115. X * This code is now a direct part of the editor source code. The editor
  2116. X * now supports the "ignorecase" parameter, and multiple substitutions
  2117. X * per line, as in "1,$s/foo/bar/g".
  2118. X * 
  2119. X * Revision 1.5  88/04/24  21:38:00  tony
  2120. X * Added preliminary support for the substitute command. Full range specs.
  2121. X * are supported, but only a single substitution is allowed on each line.
  2122. X * 
  2123. X * Revision 1.4  88/04/23  20:41:01  tony
  2124. X * Worked around a problem with adding lines to the end of the buffer when
  2125. X * the cursor is at the bottom of the screen (in misccmds.c). Also fixed a
  2126. X * bug that caused reverse searches from the start of the file to bomb.
  2127. X *
  2128. X * Revision 1.3  88/03/24  08:57:00  tony
  2129. X * Fixed a bug in cmdline() that had to do with backspacing out of colon
  2130. X * commands or searches. Searches were okay, but colon commands backed out
  2131. X * one backspace too early.
  2132. X * 
  2133. X * Revision 1.2  88/03/21  16:47:55  tony
  2134. X * Fixed a bug in renum() causing problems with large files (>6400 lines).
  2135. X * Also moved system-specific defines out of stevie.h and into a new file
  2136. X * named env.h. This keeps volatile information outside the scope of RCS.
  2137. X * 
  2138. X * Revision 1.1  88/03/20  21:00:39  tony
  2139. X * Initial revision
  2140. X * 
  2141. X */
  2142. X
  2143. Xchar    *Version = "STEVIE - Version 3.69a";
  2144. !EOR!
  2145. echo extracting - tos.c
  2146. sed 's/^X//' > tos.c << '!EOR!'
  2147. X/* $Header: /nw/tony/src/stevie/src/RCS/tos.c,v 1.5 89/07/13 22:45:31 tony Exp $
  2148. X *
  2149. X * System-dependent routines for the Atari ST.
  2150. X */
  2151. X
  2152. X#include "stevie.h"
  2153. X
  2154. X#include <osbind.h>
  2155. X
  2156. X/*
  2157. X * inchar() - get a character from the keyboard
  2158. X *
  2159. X * Certain special keys are mapped to values above 0x80. These
  2160. X * mappings are defined in keymap.h. If the key has a non-zero
  2161. X * ascii value, it is simply returned. Otherwise it may be a
  2162. X * special key we want to map.
  2163. X *
  2164. X * The ST has a bug involving keyboard input that seems to occur
  2165. X * when typing quickly, especially typing capital letters. Sometimes
  2166. X * a value of 0x02540000 is read. This doesn't correspond to anything
  2167. X * on the keyboard, according to my documentation. My solution is to
  2168. X * loop when any unknown key is seen. Normally, the bell is rung to
  2169. X * indicate the error. If the "bug" value is seen, we ignore it completely.
  2170. X */
  2171. Xint
  2172. Xinchar()
  2173. X{
  2174. X    register long    c;
  2175. X
  2176. X    for (;;) {
  2177. X        c = Bconin(2);
  2178. X    
  2179. X        if ((c & 0xff) != 0)
  2180. X            return ((int) c);
  2181. X    
  2182. X        switch ((int) (c >> 16) & 0xff) {
  2183. X    
  2184. X        case 0x62: return K_HELP;
  2185. X        case 0x61: return K_UNDO;
  2186. X        case 0x52: return K_INSERT;
  2187. X        case 0x47: return K_HOME;
  2188. X        case 0x48: return K_UARROW;
  2189. X        case 0x50: return K_DARROW;
  2190. X        case 0x4b: return K_LARROW;
  2191. X        case 0x4d: return K_RARROW;
  2192. X        case 0x29: return K_CCIRCM;    /* control-circumflex */
  2193. X        
  2194. X        /*
  2195. X         * Occurs due to a bug in TOS.
  2196. X         */
  2197. X        case 0x54:
  2198. X            break;
  2199. X        /*
  2200. X         * Add the function keys here later if we put in support
  2201. X         * for macros.
  2202. X         */
  2203. X    
  2204. X        default:
  2205. X            beep();
  2206. X            break;
  2207. X    
  2208. X        }
  2209. X    }
  2210. X}
  2211. X
  2212. Xvoid
  2213. Xoutchar(c)
  2214. Xchar    c;
  2215. X{
  2216. X    if (c < ' ')
  2217. X        Bconout(2, c);
  2218. X    else
  2219. X        Bconout(5, c);
  2220. X}
  2221. X
  2222. Xvoid
  2223. Xoutstr(s)
  2224. Xregister char    *s;
  2225. X{
  2226. X    while (*s)
  2227. X        Bconout(2, *s++);
  2228. X}
  2229. X
  2230. X/*
  2231. X * flushbuf() - a no-op for TOS
  2232. X */
  2233. Xvoid
  2234. Xflushbuf()
  2235. X{
  2236. X}
  2237. X
  2238. X#define    BGND    0
  2239. X#define    TEXT    3
  2240. X
  2241. X/*
  2242. X * vbeep() - visual bell
  2243. X */
  2244. Xstatic void
  2245. Xvbeep()
  2246. X{
  2247. X    int    text, bgnd;        /* text and background colors */
  2248. X    long    l;
  2249. X
  2250. X    text = Setcolor(TEXT, -1);
  2251. X    bgnd = Setcolor(BGND, -1);
  2252. X
  2253. X    Setcolor(TEXT, bgnd);        /* swap colors */
  2254. X    Setcolor(BGND, text);
  2255. X
  2256. X    for (l=0; l < 5000 ;l++)    /* short pause */
  2257. X        ;
  2258. X
  2259. X    Setcolor(TEXT, text);        /* restore colors */
  2260. X    Setcolor(BGND, bgnd);
  2261. X}
  2262. X
  2263. Xvoid
  2264. Xbeep()
  2265. X{
  2266. X    if (P(P_VB))
  2267. X        vbeep();
  2268. X    else
  2269. X        outchar('\007');
  2270. X}
  2271. X
  2272. X/*
  2273. X * remove(file) - remove a file
  2274. X */
  2275. Xvoid
  2276. Xremove(file)
  2277. Xchar    *file;
  2278. X{
  2279. X    Fdelete(file);
  2280. X}
  2281. X
  2282. X/*
  2283. X * rename(of, nf) - rename existing file 'of' to 'nf'
  2284. X */
  2285. Xvoid
  2286. Xrename(of, nf)
  2287. Xchar    *of, *nf;
  2288. X{
  2289. X    Fdelete(nf);        /* if 'nf' exists, remove it */
  2290. X    Frename(0, of, nf);
  2291. X}
  2292. X
  2293. Xvoid
  2294. Xwindinit()
  2295. X{
  2296. X    if (Getrez() == 0)
  2297. X        Columns = 40;        /* low resolution */
  2298. X    else
  2299. X        Columns = 80;        /* medium or high */
  2300. X
  2301. X    P(P_LI) = Rows = 25;
  2302. X
  2303. X    Cursconf(1,NULL);
  2304. X}
  2305. X
  2306. Xvoid
  2307. Xwindexit(r)
  2308. Xint    r;
  2309. X{
  2310. X    exit(r);
  2311. X}
  2312. X
  2313. Xstatic    char    gobuf[5] = { '\033', 'Y', '\0', '\0', '\0' };
  2314. X
  2315. Xvoid
  2316. Xwindgoto(r, c)
  2317. Xint    r, c;
  2318. X{
  2319. X    gobuf[2] = r + 040;
  2320. X    gobuf[3] = c + 040;
  2321. X    outstr(gobuf);
  2322. X}
  2323. X
  2324. X/*
  2325. X * System calls or library routines missing in TOS.
  2326. X */
  2327. X
  2328. Xvoid
  2329. Xsleep(n)
  2330. Xint    n;
  2331. X{
  2332. X    int    k;
  2333. X
  2334. X    k = Tgettime();
  2335. X    while ( Tgettime() <= k+n )
  2336. X        ;
  2337. X}
  2338. X
  2339. Xvoid
  2340. Xpause()
  2341. X{
  2342. X    long    n;
  2343. X
  2344. X    for (n = 0; n < 8000 ;n++)
  2345. X        ;
  2346. X}
  2347. X
  2348. Xint
  2349. Xsystem(cmd)
  2350. Xchar    *cmd;
  2351. X{
  2352. X    char    arg[1];
  2353. X
  2354. X    arg[0] = (char) 0;    /* no arguments passed to the shell */
  2355. X
  2356. X    if (Pexec(0, cmd, arg, 0L) < 0)
  2357. X        return -1;
  2358. X    else
  2359. X        return 0;
  2360. X}
  2361. X
  2362. X#ifdef    SOZOBON
  2363. X
  2364. XFILE *
  2365. Xfopenb(fname, mode)
  2366. Xchar    *fname;
  2367. Xchar    *mode;
  2368. X{
  2369. X    char    modestr[10];
  2370. X
  2371. X    sprintf(modestr, "%sb", mode);
  2372. X
  2373. X    return fopen(fname, modestr);
  2374. X}
  2375. X
  2376. X#endif
  2377. X
  2378. X#ifndef    SOZOBON
  2379. X/*
  2380. X * getenv() - get a string from the environment
  2381. X *
  2382. X * Both Alcyon and Megamax are missing getenv(). This routine works for
  2383. X * both compilers and with the Beckemeyer and Gulam shells. With gulam,
  2384. X * the env_style variable should be set to either "mw" or "gu".
  2385. X */
  2386. Xchar *
  2387. Xgetenv(name)
  2388. Xchar    *name;
  2389. X{
  2390. X    extern long    _base;
  2391. X    char    *envp, *p;
  2392. X
  2393. X    envp = *((char **) (_base + 0x2c));
  2394. X
  2395. X    for (; *envp ;envp += strlen(envp)+1) {
  2396. X        if (strncmp(envp, name, strlen(name)) == 0) {
  2397. X            p = envp + strlen(name);
  2398. X            if (*p++ == '=')
  2399. X                return p;
  2400. X        }
  2401. X    }
  2402. X    return (char *) 0;
  2403. X}
  2404. X#endif
  2405. X
  2406. X/*
  2407. X * mktemp() - quick hack since there isn't one here
  2408. X */
  2409. Xchar *
  2410. Xmktemp(name)
  2411. Xchar    *name;
  2412. X{
  2413. X    int    num;        /* pasted into the string to make it unique */
  2414. X    char    cbuf[7];
  2415. X    char    *s;        /* where the X's start in name */
  2416. X    int    fd;
  2417. X
  2418. X    if ((s = strchr(name, 'X')) == NULL)    /* needs to be an X */
  2419. X        return (char *) NULL;
  2420. X
  2421. X    if (strlen(s) != 6)            /* should be 6 X's */
  2422. X        return (char *) NULL;
  2423. X
  2424. X    for (num = 0; num < 1000 ;num++) {
  2425. X        sprintf(cbuf, "%06d", num);
  2426. X        strcpy(s, cbuf);
  2427. X        if ((fd = open(name, 0)) < 0)
  2428. X            return name;
  2429. X        close(fd);
  2430. X    }
  2431. X    return (char *) NULL;
  2432. X}
  2433. X
  2434. Xvoid
  2435. Xdoshell(cmd)
  2436. Xchar    *cmd;
  2437. X{
  2438. X    if (cmd == NULL) {
  2439. X        shell();
  2440. X        return;
  2441. X    }
  2442. X    system(cmd);
  2443. X    wait_return();
  2444. X}
  2445. X
  2446. X#define    PSIZE    128
  2447. X
  2448. X/*
  2449. X * fixname(s) - fix up a dos name
  2450. X *
  2451. X * Takes a name like:
  2452. X *
  2453. X *    \x\y\z\base.ext
  2454. X *
  2455. X * and trims 'base' to 8 characters, and 'ext' to 3.
  2456. X */
  2457. Xchar *
  2458. Xfixname(s)
  2459. Xchar    *s;
  2460. X{
  2461. X    char    *strchr(), *strrchr();
  2462. X    static    char    f[PSIZE];
  2463. X    char    base[32];
  2464. X    char    ext[32];
  2465. X    char    *p;
  2466. X    int    i;
  2467. X
  2468. X    strcpy(f, s);
  2469. X
  2470. X    for (i=0; i < PSIZE ;i++)
  2471. X        if (f[i] == '/')
  2472. X            f[i] = '\\';
  2473. X
  2474. X    /*
  2475. X     * Split the name into directory, base, extension.
  2476. X     */
  2477. X    if ((p = strrchr(f, '\\')) != NULL) {
  2478. X        strcpy(base, p+1);
  2479. X        p[1] = '\0';
  2480. X    } else {
  2481. X        strcpy(base, f);
  2482. X        f[0] = '\0';
  2483. X    }
  2484. X
  2485. X    if ((p = strchr(base, '.')) != NULL) {
  2486. X        strcpy(ext, p+1);
  2487. X        *p = '\0';
  2488. X    } else
  2489. X        ext[0] = '\0';
  2490. X
  2491. X    /*
  2492. X     * Trim the base name if necessary.
  2493. X     */
  2494. X    if (strlen(base) > 8)
  2495. X        base[8] = '\0';
  2496. X    
  2497. X    if (strlen(ext) > 3)
  2498. X        ext[3] = '\0';
  2499. X
  2500. X    /*
  2501. X     * Paste it all back together
  2502. X     */
  2503. X    strcat(f, base);
  2504. X    strcat(f, ".");
  2505. X    strcat(f, ext);
  2506. X
  2507. X    return f;
  2508. X}
  2509. X
  2510. X/*
  2511. X *    FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT!
  2512. X *
  2513. X *    The next couple of functions do system-specific stuff.
  2514. X *    They currently do nothing; I'm not familiar enough with
  2515. X *    system-specific programming on this system.
  2516. X *    If you fill it in for your system, please post the results
  2517. X *    and share with the rest of us.
  2518. X */
  2519. X
  2520. X
  2521. Xsetcolor (c)
  2522. X/*
  2523. X * Set the color to c, using the local system convention for numbering
  2524. X * colors or video attributes.
  2525. X *
  2526. X * If you implement this, remember to note the original color in
  2527. X * windinit(), before you do any setcolor() commands, and
  2528. X * do a setcolor() back to the original as part of windexit().
  2529. X */
  2530. X  int c:
  2531. X{
  2532. X}
  2533. X
  2534. X
  2535. Xsetrows (r)
  2536. X/*
  2537. X * Set the number of lines to r, if possible.  Otherwise
  2538. X * "do the right thing".  Return the number of lines actually set.
  2539. X *
  2540. X * If you implement this, remember to note the original number of rows
  2541. X * in windinit(), before you do any setrows() commands, and
  2542. X * do a setrows() back to the original as part of windexit().
  2543. X */
  2544. X  int r;
  2545. X{
  2546. X    /* Since we do nothing, just return the current number of lines */
  2547. X    return ( P(P_LI) );
  2548. X}
  2549. X
  2550. X
  2551. Xvbeep ()
  2552. X/*
  2553. X * Do a "visual bell".  This generally consists of flashing the screen
  2554. X * once in inverse video.
  2555. X */
  2556. X{
  2557. X    int    color, revco;
  2558. X
  2559. X    color = P( P_CO );        /* get current color */
  2560. X    revco = reverse_color (color);    /* system-specific */
  2561. X    setcolor (revco);
  2562. X    flushbuf ();
  2563. X    pause ();
  2564. X    setcolor (color);
  2565. X    windgoto (Cursrow, Curscol);
  2566. X    flushbuf ();
  2567. X}
  2568. X
  2569. Xreverse_color (co)
  2570. X/*
  2571. X * Returns the inverse video attribute or color of co.
  2572. X * The existing code below is VERY simple-minded.
  2573. X * Replace it with proper code for your system.
  2574. X */
  2575. X int co;
  2576. X{
  2577. X    if (co)        return (0);
  2578. X    else        return (1);
  2579. X}
  2580. X
  2581. X
  2582. X/********** End of do-it-yourself kit **********************/
  2583. X
  2584. !EOR!
  2585.  
  2586.  
  2587.