home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / util.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  726 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include <errno.h>
  10. #include "jctype.h"
  11. #include "disp.h"
  12. #include "fp.h"
  13. #include "ask.h"
  14. #include "chars.h"
  15. #include "fmt.h"
  16. #include "insert.h"
  17. #include "macros.h"
  18. #include "marks.h"
  19. #include "move.h"
  20. #include "rec.h"
  21.  
  22. #ifdef MAC
  23. # include "mac.h"
  24. #endif
  25.  
  26. bool
  27. blnkp(buf)
  28. register char    *buf;
  29. {
  30.     register char    c;
  31.  
  32.     do {
  33.         c = *buf++;
  34.     } while (jiswhite(c));
  35.     return c == '\0';    /* It's NUL if we got to the end of the Line */
  36. }
  37.  
  38. bool
  39. within_indent()
  40. {
  41.     register int    i;
  42.  
  43.     i = curchar;
  44.     for (;;) {
  45.         if (--i < 0)
  46.             return YES;
  47.         if (!jiswhite(linebuf[i]))
  48.             return NO;
  49.     }
  50. }
  51.  
  52. void
  53. DotTo(line, col)
  54. LinePtr    line;
  55. int    col;
  56. {
  57.     Bufpos    bp;
  58.  
  59.     bp.p_line = line;
  60.     bp.p_char = col;
  61.     SetDot(&bp);
  62. }
  63.  
  64. /* If bp->p_line is != current line, then save current line.  Then set dot
  65.    to bp->p_line, and if they weren't equal get that line into linebuf.  */
  66.  
  67. void
  68. SetDot(bp)
  69. register Bufpos    *bp;
  70. {
  71.     register bool    notequal;
  72.  
  73.     if (bp == NULL)
  74.         return;
  75.  
  76.     notequal = bp->p_line != curline;
  77.     if (notequal)
  78.         lsave();
  79.     if (bp->p_line != NULL)
  80.         curline = bp->p_line;
  81.     if (notequal)
  82.         getDOT();
  83.     curchar = bp->p_char;
  84.     if (curchar > length(curline))
  85.         curchar = length(curline);
  86. }
  87.  
  88. void
  89. ToLast()
  90. {
  91.     SetLine(curbuf->b_last);
  92.     Eol();
  93. }
  94.  
  95. int    MarkThresh = 22;    /* VAR: moves greater than MarkThresh will SetMark (avg screen size) */
  96.  
  97. private int    line_diff;
  98.  
  99. int
  100. inorder(nextp, char1, endp, char2)
  101. register LinePtr    nextp,
  102.         endp;
  103. int    char1,
  104.     char2;
  105. {
  106.     register LinePtr    prevp = nextp;
  107.  
  108.     line_diff = 0;
  109.     if (nextp == endp)
  110.         return char1 < char2;
  111.  
  112.     while (nextp && prevp) {
  113.         nextp = nextp->l_next;
  114.         prevp = prevp->l_prev;
  115.         line_diff += 1;
  116.         if (nextp == endp)
  117.             return YES;
  118.         if (prevp == endp)
  119.             return NO;
  120.     }
  121.     while (nextp!=NULL && nextp!=endp) {
  122.         nextp = nextp->l_next;
  123.         line_diff += 1;
  124.     }
  125.     while (prevp!=NULL && prevp!=endp) {
  126.         prevp = prevp->l_prev;
  127.         line_diff += 1;
  128.     }
  129.     /* nextp == prevp implies both are NULL: the lines are not ordered */
  130.     return nextp==prevp? -1 : nextp==endp;
  131. }
  132.  
  133. /* Number of lines (forward OR back) from nextp to endp.
  134.  * Note: if they are not related, returns 0.
  135.  */
  136. int
  137. LineDist(nextp, endp)
  138. LinePtr    nextp,
  139.         endp;
  140. {
  141.     return inorder(nextp, 0, endp, 0) == -1? 0 : line_diff;
  142. }
  143.  
  144. /* Number of lines forward from "from" to "to"; -1 if not found.
  145.  * Note: if "to" is (LinePtr)NULL, returns number of lines to end + 1
  146.  */
  147. int
  148. LinesTo(from, to)
  149. register LinePtr
  150.     from,
  151.     to;
  152. {
  153.     int    n = 0;
  154.  
  155.     for (;;) {
  156.         if (from == to)
  157.             return n;
  158.         if (from == NULL)
  159.             return -1;
  160.         n += 1;
  161.         from = from->l_next;
  162.     }
  163. }
  164.  
  165. void
  166. PushPntp(line)
  167. register LinePtr    line;
  168. {
  169.     if (LineDist(curline, line) >= MarkThresh)
  170.         set_mark();
  171. }
  172.  
  173. void
  174. ToFirst()
  175. {
  176.     SetLine(curbuf->b_first);
  177. }
  178.  
  179. int
  180. length(line)
  181. LinePtr    line;
  182. {
  183.     return strlen(lcontents(line));
  184. }
  185.  
  186. void
  187. to_word(dir)
  188. register int    dir;
  189. {
  190.     if (dir == FORWARD) {
  191.         for(;;) {
  192.             register ZXchar    c = ZXC(linebuf[curchar]);
  193.  
  194.             if (c == '\0') {
  195.                 if (curline->l_next == NULL)
  196.                     break;    /* failure: out of buffer */
  197.                 SetLine(curline->l_next);
  198.             } else if (jisword(c)) {
  199.                 break;    /* success */
  200.             } else {
  201.                 curchar += 1;
  202.             }
  203.         }
  204.     } else {
  205.         for (;;) {
  206.             if (bolp()) {
  207.                 if (curline->l_prev == NULL)
  208.                     break;    /* failure: out of buffer */
  209.                 SetLine(curline->l_prev);
  210.                 Eol();
  211.             } else if (jisword(linebuf[curchar - 1])) {
  212.                 break;    /* success */
  213.             } else {
  214.                 curchar -= 1;
  215.             }
  216.         }
  217.     }
  218. }
  219.  
  220. /* Are there any modified buffers?  Allp means include B_PROCESS
  221.    buffers in the check. */
  222.  
  223. bool
  224. ModBufs(allp)
  225. bool    allp;
  226. {
  227.     register Buffer    *b;
  228.  
  229.     for (b = world; b != NULL; b = b->b_next)
  230.         if (b->b_type != B_SCRATCH
  231.         && (b->b_type == B_FILE || allp)
  232.         && IsModified(b))
  233.             return YES;
  234.     return NO;
  235. }
  236.  
  237. char *
  238. filename(b)
  239. register Buffer    *b;
  240. {
  241.     return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]";
  242. }
  243.  
  244. int
  245. min(a, b)
  246. register int    a,
  247.         b;
  248. {
  249.     return (a < b) ? a : b;
  250. }
  251.  
  252. int
  253. max(a, b)
  254. register int    a,
  255.         b;
  256. {
  257.     return (a > b) ? a : b;
  258. }
  259.  
  260. char *
  261. lcontents(line)
  262. register LinePtr    line;
  263. {
  264.     if (line == curline)
  265.         return linebuf;
  266.     else
  267.         return lbptr(line);
  268. }
  269.  
  270. char *
  271. ltobuf(line, buf)
  272. LinePtr    line;
  273. char    *buf;
  274. {
  275.     if (line == curline) {
  276.         if (buf != linebuf)
  277.             strcpy(buf, linebuf);
  278.         Jr_Len = strlen(linebuf);
  279.     } else
  280.         getline(line->l_dline, buf);
  281.     return buf;
  282. }
  283.  
  284. void
  285. DOTsave(buf)
  286. Bufpos *buf;
  287. {
  288.     buf->p_line = curline;
  289.     buf->p_char = curchar;
  290. }
  291.  
  292. /* Return YES iff we had to rearrange the order. */
  293.  
  294. bool
  295. fixorder(line1, char1, line2, char2)
  296. register LinePtr    *line1,
  297.         *line2;
  298. register int    *char1,
  299.         *char2;
  300. {
  301.     LinePtr    tline;
  302.     int    tchar;
  303.  
  304.     if (inorder(*line1, *char1, *line2, *char2))
  305.         return NO;
  306.  
  307.     tline = *line1;
  308.     tchar = *char1;
  309.     *line1 = *line2;
  310.     *char1 = *char2;
  311.     *line2 = tline;
  312.     *char2 = tchar;
  313.  
  314.     return YES;
  315. }
  316.  
  317. bool
  318. inlist(first, what)
  319. LinePtr    first,
  320.         what;
  321. {
  322.     return LinesTo(first, what) != -1;
  323. }
  324.  
  325. /* Make curbuf (un)modified and tell the redisplay code to update the modeline
  326.    if it will need to be changed. */
  327.  
  328. void
  329. modify()
  330. {
  331.     if (!curbuf->b_modified) {
  332.         UpdModLine = YES;
  333.         curbuf->b_modified = YES;
  334.     }
  335.     DOLsave = YES;
  336. #ifdef RECOVER
  337.     if (curbuf->b_type != B_SCRATCH)
  338.         ModCount += 1;
  339. #endif
  340. }
  341.  
  342. void
  343. unmodify()
  344. {
  345.     if (curbuf->b_modified) {
  346.         UpdModLine = YES;
  347.         curbuf->b_modified = NO;
  348.     }
  349. }
  350.  
  351. /* Set or clear the divergence flag for `buf'.
  352.    A buffer that contains a file is considered to have diverged
  353.    if the file in the filesystem appears to have changed since the
  354.    last time the buffer was loaded from or saved to that file.
  355.    If the flag has changed, tell the redisplay code to update the
  356.    modeline. */
  357.  
  358. void
  359. diverge(buf, d)
  360. Buffer    *buf;
  361. bool    d;
  362. {
  363.     if (buf->b_diverged != d) {
  364.         UpdModLine = YES;
  365.         buf->b_diverged = d;
  366.     }
  367. }
  368.  
  369. int
  370. numcomp(s1, s2)
  371. register char    *s1,
  372.         *s2;
  373. {
  374.     register int    count = 0;
  375.  
  376.     while (*s1 != '\0' && *s1++ == *s2++)
  377.         count += 1;
  378.     return count;
  379. }
  380.  
  381. #ifdef FILENAME_CASEINSENSITIVE
  382. int
  383. numcompcase(s1, s2)
  384. register char    *s1,
  385.         *s2;
  386. {
  387.     register int    count = 0;
  388.  
  389.     while (*s1 != '\0' && CharDowncase(*s1++) == CharDowncase(*s2++))
  390.         count += 1;
  391.     return count;
  392. }
  393. #endif
  394.  
  395. char *
  396. copystr(str)
  397. const char    *str;
  398. {
  399.     char    *val;
  400.  
  401.     if (str == NULL)
  402.         return NULL;
  403.     val = emalloc((size_t) (strlen(str) + 1));
  404.  
  405.     strcpy(val, str);
  406.     return val;
  407. }
  408.  
  409. #ifndef byte_copy
  410. void
  411. byte_copy(from, to, count)
  412. UnivConstPtr    *from;
  413. UnivPtr        *to;
  414. register size_t    count;
  415. {
  416.     register const char    *p = from;
  417.     register char        *q = to;
  418.  
  419.     if (count != 0) {
  420.         do *q++ = *p++; while (--count != 0);
  421.     }
  422. }
  423. #endif
  424.  
  425. void
  426. len_error(flag)
  427. int    flag;
  428. {
  429.     static const char    mesg[] = "[line too long]";
  430.  
  431.     if (flag == JMP_COMPLAIN)
  432.         complain(mesg);
  433.     else
  434.         error(mesg);
  435. }
  436.  
  437. /* Insert num copies of character c at offset atchar in buffer buf of size max */
  438.  
  439. void
  440. ins_c(c, buf, atchar, num, max)
  441. char    c;
  442. char    *buf;
  443. int    atchar,
  444.     num,
  445.     max;
  446. {
  447.     /* hint to reader: all copying and filling is done right to left */
  448.     register char    *from, *to;
  449.     int taillen;
  450.  
  451.     if (num <= 0)
  452.         return;
  453.     from = &buf[atchar];
  454.     taillen = *from == '\0'?  1 : strlen(from) + 1;    /* include NUL */
  455.     if (atchar + taillen + num > max)
  456.         len_error(JMP_COMPLAIN);
  457.     from += taillen;
  458.     to = from + num;
  459.     do {
  460.         *--to = *--from;
  461.     } while (--taillen != 0);
  462.     while (to != from)
  463.         *--to = c;
  464. }
  465.  
  466. bool
  467. TwoBlank()
  468. {
  469.     register LinePtr    next = curline->l_next;
  470.  
  471.     return (next != NULL
  472.         && *(lcontents(next)) == '\0'
  473.         && next->l_next != NULL
  474.         && *(lcontents(next->l_next)) == '\0');
  475. }
  476.  
  477. void
  478. linecopy(onto, atchar, from)
  479. register char    *onto,
  480.         *from;
  481. int    atchar;
  482. {
  483.     register char    *endp = &onto[LBSIZE];
  484.  
  485.     onto += atchar;
  486.  
  487.     do {
  488.         if (onto >= endp)
  489.             len_error(JMP_ERROR);
  490.     } while ((*onto++ = *from++) != '\0');
  491. }
  492.  
  493. char *
  494. IOerr(err, file)
  495. char    *err, *file;
  496. {
  497.     return sprint("Couldn't %s \"%s\".", err, file);
  498. }
  499.  
  500. #ifdef UNIX
  501. void
  502. dopipe(p)
  503. int    *p;
  504. {
  505.     if (pipe(p) == -1)
  506.         complain("[Pipe failed: %s]", strerror(errno));
  507. }
  508.  
  509. void
  510. pipeclose(p)
  511. int    *p;
  512. {
  513.     (void) close(p[0]);
  514.     (void) close(p[1]);
  515. }
  516. #endif /* UNIX */
  517.  
  518. /* NOSTRICT */
  519.  
  520. UnivPtr
  521. emalloc(size)
  522. size_t    size;
  523. {
  524.     register UnivPtr    ptr;
  525.  
  526.     if ((ptr = malloc(size)) == NULL) {
  527.         /* Try garbage collecting lines */
  528.         GCchunks();
  529.         if ((ptr = malloc(size)) == NULL) {
  530.             /* Uh ... Oh screw it! */
  531.             error("[Out of memory]");
  532.             /* NOTREACHED */
  533.         }
  534.     }
  535.     return ptr;
  536. }
  537.  
  538. UnivPtr
  539. erealloc(ptr, size)
  540. UnivPtr    ptr;
  541. size_t    size;
  542. {
  543.     if (ptr == NULL) {
  544.         ptr = emalloc(size);
  545.     } else if ((ptr = realloc(ptr, size)) == NULL) {
  546.         /* no second chance for realloc! */
  547.         error("[out of memory]");
  548.         /* NOTREACHED */
  549.     }
  550.     return ptr;
  551. }
  552.  
  553. /* Return the basename of file F. */
  554.  
  555. char *
  556. basename(f)
  557. register char    *f;
  558. {
  559.     register char    *cp;
  560.  
  561. #ifdef MSFILESYSTEM
  562.     if (f[0] != '\0'  && f[1] == ':')
  563.         f += 2;
  564.     if ((cp = strrchr(f, '\\')) != NULL)
  565.         f = cp + 1;
  566. #endif /* MSFILESYSTEM */
  567.     if ((cp = strrchr(f, '/')) != NULL)
  568.         f = cp + 1;
  569.     return f;
  570. }
  571.  
  572. void
  573. push_env(savejmp)
  574. jmp_buf    savejmp;
  575. {
  576.     byte_copy((UnivPtr) mainjmp, (UnivPtr) savejmp, sizeof (jmp_buf));
  577. }
  578.  
  579. void
  580. pop_env(savejmp)
  581. jmp_buf    savejmp;
  582. {
  583.     byte_copy((UnivPtr) savejmp, (UnivPtr) mainjmp, sizeof (jmp_buf));
  584. }
  585.  
  586. /* get the time buf, designated by *timep, from FROM to TO. */
  587. char *
  588. get_time(timep, buf, from, to)
  589. time_t    *timep;
  590. char    *buf;
  591. int    from,
  592.     to;
  593. {
  594.     time_t    now;
  595.     char    *cp;
  596.  
  597.     if (timep != NULL)
  598.         now = *timep;
  599.     else
  600.         (void) time(&now);
  601.     cp = ctime(&now) + from;
  602.     if (to == -1)
  603.         cp[strlen(cp) - 1] = '\0';        /* Get rid of \n */
  604.     else
  605.         cp[to - from] = '\0';
  606.     if (buf) {
  607.         strcpy(buf, cp);
  608.         return buf;
  609.     } else {
  610.         return cp;
  611.     }
  612. }
  613.  
  614. /* Are s1 and s2 equal, at least for the first n chars, ignoring case? */
  615.  
  616. bool
  617. caseeqn(s1, s2, n)
  618. register const char    *s1,
  619.         *s2;
  620. register size_t    n;
  621. {
  622.     if (s1==NULL || s2==NULL)
  623.         return NO;
  624.     for (;;) {
  625.         if (n == 0)
  626.             return YES;
  627.         n--;
  628.         if (!cind_eq(*s1, *s2++))
  629.             return NO;
  630.         if (*s1++ == '\0')
  631.             return YES;
  632.     }
  633. }
  634.  
  635. void
  636. null_ncpy(to, from, n)
  637. char    *to;
  638. const char    *from;
  639. size_t    n;
  640. {
  641.     (void) strncpy(to, from, n);
  642.     to[n] = '\0';
  643. }
  644.  
  645. bool
  646. sindex(pattern, string)
  647. register char    *pattern,
  648.         *string;
  649. {
  650.     register size_t    len = strlen(pattern);
  651.  
  652.     if (len == 0)
  653.         return YES;
  654.     while (*string != '\0') {
  655.         if (*pattern == *string && strncmp(pattern, string, len) == 0)
  656.             return YES;
  657.         string += 1;
  658.     }
  659.     return NO;
  660. }
  661.  
  662. /* Free, then allocate a block.
  663.  * Like erealloc, except that the previous contents of the block are lost.
  664.  */
  665.  
  666. UnivPtr
  667. freealloc(obj, size)
  668. register UnivPtr    obj;
  669. size_t    size;
  670. {
  671.     if (obj != NULL)
  672.         obj = realloc(obj, size);
  673.     if (obj == NULL)
  674.         obj = emalloc(size);
  675.     return obj;
  676. }
  677.  
  678. /* order file names (parameter for qsort) */
  679. int
  680. fnamecomp(a, b)
  681. UnivConstPtr    a,
  682.     b;
  683. {
  684.     return strcmp(*(const char **)a, *(const char **)b);
  685. }
  686.  
  687. #ifdef NO_STRERROR
  688. extern int sys_nerr;
  689. extern char *sys_errlist[];
  690.  
  691. /*
  692.  * Unix version of strerror - map error number to descriptive string.
  693.  * ANSI systems should have this.
  694.  */
  695. char *
  696. strerror(errnum)
  697. int errnum;
  698. {
  699.     if (errnum > 0 && errnum < sys_nerr)
  700.         return(sys_errlist[errnum]);
  701.     return sprint("Error number %d", errnum);
  702. }
  703. #endif /* NO_STRERROR */
  704.  
  705. /* decode a pair of characters representing \x or ^x */
  706.  
  707. ZXchar
  708. DecodePair(first, second)
  709. ZXchar    first, second;
  710. {
  711.     if (second == EOF || second == '\n')
  712.         complain("unexpected end of file after %p", first);
  713.     if (first == '^') {
  714.         if (second == '?') {
  715.             second = DEL;
  716.         } else {
  717.             ZXchar    us = CharUpcase(second);
  718.  
  719.             if (us < '@' || '_' < us)
  720.                 complain("unknown control character %p", second);
  721.             second = CTL(us);
  722.         }
  723.     }
  724.     return second;
  725. }
  726.