home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / editor / j414src.arc / UTIL.C < prev    next >
C/C++ Source or Header  |  1989-10-10  |  18KB  |  1,078 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is 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 "ctype.h"
  10. #include "termcap.h"
  11. #include "disp.h"
  12. #include "fp.h"
  13. #include <signal.h>
  14.  
  15. #ifdef MAC
  16. # include "mac.h"
  17. #else
  18. # ifdef    STDARGS
  19. #  include <stdarg.h>
  20. # else
  21. #  include <varargs.h>
  22. # endif
  23. #endif
  24.  
  25. #ifdef MSDOS
  26. #include <time.h>
  27. #endif
  28.  
  29. const struct cmd *
  30. FindCmd(proc)
  31. register void     (*proc) proto((void));
  32. {
  33.     register const struct cmd    *cp;
  34.  
  35.     for (cp = commands; cp->Name; cp++)
  36.         if (cp->c_proc == proc)
  37.             return cp;
  38.     return 0;
  39. }
  40.  
  41. int    Interactive;    /* True when we invoke with the command handler? */
  42. data_obj    *LastCmd;
  43. char    *ProcFmt = ": %f ";
  44.  
  45. void
  46. ExecCmd(cp)
  47. register data_obj    *cp;
  48. {
  49.     LastCmd = cp;
  50.     if (cp->Type & MAJOR_MODE) {
  51.         SetMajor((cp->Type >> 8));
  52.     } else if (cp->Type & MINOR_MODE) {
  53.         TogMinor((cp->Type >> 8));
  54.     } else    switch (cp->Type&TYPEMASK) {
  55.         case MACRO:
  56.             do_macro((struct macro *) cp);
  57.             break;
  58.  
  59.         case FUNCTION:
  60.             {
  61.             register struct cmd    *cmd = (struct cmd *) cp;
  62.  
  63.             if (cmd->c_proc) {
  64.                 if ((cmd->Type & MODIFIER) &&
  65.                     (BufMinorMode(curbuf, ReadOnly))) {
  66.                     rbell();
  67.                     message("[Buffer is read-only]");
  68.                 } else
  69.                     (*cmd->c_proc)();
  70.             }
  71.             }
  72.     }
  73. }
  74.  
  75. Line *
  76. lastline(lp)
  77. register Line    *lp;
  78. {
  79.     register Line    *next;
  80.  
  81.     while ((next = lp->l_next) != NULL)
  82.         lp = next;
  83.     return lp;
  84. }
  85.  
  86. char    key_strokes[100],
  87.     *keys_p = key_strokes;
  88.  
  89. void
  90. pp_key_strokes(buffer, size)
  91. char    *buffer;
  92. size_t    size;
  93. {
  94.     char    *buf_end = buffer + size - 5,    /* leave some extra space */
  95.         *kp = key_strokes,
  96.         c;
  97.  
  98.     *buffer = '\0';
  99.     while ((c = *kp++) != '\0') {
  100.         swritef(buffer, "%p ", c);
  101.         buffer += strlen(buffer);
  102.         if (buffer > buf_end)
  103.             break;
  104.     }
  105. }
  106.  
  107. private int    *slowp = 0;    /* for waitchar() */
  108.  
  109. private SIGRESULT
  110. slowpoke(junk)
  111. int    junk;
  112. {
  113.     char    buffer[100];
  114.  
  115.     if (slowp)
  116.         *slowp = YES;
  117.     pp_key_strokes(buffer, sizeof (buffer));
  118.     f_mess(buffer);
  119.     SIGRETURN;
  120. }
  121.  
  122. #ifdef UNIX
  123. # ifdef BSD4_2
  124. #  define N_SEC    1    /* will be precisely 1 second on 4.2 */
  125. # else
  126. #  define N_SEC    2    /* but from 1 to 2 seconds otherwise */
  127. # endif
  128. #else /* MSDOS or MAC */
  129. # define N_SEC    1
  130. int in_macro();
  131. #endif /* UNIX */
  132.  
  133. int
  134. waitchar(slow)
  135. int    *slow;
  136. {
  137.     int    c;
  138. #ifdef UNIX
  139.     unsigned int    old_time;
  140.     SIGRESULT    (*oldproc) proto((int));
  141. #else /* MSDOS or MAC */
  142.     long sw, time();
  143. #endif /* UNIX */
  144.  
  145.     slowp = slow;
  146.  
  147.     if (in_macro())        /* make macros faster ... */
  148.         return getch();
  149.  
  150.     /* If slow is a valid pointer and it's value is yes, then
  151.        we know we have already been slow during this sequence,
  152.        so we just wait for the character and then echo it. */
  153.     if (slow != 0 && *slow == YES) {
  154.         c = getch();
  155.         slowpoke(0);
  156.         return c;
  157.     }
  158. #ifdef UNIX
  159.     oldproc = signal(SIGALRM, slowpoke);
  160.  
  161.     if ((old_time = alarm((unsigned) N_SEC)) == 0)
  162.         old_time = UpdFreq;
  163.     c = getch();
  164.     (void) alarm(old_time);
  165.     (void) signal(SIGALRM, oldproc);
  166.  
  167.     if (slow != 0 && *slow == YES)
  168.         slowpoke(0);
  169.     return c;
  170.  
  171. #else /* MSDOS or MAC */
  172. #ifdef MAC
  173.     Keyonly = 1;
  174.     if (charp() || in_macro()) {
  175.         c = getch();    /* to avoid flicker */
  176.         if (slow != 0 && *slow == YES)
  177.             slowpoke();
  178.         return c;
  179.     }
  180. #endif
  181.     time(&sw);
  182.     sw += N_SEC;
  183.     while (time(NULL) <= sw)
  184.         if (charp() || in_macro())
  185.             return getch();
  186. #ifdef MAC
  187.     menus_off();
  188. #endif
  189.     slowpoke();
  190.     c = getch();
  191.     slowpoke();
  192.  
  193.     return c;
  194. #endif /* UNIX */
  195. }
  196.  
  197. /* dir > 0 means forward; else means backward. */
  198.  
  199. char *
  200. StrIndex(dir, buf, charpos, what)
  201. int    dir;
  202. register char    *buf;
  203. int    charpos;
  204. register int    what;
  205. {
  206.     register char    *cp = &buf[charpos];
  207.     register int    c;
  208.  
  209.     if (dir > 0) {
  210.         while ((c = *cp++) != '\0')
  211.             if ((c == what) != '\0')
  212.                 return (cp - 1);
  213.     } else {
  214.         while (cp >= buf && (c = *cp--)!='\0')
  215.             if (c == what)
  216.                 return (cp + 1);
  217.     }
  218.     return 0;
  219. }
  220.  
  221. int
  222. blnkp(buf)
  223. register char    *buf;
  224. {
  225.     register char    c;
  226.  
  227.     while ((c = *buf++)!='\0' && (c == ' ' || c == '\t'))
  228.         ;
  229.     return c == 0;    /* It's zero if we got to the end of the Line */
  230. }
  231.  
  232. int
  233. within_indent()
  234. {
  235.     register char    c;
  236.     register int    i;
  237.  
  238.     i = curchar;
  239.     while (--i >= 0 && ((c = linebuf[i]) == ' ' || c == '\t'))
  240.         ;
  241.     return (i < 0);        /* it's < 0 if we got to the beginning */
  242. }
  243.  
  244. Line *
  245. next_line(line, num)
  246. register Line    *line;
  247. register int    num;
  248. {
  249.     if (num < 0)
  250.         return prev_line(line, -num);
  251.     if (line)
  252.         while (--num >= 0 && line->l_next != 0)
  253.             line = line->l_next;
  254.     return line;
  255. }
  256.  
  257. Line *
  258. prev_line(line, num)
  259. register Line    *line;
  260. register int    num;
  261. {
  262.     if (num < 0)
  263.         return next_line(line, -num);
  264.     if (line)
  265.         while (--num >= 0 && line->l_prev != 0)
  266.             line = line->l_prev;
  267.     return line;
  268. }
  269.  
  270. void
  271. DotTo(line, col)
  272. Line    *line;
  273. int    col;
  274. {
  275.     Bufpos    bp;
  276.  
  277.     bp.p_line = line;
  278.     bp.p_char = col;
  279.     SetDot(&bp);
  280. }
  281.  
  282. /* If bp->p_line is != current line, then save current line.  Then set dot
  283.    to bp->p_line, and if they weren't equal get that line into linebuf.  */
  284.  
  285. void
  286. SetDot(bp)
  287. register Bufpos    *bp;
  288. {
  289.     register int    notequal;
  290.  
  291.     if (bp == 0)
  292.         return;
  293.  
  294.     notequal = bp->p_line != curline;
  295.     if (notequal)
  296.         lsave();
  297.     if (bp->p_line)
  298.         curline = bp->p_line;
  299.     if (notequal)
  300.         getDOT();
  301.     curchar = bp->p_char;
  302.     if (curchar > length(curline))
  303.         curchar = length(curline);
  304. }
  305.  
  306. void
  307. ToLast()
  308. {
  309.     SetLine(curbuf->b_last);
  310.     Eol();
  311. }
  312.  
  313. int    MarkThresh = 22;    /* average screen size ... */
  314. static int    line_diff;
  315.  
  316. int
  317. LineDist(nextp, endp)
  318. register Line    *nextp,
  319.         *endp;
  320. {
  321.     (void) inorder(nextp, 0, endp, 0);
  322.     return line_diff;
  323. }
  324.  
  325. int
  326. inorder(nextp, char1, endp, char2)
  327. register Line    *nextp,
  328.         *endp;
  329. int    char1,
  330.     char2;
  331. {
  332.     int    count = 0;
  333.     register Line    *prevp = nextp;
  334.  
  335.     line_diff = 0;
  336.     if (nextp == endp)
  337.         return char1 < char2;
  338.  
  339.     while (nextp || prevp) {
  340.         if (nextp == endp || prevp == endp)
  341.             break;
  342.         if (nextp)
  343.             nextp = nextp->l_next;
  344.         if (prevp)
  345.             prevp = prevp->l_prev;
  346.         count += 1;
  347.     }
  348.     if (nextp == 0 && prevp == 0)
  349.         return -1;
  350.     line_diff = count;
  351.  
  352.     return nextp == endp;
  353. }
  354.  
  355. void
  356. PushPntp(line)
  357. register Line    *line;
  358. {
  359.     if (LineDist(curline, line) >= MarkThresh)
  360.         set_mark();
  361. }
  362.  
  363. void
  364. ToFirst()
  365. {
  366.     SetLine(curbuf->b_first);
  367. }
  368.  
  369. int
  370. length(line)
  371. Line    *line;
  372. {
  373.     return strlen(lcontents(line));
  374. }
  375.  
  376. void
  377. to_word(dir)
  378. register int    dir;
  379. {
  380.     register char    c;
  381.  
  382.     if (dir == FORWARD) {
  383.         while ((c = linebuf[curchar]) != 0 && !isword(c))
  384.             curchar += 1;
  385.         if (eolp()) {
  386.             if (curline->l_next == 0)
  387.                 return;
  388.             SetLine(curline->l_next);
  389.             to_word(dir);
  390.             return;
  391.         }
  392.     } else {
  393.         while (!bolp() && (c = linebuf[curchar - 1], !isword(c)))
  394.             curchar -= 1;
  395.         if (bolp()) {
  396.             if (curline->l_prev == 0)
  397.                 return;
  398.             SetLine(curline->l_prev);
  399.             Eol();
  400.             to_word(dir);
  401.         }
  402.     }
  403. }
  404.  
  405. /* Are there any modified buffers?  Allp means include B_PROCESS
  406.    buffers in the check. */
  407.  
  408. int
  409. ModBufs(allp)
  410. int    allp;
  411. {
  412.     register Buffer    *b;
  413.  
  414.     for (b = world; b != 0; b = b->b_next) {
  415.         if (b->b_type == B_SCRATCH)
  416.             continue;
  417.         if ((b->b_type == B_FILE || allp) && IsModified(b))
  418.             return 1;
  419.     }
  420.     return 0;
  421. }
  422.  
  423. char *
  424. filename(b)
  425. register Buffer    *b;
  426. {
  427.     return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]";
  428. }
  429.  
  430. char *
  431. itoa(num)
  432. register int    num;
  433. {
  434.     static char    line[15];
  435.  
  436.     swritef(line, "%d", num);
  437.     return line;
  438. }
  439.  
  440. int
  441. min(a, b)
  442. register int    a,
  443.         b;
  444. {
  445.     return (a < b) ? a : b;
  446. }
  447.  
  448. int
  449. max(a, b)
  450. register int    a,
  451.         b;
  452. {
  453.     return (a > b) ? a : b;
  454. }
  455.  
  456. void
  457. tiewind(w, bp)
  458. register Window    *w;
  459. register Buffer    *bp;
  460. {
  461.     int    not_tied = (w->w_bufp != bp);
  462.  
  463.     UpdModLine = YES;    /* kludge ... but speeds things up considerably */
  464.     w->w_line = bp->b_dot;
  465.     w->w_char = bp->b_char;
  466.     w->w_bufp = bp;
  467.     if (not_tied)
  468.         CalcWind(w);    /* ah, this has been missing since the
  469.                    beginning of time! */
  470. }
  471.  
  472. char *
  473. lcontents(line)
  474. register Line    *line;
  475. {
  476.     if (line == curline)
  477.         return linebuf;
  478.     else
  479.         return lbptr(line);
  480. }
  481.  
  482. char *
  483. ltobuf(line, buf)
  484. Line    *line;
  485. char    *buf;
  486. {
  487.     if (line == curline) {
  488.         if (buf != linebuf)
  489.             strcpy(buf, linebuf);
  490.         Jr_Len = strlen(linebuf);
  491.     } else
  492.         getline(line->l_dline, buf);
  493.     return buf;
  494. }
  495.  
  496. void
  497. DOTsave(buf)
  498. Bufpos *buf;
  499. {
  500.     buf->p_line = curline;
  501.     buf->p_char = curchar;
  502. }
  503.  
  504. /* Return none-zero if we had to rearrange the order. */
  505.  
  506. int
  507. fixorder(line1, char1, line2, char2)
  508. register Line    **line1,
  509.         **line2;
  510. register int    *char1,
  511.         *char2;
  512. {
  513.     Line    *tline;
  514.     int    tchar;
  515.  
  516.     if (inorder(*line1, *char1, *line2, *char2))
  517.         return 0;
  518.  
  519.     tline = *line1;
  520.     tchar = *char1;
  521.     *line1 = *line2;
  522.     *char1 = *char2;
  523.     *line2 = tline;
  524.     *char2 = tchar;
  525.  
  526.     return 1;
  527. }
  528.  
  529. int
  530. inlist(first, what)
  531. register Line    *first,
  532.         *what;
  533. {
  534.     while (first) {
  535.         if (first == what)
  536.             return 1;
  537.         first = first->l_next;
  538.     }
  539.     return 0;
  540. }
  541.  
  542. /* Make `buf' (un)modified and tell the redisplay code to update the modeline
  543.    if it will need to be changed. */
  544.  
  545. int    ModCount = 0;
  546.  
  547. void
  548. modify()
  549. {
  550.     if (!curbuf->b_modified) {
  551.         UpdModLine = YES;
  552.         curbuf->b_modified = YES;
  553.     }
  554.     DOLsave = YES;
  555.     if (!Asking)
  556.         ModCount += 1;
  557. }
  558.  
  559. void
  560. unmodify()
  561. {
  562.     if (curbuf->b_modified) {
  563.         UpdModLine = YES;
  564.         curbuf->b_modified = NO;
  565.     }
  566. }
  567.  
  568. int
  569. numcomp(s1, s2)
  570. register char    *s1,
  571.         *s2;
  572. {
  573.     register int    count = 0;
  574.  
  575.     while (*s1 != 0 && *s1++ == *s2++)
  576.         count += 1;
  577.     return count;
  578. }
  579.  
  580. char *
  581. copystr(str)
  582. char    *str;
  583. {
  584.     char    *val;
  585.  
  586.     if (str == 0)
  587.         return 0;
  588.     val = emalloc((size_t) (strlen(str) + 1));
  589.  
  590.     strcpy(val, str);
  591.     return val;
  592. }
  593.  
  594. #ifndef byte_copy
  595. void
  596. byte_copy(from, to, count)
  597. register char    *from,
  598.         *to;
  599. register size_t    count;
  600. {
  601.     while (count-- > 0)
  602.         *to++ = *from++;
  603. }
  604. #endif
  605.  
  606. void
  607. len_error(flag)
  608. int    flag;
  609. {
  610.     char    *mesg = "[line too long]";
  611.  
  612.     if (flag == COMPLAIN)
  613.         complain(mesg);
  614.     else
  615.         error(mesg);
  616. }
  617.  
  618. /* Insert num number of c's at offset atchar in a linebuf of LBSIZE */
  619.  
  620. void
  621. ins_c(c, buf, atchar, num, max)
  622. int    c;
  623. char    *buf;
  624. int    atchar,
  625.     num,
  626.     max;
  627. {
  628.     register char    *pp, *pp1;
  629.     register int    len;
  630.     int    numchars;    /* number of characters to copy forward */
  631.  
  632.     if (num <= 0)
  633.         return;
  634.     len = atchar + strlen(&buf[atchar]);
  635.     if (len + num >= max)
  636.         len_error(COMPLAIN);
  637.     pp = &buf[len + 1];        /* + 1 so we can --pp (not pp--) */
  638.     pp1 = &buf[len + num + 1];
  639.     numchars = len - atchar;
  640.     while (numchars-- >= 0)
  641.         *--pp1 = *--pp;
  642.     pp = &buf[atchar];
  643.     while (--num >= 0)
  644.         *pp++ = c;
  645. }
  646.  
  647. int
  648. TwoBlank()
  649. {
  650.     register Line    *next = curline->l_next;
  651.  
  652.     return ((next != 0) &&
  653.         (*(lcontents(next)) == '\0') &&
  654.         (next->l_next != 0) &&
  655.         (*(lcontents(next->l_next)) == '\0'));
  656. }
  657.  
  658. void
  659. linecopy(onto, atchar, from)
  660. register char    *onto,
  661.         *from;
  662. int    atchar;
  663. {
  664.     register char    *endp = &onto[LBSIZE - 2];
  665.  
  666.     onto += atchar;
  667.  
  668.     while ((*onto = *from++) != '\0')
  669.         if (onto++ >= endp)
  670.             len_error(ERROR);
  671. }
  672.  
  673. char *
  674. IOerr(err, file)
  675. char    *err, *file;
  676. {
  677.     return sprint("Couldn't %s \"%s\".", err, file);
  678. }
  679.  
  680. #ifdef UNIX
  681. void
  682. dopipe(p)
  683. int    *p;
  684. {
  685.     if (pipe(p) == -1)
  686.         complain("[Pipe failed]");
  687. }
  688.  
  689. void
  690. pclose(p)
  691. int    *p;
  692. {
  693.     (void) close(p[0]);
  694.     (void) close(p[1]);
  695. }
  696. #endif /* UNIX */
  697.  
  698. /* NOSTRICT */
  699.  
  700. char *
  701. emalloc(size)
  702. size_t    size;
  703. {
  704.     register char    *ptr;
  705.  
  706.     if ((ptr = malloc(size)) != NULL)
  707.         return ptr;
  708.     /* Try garbage collecting lines */
  709.     GCchunks();
  710.     if ((ptr = malloc(size)) != NULL)
  711.         return ptr;
  712.     /* Uh ... Oh screw it! */
  713.     error("[Out of memory] ");
  714.     /* NOTREACHED */
  715. }
  716.  
  717. /* Return the basename of file F. */
  718.  
  719. char *
  720. basename(f)
  721. register char    *f;
  722. {
  723.     register char    *cp;
  724.  
  725.     if ((cp = strrchr(f, '/')) != NULL)
  726.         return cp + 1;
  727.     else
  728. #ifdef MSDOS
  729.         if (cp = strrchr(f, '\\'))
  730.             return cp + 1;
  731.     else
  732.         if (cp = strrchr(f, ':'))
  733.             return cp + 1;
  734. #endif /* MSDOS */
  735.         return f;
  736. }
  737.  
  738. void
  739. push_env(savejmp)
  740. jmp_buf    savejmp;
  741. {
  742.     byte_copy((char *) mainjmp, (char *) savejmp, sizeof (jmp_buf));
  743. }
  744.  
  745. void
  746. pop_env(savejmp)
  747. jmp_buf    savejmp;
  748. {
  749.     byte_copy((char *) savejmp, (char *) mainjmp, sizeof (jmp_buf));
  750. }
  751.  
  752. #ifdef LOAD_AV
  753. # if defined(BSD4_2) && !defined(BSD2_10)
  754. #   if defined(PURDUE_EE) && (defined(vax) || defined(gould))
  755.  
  756. void
  757. get_la(dp)
  758. double *dp;
  759. {
  760.     *dp = (double) loadav(0) / 100.0;
  761. }
  762.  
  763. #   else /* !PURDUE_EE || (!vax && !gould) */
  764.  
  765. #ifdef sun
  766. #   include <sys/param.h>
  767. #endif
  768. #include <nlist.h>
  769.  
  770. static struct    nlist nl[] = {
  771.     { "_avenrun", 0, 0, 0, 0 },
  772. #define    X_AVENRUN    0
  773.     { "", 0, 0, 0, 0 }
  774. };
  775.  
  776. void
  777. get_la(dp)
  778. double    *dp;
  779. {
  780. #ifdef sun
  781.     long    avenrun[3];
  782. #else
  783.     double    avenrun[3];
  784. #endif
  785.     static int    kmem = 0;
  786.     extern long    lseek proto((int, long, int));
  787.  
  788.     if (kmem == -1) {
  789.         *dp = 4.0;    /* So shell commands will say "Chugging" */
  790.         return;
  791.     } else if (kmem == 0) {
  792.         if ((kmem = open("/dev/kmem", 0)) == -1) {
  793.             f_mess("Can't open kmem for load average.");
  794.             *dp = 4.0;
  795.             return;
  796.         }
  797.         nlist("/vmunix", nl);
  798.     }
  799.     lseek(kmem, (long) nl[X_AVENRUN].n_value, 0);
  800.     read(kmem, (char *) avenrun, sizeof(avenrun));
  801. #ifdef sun
  802.     *dp = (double) avenrun[0] / FSCALE;
  803. #else
  804.     *dp = avenrun[0];
  805. #endif
  806. }
  807.  
  808. #    endif
  809. #  else /* !BSD4_2 || BSD2_10 */
  810.  
  811. void
  812. get_la(dp)
  813. double    *dp;
  814. {
  815.     short    avg[3];
  816.  
  817.     gldav(avg);
  818.     *dp = (double) avg[0] / 256;
  819. }
  820.  
  821. #  endif
  822. #endif /* LOAD_AV */
  823.  
  824. /* get the time buf, designated by *timep, from FROM to TO. */
  825. char *
  826. get_time(timep, buf, from, to)
  827. time_t    *timep;
  828. char    *buf;
  829. int    from,
  830.     to;
  831. {
  832.     time_t    now;
  833.     char    *cp;
  834.     extern char    *ctime();
  835.  
  836.     if (timep != 0)
  837.         now = *timep;
  838.     else
  839.         (void) time(&now);
  840.     cp = ctime(&now) + from;
  841. #ifndef MSDOS
  842.     if (to == -1)
  843. #else /* MSDOS */
  844.     if ((to == -1) && (cp[strlen(cp)-1] == '\n'))
  845. #endif /* MSDOS */
  846.         cp[strlen(cp) - 1] = '\0';        /* Get rid of \n */
  847.     else
  848.         cp[to - from] = '\0';
  849.     if (buf) {
  850.         strcpy(buf, cp);
  851.         return buf;
  852.     } else
  853.         return cp;
  854. }
  855.  
  856. int
  857. casecmp(s1, s2)
  858. register char    *s1,
  859.         *s2;
  860. {
  861.     if (!s1 || !s2)
  862.         return 1;    /* which is not zero ... */
  863.     while (CharUpcase(*s1) == CharUpcase(*s2++))
  864.         if (*s1++ == '\0')
  865.             return 0;
  866.     return (*s1 - *--s2);
  867. }
  868.  
  869. int
  870. casencmp(s1, s2, n)
  871. register char    *s1,
  872.         *s2;
  873. register size_t    n;
  874. {
  875.     if (!s1 || !s2)
  876.         return 1;    /* which is not zero ... */
  877.     for (;;) {
  878.         if (n == 0)
  879.             return 0;
  880.         n--;
  881.         if (CharUpcase(*s1) != CharUpcase(*s2++))
  882.             return *s1 - *--s2;
  883.         if (*s1++ == '\0')
  884.             return 0;
  885.     }
  886. }
  887.  
  888. void
  889. null_ncpy(to, from, n)
  890. char    *to,
  891.     *from;
  892. size_t    n;
  893. {
  894.     (void) strncpy(to, from, n);
  895.     to[n] = '\0';
  896. }
  897.  
  898. /* Tries to pause for delay/10 seconds OR until a character is typed
  899.    at the keyboard.  This works well on BSD4_2 and not so well on the
  900.    rest.  Returns 1 if it returned because of keyboard input, or 0
  901.    otherwise. */
  902.  
  903. #ifdef MAC
  904. void
  905. SitFor(delay)
  906. int    delay;
  907. {
  908.     long    start,
  909.         end;
  910.  
  911. #define Ticks ((long *) 0x16A)    /* 1/60 sec */
  912.     Keyonly = 1;
  913.     redisplay();
  914.     start = *Ticks;
  915.  
  916.     end = start + delay * 6;
  917.     do
  918.         if (InputPending = charp())
  919.             break;
  920.     while (*Ticks < end);
  921. #undef    Ticks
  922. }
  923. #else    /* not MAC */
  924.  
  925. #ifndef MSDOS
  926. #if defined(BSD4_2) && !defined(BSD2_10)
  927. #include <sys/time.h>
  928. #endif
  929. #endif
  930.  
  931. void
  932. SitFor(delay)
  933. int    delay;
  934. {
  935. #ifndef MSDOS
  936. #if defined(BSD4_2) && !defined(BSD2_10)
  937.     struct timeval    timer;
  938.     long    readfds = 1;
  939.  
  940.     timer.tv_sec = (delay / 10);
  941.     timer.tv_usec = (delay % 10) * 100000;
  942.  
  943.     if (charp())
  944.         return;
  945.     /* gross that I had to snarf this from getch() */
  946.     if (!UpdMesg && !Asking) {    /* Don't erase if we are asking */
  947.         if (mesgbuf[0] && !errormsg)
  948.             message(NullStr);
  949.     }
  950.     redisplay();
  951.     select(1, &readfds, (long *)0, (long *)0, &timer);
  952. #else
  953.     static const int cps[] = {
  954.         0,
  955.         5,
  956.         7,
  957.         11,
  958.         13,
  959.         15,
  960.         20,
  961.         30,
  962.         60,
  963.         120,
  964.         180,
  965.         240,
  966.         480,
  967.         960,
  968.         1920,
  969.         1920,
  970.     };
  971.     register int    nchars,
  972.             check_cnt;
  973.  
  974.     if (charp())
  975.         return;
  976.     nchars = (delay * cps[ospeed]) / 10;
  977.     check_cnt = BufSize;
  978.     redisplay();
  979.     while ((--nchars > 0) && !InputPending) {
  980.         jputchar(0);
  981.         if (--check_cnt == 0) {
  982.             check_cnt = BufSize;
  983.             InputPending = charp();
  984.         }
  985.     }
  986. #endif
  987. #else /* MSDOS */
  988. #include <bios.h>
  989. #include <dos.h>
  990.  
  991.     long    start,
  992.         end;
  993. #ifndef IBMPC
  994.     struct dostime_t tc;
  995. #endif
  996.  
  997.     redisplay();
  998. #ifdef IBMPC
  999.     _bios_timeofday(_TIME_GETCLOCK, &start);
  1000. #else
  1001.     _dos_gettime(&tc);
  1002.     start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
  1003.         (long)(tc.second*10)+(long)(tc.hsecond/10);
  1004. #endif
  1005.     end = (start + delay);
  1006.     do  {
  1007.         if (InputPending = charp())
  1008.             break;
  1009. #ifdef IBMPC
  1010.     if (_bios_timeofday(_TIME_GETCLOCK, &start))
  1011.             break;    /* after midnight */
  1012. #else
  1013.         start = (long)(tc.hour*60L*60L*10L)+(long)(tc.minute*60L*10L)+
  1014.         (long)(tc.second*10)+(long)(tc.hsecond/10);
  1015. #endif
  1016.     }
  1017.     while (start < end);
  1018. #endif /* MSDOS */
  1019. }
  1020. #endif /* MAC */
  1021.  
  1022. int
  1023. sindex(pattern, string)
  1024. register char    *pattern,
  1025.         *string;
  1026. {
  1027.     register size_t    len = strlen(pattern);
  1028.  
  1029.     while (*string != '\0') {
  1030.         if (*pattern == *string && strncmp(pattern, string, len) == 0)
  1031.             return TRUE;
  1032.         string += 1;
  1033.     }
  1034.     return FALSE;
  1035. }
  1036.  
  1037. void
  1038. make_argv(argv, ap)
  1039. register char    *argv[];
  1040. va_list    ap;
  1041. {
  1042.     register char    *cp;
  1043.     register int    i = 0;
  1044.  
  1045.     argv[i++] = va_arg(ap, char *);
  1046.     argv[i++] = basename(argv[0]);
  1047.     while ((cp = va_arg(ap, char *)) != NULL)
  1048.         argv[i++] = cp;
  1049.     argv[i] = 0;
  1050. }
  1051.  
  1052. int
  1053. pnt_line()
  1054. {
  1055.     register Line    *lp = curbuf->b_first;
  1056.     register int    i;
  1057.  
  1058.     for (i = 0; lp != 0; i++, lp = lp->l_next)
  1059.         if (lp == curline)
  1060.             break;
  1061.     return i + 1;
  1062. }
  1063.  
  1064. char *
  1065. ralloc(obj, size)
  1066. register char    *obj;
  1067. size_t    size;
  1068. {
  1069.     register char    *new;
  1070.  
  1071.     if (obj)
  1072.         new = realloc(obj, size);
  1073.     if (new == 0 || !obj)
  1074.         new = emalloc(size);
  1075.     return new;
  1076. }
  1077.  
  1078.