home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / jove414s.zip / extend.c < prev    next >
C/C++ Source or Header  |  1991-07-06  |  15KB  |  713 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 "fp.h"
  10. #include "termcap.h"
  11. #include "ctype.h"
  12. #include "chars.h"
  13. #include "disp.h"
  14. #include "re.h"
  15.  
  16. #if defined(JOB_CONTROL) || defined(IPROCS) || defined (OS2IPROCS)
  17. # include <signal.h>
  18. #endif
  19.  
  20. #ifdef MAC
  21. # include "mac.h"
  22. #else
  23. # ifdef    STDARGS
  24. #  include <stdarg.h>
  25. # else
  26. #  include <varargs.h>
  27. # endif
  28. #endif
  29.  
  30. #ifdef MSDOS
  31. # include <process.h>
  32. #endif
  33.  
  34. private void
  35.     DefAutoExec proto((struct data_obj *(*proc)()));
  36.  
  37. private int
  38.     match proto((char **, char *));
  39.  
  40. int    InJoverc = 0;
  41.  
  42. /* Auto execute code */
  43.  
  44. #define NEXECS    20
  45.  
  46. private struct {
  47.     char    *a_pattern;
  48.     data_obj    *a_cmd;
  49. } AutoExecs[NEXECS];    /* must be initialized by system to 0 */
  50.  
  51. private int    ExecIndex = 0;
  52.  
  53. /* Command auto-execute. */
  54.  
  55. void
  56. CAutoExec()
  57. {
  58.     DefAutoExec(findcom);
  59. }
  60.  
  61. /* Macro auto-execute. */
  62.  
  63. void
  64. MAutoExec()
  65. {
  66.     DefAutoExec(findmac);
  67. }
  68.  
  69. private void
  70. DefAutoExec(proc)
  71. #if defined(MAC) || defined(IBMPC)
  72. data_obj    *(*proc)();
  73. #else
  74. data_obj    *(*proc) proto((char *));
  75. #endif
  76. {
  77.     data_obj    *d;
  78.     char    *pattern;
  79.     int    i;
  80.  
  81.     if (ExecIndex >= NEXECS)
  82.         complain("Too many auto-executes, max %d.", NEXECS);
  83.     if ((d = (*proc)(ProcFmt)) == 0)
  84.         return;
  85.     pattern = do_ask("\r\n", (int (*) proto((int))) 0, (char *) 0, ": %f %s ",
  86.         d->Name);
  87.     for (i = 0; i < ExecIndex; i++) {
  88.         if (AutoExecs[i].a_cmd == d) {
  89.         char    *ipat = AutoExecs[i].a_pattern;
  90.  
  91.         if ((pattern == NULL || ipat == NULL)?
  92.             (pattern == ipat) : (strcmp(pattern, ipat) == 0))
  93.             return;        /* eliminate duplicates */
  94.         }
  95.     }
  96.     AutoExecs[ExecIndex].a_pattern = copystr(pattern);
  97.     AutoExecs[ExecIndex].a_cmd = d;
  98.     ExecIndex += 1;
  99. }
  100.  
  101. /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
  102.    same kind of file (i.e., match the same pattern) or OLD is 0 and it
  103.    matches, OR if the pattern is 0 (none was specified) then, we execute
  104.    the command associated with that kind of file. */
  105.  
  106. void
  107. DoAutoExec(new, old)
  108. register  char    *new,
  109.         *old;
  110. {
  111.     register  int    i;
  112.  
  113.     set_arg_value(1);
  114.     for (i = 0; i < ExecIndex; i++)
  115.         if ((AutoExecs[i].a_pattern == 0) ||
  116.             ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
  117.              (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
  118.             ExecCmd(AutoExecs[i].a_cmd);
  119. }
  120.  
  121. int
  122. addgetc()
  123. {
  124.     int    c;
  125.     int _fastcall get_ch(void);
  126.  
  127.     if (!InJoverc) {
  128.         Asking = strlen(mesgbuf);
  129.         c = get_ch();
  130.         Asking = 0;
  131.         add_mess("%p ", c);
  132.     } else {
  133.         c = get_ch();
  134.         if (c == '\n')
  135.             return EOF;    /* this isn't part of the sequence */
  136.         else if (c == '\\') {
  137.             if ((c = get_ch()) == LF)
  138.                 complain("[Premature end of line]");
  139.         } else if (c == '^') {
  140.             if ((c = get_ch()) == '?')
  141.                 c = RUBOUT;
  142.             else if (isalpha(c) || strchr("@[\\]^_", c))
  143.                 c = CTL(c);
  144.             else
  145.                 complain("[Unknown control character]");
  146.         }
  147.     }
  148.     return c;
  149. }
  150.  
  151. void
  152. Extend()
  153. {
  154.     data_obj    *d;
  155.  
  156.     if ((d = findcom(": ")) != NULL)
  157.         ExecCmd(d);
  158. }
  159.  
  160. /* Read a positive integer from CP.  It must be in base BASE, and
  161.    complains if it isn't.  If allints is nonzero, all the characters
  162.    in the string must be integers or we return -1; otherwise we stop
  163.    reading at the first nondigit. */
  164.  
  165. int
  166. chr_to_int(cp, base, allints, result)
  167. register  char    *cp;
  168. int    base,
  169.     allints;
  170. register  int    *result;
  171. {
  172.     register  int    c;
  173.     int    value = 0,
  174.         sign;
  175.  
  176.     if ((c = *cp) == '-') {
  177.         sign = -1;
  178.         cp += 1;
  179.     } else
  180.         sign = 1;
  181.     while ((c = *cp++) != '\0') {
  182.         if (!isdigit(c)) {
  183.             if (allints == YES)
  184.                 return INT_BAD;
  185.             break;
  186.         }
  187.         c = c - '0';
  188.         if (c >= base)
  189.             complain("You must specify in base %d.", base);
  190.         value = value * base + c;
  191.     }
  192.     *result = value * sign;
  193.     return INT_OKAY;
  194. }
  195.  
  196. int
  197. ask_int(prompt, base)
  198. char    *prompt;
  199. int    base;
  200. {
  201.     char    *val = ask((char *) 0, prompt);
  202.     int    value;
  203.  
  204.     if (chr_to_int(val, base, YES, &value) == INT_BAD)
  205.         complain("That's not a number!");
  206.     return value;
  207. }
  208.  
  209. void
  210. vpr_aux(vp, buf)
  211. register  const struct variable    *vp;
  212. char    *buf;
  213. {
  214.     switch (vp->v_flags & V_TYPEMASK) {
  215.     case V_BASE10:
  216.         swritef(buf, "%d", *((int *) vp->v_value));
  217.         break;
  218.  
  219.     case V_BASE8:
  220.         swritef(buf, "%o", *((int *) vp->v_value));
  221.         break;
  222.  
  223.     case V_BOOL:
  224.         swritef(buf, (*((int *) vp->v_value)) ? "on" : "off");
  225.         break;
  226.  
  227.     case V_STRING:
  228.     case V_FILENAME:
  229.         swritef(buf, "%s", vp->v_value);
  230.         break;
  231.  
  232.     case V_CHAR:
  233.         swritef(buf, "%p", *((int *) vp->v_value));
  234.         break;
  235.     }
  236. }
  237.  
  238. void
  239. PrVar()
  240. {
  241.     struct variable    *vp;
  242.     char    prbuf[256];
  243.  
  244.     if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
  245.         return;
  246.     vpr_aux(vp, prbuf);
  247.     s_mess(": %f %s => %s", vp->Name, prbuf);
  248. }
  249.  
  250. void
  251. SetVar()
  252. {
  253.     struct variable    *vp;
  254.     char    *prompt;
  255. #ifdef OS2
  256.     void        _fastcall setcolor(unsigned char  fg, unsigned char bg);
  257. #endif
  258.     if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
  259.         return;
  260.     prompt = sprint(": %f %s ", vp->Name);
  261.  
  262.     switch (vp->v_flags & V_TYPEMASK) {
  263.     case V_BASE10:
  264.     case V_BASE8:
  265.         {
  266.         int    value;
  267.  
  268.         value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
  269.                       ? 10 : 8);
  270.         *((int *) vp->v_value) = value;
  271.         break;
  272.         }
  273.  
  274.     case V_BOOL:
  275.         {
  276.         char    *def = *((int *) vp->v_value) ? "off" : "on",
  277.             *on_off;
  278.         int    value;
  279.  
  280.         on_off = ask(def, prompt);
  281.         if (casecmp(on_off, "on") == 0)
  282.             value = ON;
  283.         else if (casecmp(on_off, "off") == 0)
  284.             value = OFF;
  285.         else
  286.             complain("Boolean variables must be ON or OFF.");
  287.         *((int *) vp->v_value) = value;
  288. #ifdef MAC
  289.         MarkVar(vp,-1,0);    /* mark the menu item */
  290. #endif
  291.         s_mess("%s%s", prompt, value ? "on" : "off");
  292.         break;
  293.         }
  294.  
  295.     case V_FILENAME:
  296.         {
  297.         char    fbuf[FILESIZE];
  298.  
  299.         swritef(&prompt[strlen(prompt)], "(default %s) ", vp->v_value);
  300.         (void) ask_file(prompt, (char *) vp->v_value, fbuf);
  301.         strcpy((char *) vp->v_value, fbuf);
  302.         break;
  303.         }
  304.  
  305.     case V_STRING:
  306.         {
  307.         char    *str;
  308.  
  309.         /* Do_ask() so you can set string to "" if you so desire. */
  310.         str = do_ask("\r\n", (int (*) proto((int))) 0, (char *) vp->v_value,
  311.             prompt);
  312.         if (str == 0)
  313.             str = NullStr;
  314.         strcpy(vp->v_value, str);
  315.         /* ... and hope there is enough room. */
  316.         break;
  317.         }
  318.     case V_CHAR:
  319.         f_mess(prompt);
  320.         *((int *) vp->v_value) = addgetc();
  321.         break;
  322.  
  323.     }
  324.     if (vp->v_flags & V_MODELINE)
  325.         UpdModLine = YES;
  326.     if (vp->v_flags & V_CLRSCREEN) {
  327. #ifdef IBMPC
  328.         setcolor(Fgcolor, Bgcolor);
  329. #endif /* IBMPC */
  330.         ClAndRedraw();
  331.     }
  332.     if (vp->v_flags & V_TTY_RESET)
  333.         tty_reset();
  334. }
  335.  
  336. /* Command completion - possible is an array of strings, prompt is
  337.    the prompt to use, and flags are ... well read jove.h.
  338.  
  339.    If flags are RET_STATE, and the user hits <return> what they typed
  340.    so far is in the Minibuf string. */
  341.  
  342. private char    **Possible;
  343. private int    comp_value,
  344.         comp_flags;
  345.  
  346. int
  347. aux_complete(c)
  348. int    c;
  349. {
  350.     int    command,
  351.         i;
  352.     void _fastcall screen_buffer_flush (void);
  353.  
  354.     if (comp_flags & CASEIND) {
  355.         char    *lp;
  356.  
  357.         for (lp = linebuf; *lp != '\0'; lp++)
  358. #if (defined(IBMPC) || defined(MAC))
  359.             lower(lp);
  360. #else
  361.             if (isupper(*lp))
  362.                 *lp = tolower(*lp);
  363. #endif
  364.     }
  365.     switch (c) {
  366.     case EOF:
  367.         comp_value = -1;
  368.         return 0;
  369.  
  370.     case '\r':
  371.     case '\n':
  372.         command = match(Possible, linebuf);
  373.         if (command >= 0) {
  374.             comp_value = command;
  375.             return 0;    /* tells ask to stop */
  376.         }
  377.         if (eolp() && bolp()) {
  378.             comp_value = NULLSTRING;
  379.             return 0;
  380.         }
  381.         if (comp_flags & RET_STATE) {
  382.             comp_value = command;
  383.             return 0;
  384.         }
  385.         if (InJoverc)
  386.             complain("[\"%s\" unknown]", linebuf);
  387.         rbell();
  388.         break;
  389.  
  390.     case '\t':
  391.     case ' ':
  392.         {
  393.         int    minmatch = 1000,
  394.             maxmatch = 0,
  395.             numfound = 0,
  396.             lastmatch = -1,
  397.             len = strlen(linebuf);
  398.  
  399.         for (i = 0; Possible[i] != 0; i++) {
  400.             int    this_len;
  401.  
  402.             this_len = numcomp(Possible[i], linebuf);
  403.             maxmatch = max(maxmatch, this_len);
  404.             if (this_len >= len) {
  405.                 if (numfound)
  406.                     minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
  407.                 else
  408.                     minmatch = strlen(Possible[i]);
  409.                 numfound += 1;
  410.                 lastmatch = i;
  411.                 if (strcmp(linebuf, Possible[i]) == 0)
  412.                     break;
  413.             }
  414.         }
  415.  
  416.         if (numfound == 0) {
  417.             rbell();
  418.             if (InJoverc)
  419.                 complain("[\"%s\" unknown]", linebuf);
  420.             /* If we're not in the .joverc then
  421.                let's do something helpful for the
  422.                user. */
  423.             if (maxmatch < len) {
  424.                 char    *cp;
  425.  
  426.                 cp = linebuf + maxmatch;
  427.                 *cp = 0;
  428.                 Eol();
  429.             }
  430.             break;
  431.         }
  432.         if (c != '\t' && numfound == 1) {
  433.             comp_value = lastmatch;
  434.             return 0;
  435.         }
  436.         null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch);
  437.         Eol();
  438.         if (minmatch == len)    /* No difference */
  439.             rbell();
  440.         break;
  441.         }
  442.  
  443.     case '?':
  444.         {
  445.         int    len;
  446.  
  447.         if (InJoverc)
  448.             complain((char *) 0);
  449.         /* kludge: in case we're using UseBuffers, in which case
  450.            linebuf gets written all over */
  451.         strcpy(Minibuf, linebuf);
  452.         len = strlen(Minibuf);
  453.         TOstart("Completion", TRUE);    /* for now ... */
  454.         for (i = 0; Possible[i]; i++)
  455.             if (numcomp(Possible[i], Minibuf) >= len) {
  456.                 Typeout(Possible[i]);
  457.                 if (TOabort != 0)
  458.                     break;
  459.             }
  460.  
  461.         TOstop();
  462.         }
  463.         break;
  464.     }
  465.     return !FALSE;
  466. }
  467.  
  468. int
  469. complete(possible, prompt, flags)
  470. register  char    *possible[];
  471. char    *prompt;
  472. int    flags;
  473. {
  474.     void _fastcall screen_buffer_flush (void);
  475.     /* protect static "Possible" from being overwritten due to recursion */
  476.     if (InRealAsk)
  477.         complain((char *) NULL);
  478.  
  479.     Possible = possible;
  480.     comp_flags = flags;
  481.     (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
  482.     //screen_buffer_flush ();    /* DB */
  483.     return comp_value;
  484. }
  485.  
  486. private int
  487. match(choices, what)
  488. register  char    **choices,
  489.         *what;
  490. {
  491.     register  size_t    len;
  492.     int    i,
  493.         found = 0,
  494.         save,
  495.         exactmatch = -1;
  496.  
  497.     len = strlen(what);
  498.     if (len == 0)
  499.         return NULLSTRING;
  500.     for (i = 0; choices[i]; i++) {
  501.         if (strncmp(what, choices[i], len) == 0) {
  502.             if (strcmp(what, choices[i]) == 0)
  503.                 exactmatch = i;
  504.             save = i;
  505.             found += 1;    /* found one */
  506.         }
  507.     }
  508.  
  509.     if (found == 0)
  510.         save = ORIGINAL;
  511.     else if (found > 1) {
  512.         if (exactmatch != -1)
  513.             save = exactmatch;
  514.         else
  515.             save = AMBIGUOUS;
  516.     }
  517.  
  518.     return save;
  519. }
  520.  
  521. void
  522. Source()
  523. {
  524.     extern char    *getenv();
  525.     char    *com,
  526.         buf[FILESIZE];
  527.  
  528. #ifndef MSDOS
  529.     swritef(buf, "%s/.joverc", HomeDir);
  530. #else /* MSDOS */
  531.     if (com = getenv("JOVERC"))
  532.         strcpy(buf, com);
  533.     else
  534.         strcpy(buf, Joverc);
  535. #endif /* MSDOS */
  536.     com = ask_file((char *) 0, buf, buf);
  537.     if (joverc(buf) == 0)
  538.         complain(IOerr("read", com));
  539. }
  540.  
  541. void
  542. BufPos()
  543. {
  544.     register  Line    *lp = curbuf->b_first;
  545.     register  int    i,
  546.             dotline;
  547.     long    dotchar,
  548.         nchars;
  549.  
  550.     for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
  551.         if (lp == curline) {
  552.             dotchar = nchars + curchar;
  553.             dotline = i + 1;
  554.         }
  555.         nchars += length(lp) + (lp->l_next != 0); /* include the NL */
  556.     }
  557.  
  558.     s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
  559.            filename(curbuf), dotline, i, dotchar, nchars,
  560.            (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
  561.            calc_pos(linebuf, curchar),
  562.            calc_pos(linebuf, (int)strlen(linebuf)));
  563. }
  564.  
  565. #define IF_UNBOUND    (-1)
  566. #define IF_TRUE        1
  567. #define IF_FALSE    (!IF_TRUE)
  568.  
  569. #ifndef MAC
  570. private int
  571. do_if(cmd)
  572. char    *cmd;
  573. {
  574. #ifdef MSDOS
  575.     int status;
  576. #else
  577.     int    pid,
  578.         status;
  579. #endif /* MSDOS */
  580. #ifndef MSDOS
  581.  
  582.     switch (pid = fork()) {
  583.     case -1:
  584.         complain("[Fork failed: if]");
  585.         /*NOTREACHED*/
  586.  
  587.     case 0:
  588.         {
  589. #endif /* MSDOS */
  590.         char    *args[12],
  591.             *cp = cmd,
  592.             **ap = args;
  593.  
  594.         *ap++ = cmd;
  595.         for (;;) {
  596.             if ((cp = strchr(cp, ' ')) == 0)
  597.                 break;
  598.             *cp++ = '\0';
  599.             *ap++ = cp;
  600.         }
  601.         *ap = 0;
  602.  
  603. #ifndef MSDOS
  604.         close(0);    /*    we want reads to fail */
  605.         /* close(1);     but not writes or ioctl's
  606.         close(2);    */
  607. #else /* MSDOS */
  608.     if ((status = spawnvp(0, args[0], args)) < 0)
  609.         complain("[Spawn failed: if]");
  610. # ifdef OS2
  611.     os2_kbd_open();
  612. # endif /* OS2 */
  613. #endif /* MSDOS */
  614.  
  615. #if (!defined MSDOS && !defined OS2IPROCS)
  616.         (void) execvp(args[0], (const char **)args);
  617.         _exit(-10);    /* signals exec error (see below) */
  618.         }
  619.     }
  620. #ifdef IPROCS
  621.     SigHold(SIGCHLD);
  622. #endif
  623.     dowait(pid, &status);
  624. #ifdef IPROCS
  625.     SigRelse(SIGCHLD);
  626. #endif
  627.     if (status == -10)
  628.         complain("[Exec failed]");
  629.     if (status < 0)
  630.         complain("[Exit %d]", status);
  631. #endif /* MSDOS && OS2IPROCS */
  632.     return (status == 0);    /* 0 means successful */
  633. }
  634. #endif /* MAC */
  635.  
  636. int
  637. joverc(file)
  638. char    *file;
  639. {
  640.     char    buf[LBSIZE],
  641.         lbuf[LBSIZE];
  642.     int    lnum = 0,
  643.         eof = FALSE;
  644.     jmp_buf    savejmp;
  645.     int    IfStatus = IF_UNBOUND;
  646.     File    *fp;
  647.  
  648.     fp = open_file(file, buf, F_READ, NO, YES);
  649.     if (fp == NIL)
  650.         return NO;    /* joverc returns an integer */
  651.  
  652.     /* Catch any errors, here, and do the right thing with them,
  653.        and then restore the error handle to whoever did a setjmp
  654.        last. */
  655.  
  656.     InJoverc += 1;
  657.     push_env(savejmp);
  658.     if (setjmp(mainjmp)) {
  659.         Buffer    *savebuf = curbuf;
  660.  
  661.         SetBuf(do_select((Window *) 0, "RC errors"));
  662.         ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO);
  663.         unmodify();
  664.         SetBuf(savebuf);
  665.         Asking = 0;
  666.     }
  667.     if (!eof) do {
  668.         eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
  669.         lnum += 1;
  670.         if (lbuf[0] == '#')        /* a comment */
  671.             continue;
  672. #ifndef MAC
  673.         if (casencmp(lbuf, "if", (size_t)2) == 0) {
  674.             char    cmd[128];
  675.  
  676.             if (IfStatus != IF_UNBOUND)
  677.                 complain("[Cannot have nested if's]");
  678.             if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
  679.                 complain("[If syntax error]");
  680.             putmatch(1, cmd, sizeof cmd);
  681.             IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
  682.             continue;
  683.         } else if (casencmp(lbuf, "else", (size_t)4) == 0) {
  684.             if (IfStatus == IF_UNBOUND)
  685.                 complain("[Unexpected `else']");
  686.             IfStatus = !IfStatus;
  687.             continue;
  688.         } else if (casencmp(lbuf, "endif", (size_t)5) == 0) {
  689.             if (IfStatus == IF_UNBOUND)
  690.                 complain("[Unexpected `endif']");
  691.             IfStatus = IF_UNBOUND;
  692.             continue;
  693.         }
  694. #endif
  695.         if (IfStatus == IF_FALSE)
  696.             continue;
  697.         (void) strcat(lbuf, "\n");
  698.         Inputp = lbuf;
  699.         while (*Inputp == ' ' || *Inputp == '\t')
  700.             Inputp += 1;    /* skip white space */
  701.         Extend();
  702.     } while (!eof);
  703.  
  704.     f_close(fp);
  705.     pop_env(savejmp);
  706.     Inputp = 0;
  707.     Asking = 0;
  708.     InJoverc -= 1;
  709.     if (IfStatus != IF_UNBOUND)
  710.         complain("[Missing endif]");
  711.     return 1;
  712. }
  713.