home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / eval.c < prev    next >
C/C++ Source or Header  |  1998-09-22  |  34KB  |  1,536 lines

  1. /*    EVAL.C:    Expression evaluation functions for
  2.         MicroEMACS
  3.  
  4.     written 1986 by Daniel Lawrence
  5.  *
  6.  * $Header: /usr/build/vile/vile/RCS/eval.c,v 1.168 1998/09/22 23:02:21 tom Exp $
  7.  *
  8.  */
  9.  
  10. #include    "estruct.h"
  11. #include    "edef.h"
  12. #include    "nevars.h"
  13. #include    "patchlev.h"
  14.  
  15. #define    FUNC_NAMELEN    4
  16.  
  17. #define    ILLEGAL_NUM    -1
  18. #define    MODE_NUM    -2
  19. #define    USER_NUM    -3
  20.  
  21. #if SYS_OS2 || SYS_OS2_EMX
  22. #  define SHELL_NAME "COMSPEC"
  23. #  define SHELL_PATH "cmd.exe"
  24. #else
  25. #  if SYS_WINNT
  26. #    define SHELL_NAME "COMSPEC"
  27. #    define SHELL_PATH (is_winnt() ? "cmd.exe" : "command.com")
  28. #  else
  29. #    if SYS_MSDOS
  30. #      define SHELL_NAME "COMSPEC"
  31. #      define SHELL_PATH "command.com"
  32. #    else
  33. #      define SHELL_NAME "SHELL"
  34. #      define SHELL_PATH "/bin/sh"
  35. #    endif
  36. #  endif
  37. #endif
  38.  
  39. /* When the command interpretor needs to get a variable's name, rather than its
  40.  * value, it is passed back as a VDESC variable description structure.  The
  41.  * v_num field is an index into the appropriate variable table.
  42.  */
  43.  
  44.     /* macros for environment-variable switch */
  45.     /*  (if your compiler balks with "non-constant case expression" */
  46. #if CC_CANNOT_OFFSET_CASES
  47. #define    If(N)        if (vnum == N) {
  48. #define    ElseIf(N)    } else If(N)
  49. #define    Otherwise    } else {
  50. #define    EndIf        }
  51. #else            /* more compact if it works... */
  52. #define    If(N)        switch (vnum) { case N: {
  53. #define    ElseIf(N)    break; } case N: {
  54. #define    Otherwise    break; } default: {
  55. #define    EndIf        }}
  56. #endif
  57.  
  58. #if OPT_EVAL
  59. typedef struct    {
  60.     int    v_type;    /* type of variable */
  61.     int    v_num;    /* index, if it's an environment-variable */
  62.     UVAR *    v_ptr;    /* pointer, if it's a user-variable */
  63.     } VDESC;
  64.  
  65. static    SIZE_T    s2size ( char *s );
  66. static    char *    getkill (void);
  67. static    char *    ltos ( int val );
  68. static    char *    s2offset ( char *s, char *n );
  69. static    int    PromptAndSet ( const char *var, int f, int n );
  70. static    int    SetVarValue ( VDESC *var, const char *value );
  71. static    int    ernd (void);
  72. static    int    gtlbl ( const char *tokn );
  73. static    int    l_strtol ( const char *s );
  74. static    int    sindex ( const char *sourc, const char *pattern );
  75. #endif
  76.  
  77. /*--------------------------------------------------------------------------*/
  78.  
  79. #if    ENVFUNC && OPT_EVAL
  80. static char *
  81. GetEnv(char *s)
  82. {
  83.     register char *v = getenv(s);
  84.     return v ? v : "";
  85. }
  86.  
  87. static char *
  88. DftEnv(
  89. register char    *name,
  90. register char    *dft)
  91. {
  92.     name = GetEnv(name);
  93.     return (*name == EOS) ? dft : name;
  94. }
  95.  
  96. static void
  97. SetEnv(
  98. char    **namep,
  99. const char *value)
  100. {
  101.     FreeIfNeeded(*namep);
  102.     *namep = strmalloc(value);
  103. }
  104. #else
  105. #define    GetEnv(s)    ""
  106. #define    DftEnv(s,d)    d
  107. #define    SetEnv(np,s)    (*(np) = strmalloc(s))
  108. #endif
  109.  
  110. #if OPT_EVAL && OPT_SHELL
  111. static char *shell;    /* $SHELL environment is "$shell" variable */
  112. static char *directory;    /* $TMP environment is "$directory" variable */
  113. #if DISP_X11
  114. static char *x_display;    /* $DISPLAY environment is "$xdisplay" variable */
  115. static char *x_shell;    /* $XSHELL environment is "$xshell" variable */
  116. #endif
  117. #endif
  118.  
  119. #if OPT_EVAL && OPT_SHELL
  120. char *
  121. get_shell(void)
  122. {
  123.     if (shell == 0)
  124.         SetEnv(&shell, DftEnv(SHELL_NAME, SHELL_PATH));
  125.     return shell;
  126. }
  127. #endif
  128.  
  129. #if OPT_SHOW_EVAL
  130. /* list the current vars into the current buffer */
  131. /* ARGSUSED */
  132. static void
  133. makevarslist(int dum1 GCC_UNUSED, void *ptr)
  134. {
  135.     register UVAR *p;
  136.     register int j;
  137.  
  138.     bprintf("--- Environment variables %*P\n", term.t_ncol-1, '-');
  139.     bprintf("%s", (char *)ptr);
  140.     for (p = user_vars, j = 0; p != 0; p = p->next) {
  141.         if (!j++)
  142.             bprintf("--- User variables %*P", term.t_ncol-1, '-');
  143.         bprintf("\n%%%s = %s", p->u_name, p->u_value);
  144.     }
  145. }
  146.  
  147. /* Test a name to ensure that it is a mode-name, filtering out modish-stuff
  148.  * such as "all" and "noview"
  149.  */
  150. static int
  151. is_mode_name(const char *name, int showall, VALARGS *args)
  152. {
  153.     if (is_varmode(name)) {
  154.         if (find_mode(name, -TRUE, args)) {
  155.             if (!showall && !strcmp(name, args->names->shortname))
  156.                 return FALSE;
  157.             return TRUE;
  158.         }
  159.         return SORTOFTRUE;
  160.     }
  161.     return FALSE;
  162. }
  163.  
  164. /* filter out mode-names that apply only to abbreviations */
  165. static const char *
  166. get_listvalue(const char *name, int showall)
  167. {
  168.     VALARGS args;
  169.     register int    s;
  170.  
  171.     if ((s = is_mode_name(name, showall, &args)) == TRUE)
  172.         return string_mode_val(&args);
  173.     else if (s == SORTOFTRUE)
  174.         return gtenv(name);
  175.     return 0;
  176. }
  177. #endif /* OPT_SHOW_EVAL */
  178.  
  179. /* ARGSUSED */
  180. #if OPT_SHOW_EVAL
  181. int
  182. listvars(int f, int n)
  183. {
  184.     char *values;
  185.     register WINDOW *wp = curwp;
  186.     register int s;
  187.     register ALLOC_T t;
  188.     register char *v;
  189.     register const char *vv;
  190.     static    const char fmt[] = { "$%s = %*S\n" };
  191.     const char *const *Names = f ? list_of_modes() : envars;
  192.     int    showall = f ? (n > 1) : FALSE;
  193.  
  194.     /* collect data for environment-variables, since some depend on window */
  195.     for (s = t = 0; Names[s] != 0; s++) {
  196.         if ((vv = get_listvalue(Names[s], showall)) != 0)
  197.             t += strlen(Names[s]) + strlen(fmt) + strlen(vv);
  198.     }
  199.     if ((values = typeallocn(char, t)) == 0)
  200.         return FALSE;
  201.  
  202.     for (s = 0, v = values; Names[s] != 0; s++) {
  203.         if ((vv = get_listvalue(Names[s], showall)) != 0) {
  204.             t = strlen(vv);
  205.             if (t == 0) {
  206.                 t = 1;
  207.                 vv = "";
  208.             } else if (vv[t-1] == '\n')
  209.                 t--;    /* suppress trailing newline */
  210.             v = lsprintf(v, fmt, Names[s], t, vv);
  211.         }
  212.     }
  213.     s = liststuff(VARIABLES_BufName, FALSE,
  214.                 makevarslist, 0, (void *)values);
  215.     free(values);
  216.  
  217.     /* back to the buffer whose modes we just listed */
  218.     swbuffer(wp->w_bufp);
  219.     return s;
  220. }
  221. #endif /* OPT_SHOW_EVAL */
  222.  
  223. #if OPT_EVAL
  224. static const char *
  225. gtfun(            /* evaluate a function */
  226. const char *fname)    /* name of function to evaluate */
  227. {
  228.     register int fnum;        /* index to function to eval */
  229.     const char *it = errorm;
  230.     char arg0[FUNC_NAMELEN];
  231.     char arg1[NSTRING];        /* value of first argument */
  232.     char arg2[NSTRING];        /* value of second argument */
  233.     char arg3[NSTRING];        /* value of third argument */
  234.     static char result[2 * NSTRING];    /* string result */
  235.  
  236.     *arg1 = *arg2 = *arg3 = EOS;
  237.     if (!fname[0])
  238.         return(it);
  239.  
  240.     /* look the function up in the function table */
  241.     mklower(strncpy0(arg0, fname, FUNC_NAMELEN)); /* case-independent */
  242.     for (fnum = 0; fnum < NFUNCS; fnum++)
  243.         if (strcmp(arg0, funcs[fnum].f_name) == 0)
  244.             break;
  245.  
  246.     /* return errorm on a bad reference */
  247.     if (fnum == NFUNCS)
  248.         return(errorm);
  249.  
  250.     /* if needed, retrieve the first argument */
  251.     if (funcs[fnum].f_type >= MONAMIC) {
  252.         if (macarg(arg1) != TRUE)
  253.             return(errorm);
  254.  
  255.         /* if needed, retrieve the second argument */
  256.         if (funcs[fnum].f_type >= DYNAMIC) {
  257.             if (macarg(arg2) != TRUE)
  258.                 return(errorm);
  259.  
  260.             /* if needed, retrieve the third argument */
  261.             if (funcs[fnum].f_type >= TRINAMIC)
  262.                 if (macarg(arg3) != TRUE)
  263.                     return(errorm);
  264.         }
  265.     }
  266.  
  267.     /* and now evaluate it! */
  268.     switch (fnum) {
  269.     case UFADD:
  270.         it = l_itoa(l_strtol(arg1) + l_strtol(arg2));
  271.         break;
  272.     case UFSUB:
  273.         it = l_itoa(l_strtol(arg1) - l_strtol(arg2));
  274.         break;
  275.     case UFTIMES:
  276.         it = l_itoa(l_strtol(arg1) * l_strtol(arg2));
  277.         break;
  278.     case UFDIV:
  279.         it = l_itoa(l_strtol(arg1) / l_strtol(arg2));
  280.         break;
  281.     case UFMOD:
  282.         it = l_itoa(l_strtol(arg1) % l_strtol(arg2));
  283.         break;
  284.     case UFNEG:
  285.         it = l_itoa(-l_strtol(arg1));
  286.         break;
  287.     case UFCAT:
  288.         it = strcat(strcpy(result, arg1), arg2);
  289.         break;
  290.     case UFLEFT:
  291.         it = strncpy0(result, arg1, s2size(arg2)+1);
  292.         break;
  293.     case UFRIGHT:
  294.         it = strcpy(result, s2offset(arg1,arg2));
  295.         break;
  296.     case UFMID:
  297.         it = strncpy0(result, s2offset(arg1,arg2), s2size(arg3)+1);
  298.         break;
  299.     case UFNOT:
  300.         it = ltos(stol(arg1) == FALSE);
  301.         break;
  302.     case UFEQUAL:
  303.         it = ltos(l_strtol(arg1) == l_strtol(arg2));
  304.         break;
  305.     case UFLESS:
  306.         it = ltos(l_strtol(arg1) < l_strtol(arg2));
  307.         break;
  308.     case UFGREATER:
  309.         it = ltos(l_strtol(arg1) > l_strtol(arg2));
  310.         break;
  311.     case UFSEQUAL:
  312.         it = ltos(strcmp(arg1, arg2) == 0);
  313.         break;
  314.     case UFSLESS:
  315.         it = ltos(strcmp(arg1, arg2) < 0);
  316.         break;
  317.     case UFSGREAT:
  318.         it = ltos(strcmp(arg1, arg2) > 0);
  319.         break;
  320.     case UFIND:
  321.         it = tokval(arg1);
  322.         break;
  323.     case UFAND:
  324.         it = ltos(stol(arg1) && stol(arg2));
  325.         break;
  326.     case UFOR:
  327.         it = ltos(stol(arg1) || stol(arg2));
  328.         break;
  329.     case UFLENGTH:
  330.         it = l_itoa((int)strlen(arg1));
  331.         break;
  332.     case UFUPPER:
  333.         it = mkupper(arg1);
  334.         break;
  335.     case UFLOWER:
  336.         it = mklower(arg1);
  337.         break;
  338.     case UFTRIM:
  339.         it = mktrimmed(arg1);
  340.         break;
  341.     case UFTRUTH:
  342.         /* is it the answer to everything? */
  343.         it = ltos(l_strtol(arg1) == 42);
  344.         break;
  345.     case UFASCII:
  346.         it = l_itoa((int)arg1[0]);
  347.         break;
  348.     case UFCHR:
  349.         result[0] = (char)l_strtol(arg1);
  350.         result[1] = EOS;
  351.         it = result;
  352.         break;
  353.     case UFGTKEY:
  354.         result[0] = (char)keystroke_raw8();
  355.         result[1] = EOS;
  356.         it = result;
  357.         break;
  358.     case UFGTSEQ:
  359.         (void)kcod2escape_seq(kbd_seq_nomap(), result);
  360.         it = result;
  361.         break;
  362.     case UFRND:
  363.         it = l_itoa((ernd() % absol(l_strtol(arg1))) + 1);
  364.         break;
  365.     case UFABS:
  366.         it = l_itoa(absol(l_strtol(arg1)));
  367.         break;
  368.     case UFSINDEX:
  369.         it = l_itoa(sindex(arg1, arg2));
  370.         break;
  371.     case UFENV:
  372.         it = GetEnv(arg1);
  373.         break;
  374.     case UFBIND:
  375.         it = prc2engl(arg1);
  376.         break;
  377.     case UFREADABLE:
  378.         it = ltos(doglob(arg1)
  379.             && flook(arg1, FL_HERE|FL_READABLE) != NULL);
  380.         break;
  381.     case UFWRITABLE:
  382.         it = ltos(doglob(arg1)
  383.             && flook(arg1, FL_HERE|FL_WRITEABLE) != NULL);
  384.         break;
  385.     case UFLOCMODE:
  386.     case UFGLOBMODE:
  387.         { VALARGS args;
  388.         if (find_mode(arg1, (fnum == UFGLOBMODE), &args) != TRUE)
  389.             break;
  390.         it = string_mode_val(&args);
  391.         }
  392.         break;
  393.     default:
  394.         it = errorm;
  395.         break;
  396.     }
  397.     return it;
  398. }
  399.  
  400. static const char *
  401. gtusr(            /* look up a user var's value */
  402. const char *vname)    /* name of user variable to fetch */
  403. {
  404.     register UVAR    *p;
  405.  
  406.     if (vname[0] != EOS) {
  407.         for (p = user_vars; p != 0; p = p->next)
  408.             if (!strcmp(vname, p->u_name))
  409.                 return p->u_value;
  410.     }
  411.     return (errorm);
  412. }
  413.  
  414. char *
  415. gtenv(const char *vname)    /* name of environment variable to retrieve */
  416. {
  417.     register int vnum;    /* ordinal number of var referenced */
  418.     register char *value = errorm;
  419.     BUFFER *bp;
  420.  
  421.     if (vname[0] != EOS) {
  422.  
  423.         /* scan the list, looking for the referenced name */
  424.         for (vnum = 0; envars[vnum] != 0; vnum++)
  425.             if (strcmp(vname, envars[vnum]) == 0)
  426.                 break;
  427.  
  428.         /* return errorm on a bad reference */
  429.         if (envars[vnum] == 0) {
  430. #if !SMALLER
  431.             VALARGS    args;
  432.  
  433.             if (is_mode_name(vname, TRUE, &args) == TRUE)
  434.                 value = string_mode_val(&args);
  435. #endif
  436.             return (value);
  437.         }
  438.  
  439.  
  440.         /* otherwise, fetch the appropriate value */
  441.  
  442.         /* NOTE -- if you get a compiler error from this code, find
  443.             the definitions of If and ElseIf up above, and add your
  444.             system to the set of those with broken compilers that need
  445.             to use ifs instead of a switch statement */
  446.  
  447.         If( EVPAGELEN )        value = l_itoa(term.t_nrow);
  448.         ElseIf( EVCURCOL )    value = l_itoa(getccol(FALSE) + 1);
  449.         ElseIf( EVCURLINE )    value = l_itoa(getcline());
  450. #if OPT_RAMSIZE
  451.         ElseIf( EVRAM )        value = l_itoa((int)(envram / 1024l));
  452. #endif
  453.         ElseIf( EVFLICKER )    value = ltos(flickcode);
  454.         ElseIf( EVCURWIDTH )    value = l_itoa(term.t_ncol);
  455.         ElseIf( EVBCHARS )
  456.             bsizes(curbp);
  457.             value = l_itoa(curbp->b_bytecount);
  458.         ElseIf( EVBLINES )
  459.             bsizes(curbp);
  460.             value = l_itoa(curbp->b_linecount);
  461.         ElseIf( EVCBUFNAME )    value = curbp->b_bname;
  462.         ElseIf( EVABUFNAME )    value = ((bp = find_alt()) != 0)
  463.                         ? bp->b_bname
  464.                         : "";
  465.         ElseIf( EVCFNAME )    value = curbp ? curbp->b_fname : "";
  466.         ElseIf( EVSRES )    value = sres;
  467.         ElseIf( EVDEBUG )    value = ltos(macbug);
  468.         ElseIf( EVSTATUS )    value = ltos(cmdstatus);
  469.         ElseIf( EVPALETTE )    value = tb_values(palstr);
  470.         ElseIf( EVLASTKEY )    value = l_itoa(lastkey);
  471.         ElseIf( EVCURCHAR )
  472.             if (curbp && !is_empty_buf(curbp)) {
  473.                 value = is_at_end_of_line(DOT)
  474.                     ? l_itoa('\n')
  475.                     : l_itoa(char_at(DOT));
  476.             }
  477.  
  478.         ElseIf( EVDISCMD )    value = ltos(discmd);
  479.         ElseIf( EVPATCHLEVEL )    value = PATCHLEVEL;
  480.         ElseIf( EVVERSION )    value = version;
  481.         ElseIf( EVPROGNAME )    value = prognam;
  482.         ElseIf( EVOS )        value = opersys;
  483.         ElseIf( EVSEED )    value = l_itoa(seed);
  484.         ElseIf( EVDISINP )    value = ltos(disinp);
  485.         ElseIf( EVWLINES )    value = l_itoa(curwp->w_ntrows);
  486.         ElseIf( EVCWLINE )    value = l_itoa(getwpos());
  487.         ElseIf( EVFWD_SEARCH )    value = ltos(last_srch_direc == FORWARD);
  488.         ElseIf( EVSEARCH )    value = pat;
  489.         ElseIf( EVREPLACE )    value = rpat;
  490.         ElseIf( EVMATCH )    value = (patmatch == NULL) ?
  491.                             "" : patmatch;
  492.         ElseIf( EVMODE )    value = current_modename();
  493.         ElseIf( EVEOC )        value = l_itoa(ev_end_of_cmd ? 1 : 0);
  494. #if OPT_MLFORMAT
  495.         ElseIf( EVMLFORMAT )
  496.             if (modeline_format == 0)
  497.                 mlwrite("BUG: modeline_format uninitialized");
  498.             value = modeline_format;
  499. #endif
  500.  
  501.         ElseIf( EVMODIFIED )    value = ltos(curbp && b_is_changed(curbp));
  502.         ElseIf( EVKILL )    value = getkill();
  503.         ElseIf( EVTPAUSE )    value = l_itoa(term.t_pause);
  504.         ElseIf( EVPENDING )    value = ltos(keystroke_avail());
  505.         ElseIf( EVLLENGTH )    value = l_itoa(llength(DOT.l));
  506. #if OPT_MAJORMODE
  507.         ElseIf( EVMAJORMODE )    value = (curbp->majr != 0)
  508.                         ? curbp->majr->name
  509.                         : "";
  510. #endif
  511.         ElseIf( EVLINE )    value = getctext((CHARTYPE)0);
  512.         ElseIf( EVWORD )    value = getctext(vl_nonspace);
  513.         ElseIf( EVIDENTIF )    value = getctext(vl_ident);
  514.         ElseIf( EVQIDENTIF )    value = getctext(vl_qident);
  515.         ElseIf( EVPATHNAME )    value = getctext(vl_pathn);
  516. #if SYS_UNIX
  517.         ElseIf( EVPROCESSID )    value = l_itoa(getpid());
  518. #endif
  519. #if OPT_SHELL
  520.         ElseIf( EVCWD )        value = current_directory(FALSE);
  521.         ElseIf( EVOCWD )    value = previous_directory();
  522. #endif
  523. #if OPT_PROCEDURES
  524.         ElseIf( EVCDHOOK )    value = cdhook;
  525.         ElseIf( EVRDHOOK )    value = readhook;
  526.         ElseIf( EVWRHOOK )    value = writehook;
  527.         ElseIf( EVBUFHOOK )    value = bufhook;
  528.         ElseIf( EVEXITHOOK )    value = exithook;
  529. #endif
  530. #if SYS_WINNT && defined(DISP_NTWIN)
  531.         ElseIf( EVFONT )    value = ntwinio_current_font();
  532. #endif
  533. #if OPT_SHELL
  534. #if DISP_X11
  535.         ElseIf( EVFONT )    value = x_current_fontname();
  536.         ElseIf( EVTITLE )    value = x_get_window_name();
  537.         ElseIf( EVICONNAM )    value = x_get_icon_name();
  538.         ElseIf( EVXDISPLAY )
  539.             if (x_display == 0)
  540.                 SetEnv(&x_display, DftEnv("DISPLAY", "unix:0"));
  541.             value = x_display;
  542.         ElseIf( EVXSHELL )
  543.             if (x_shell == 0)
  544.                 SetEnv(&x_shell, DftEnv("XSHELL", "xterm"));
  545.             value = x_shell;
  546. #endif
  547.         ElseIf( EVSHELL )
  548.             value = get_shell();
  549.  
  550.         ElseIf( EVDIRECTORY )
  551.             if (directory == 0)
  552.                 SetEnv(&directory, DftEnv("TMP", P_tmpdir));
  553.             value = directory;
  554. #endif
  555.  
  556.         ElseIf( EVHELPFILE )    value = helpfile;
  557.  
  558.         ElseIf( EVSTARTUP_FILE ) value = startup_file;
  559.  
  560.         ElseIf( EVSTARTUP_PATH ) value = startup_path;
  561.  
  562. #if OPT_COLOR
  563.         ElseIf( EVNCOLORS )    value = l_itoa(ncolors);
  564. #endif
  565.  
  566.         ElseIf( EVNTILDES )    value = l_itoa(ntildes);
  567.  
  568.         EndIf
  569.     }
  570.     if (value == 0)
  571.         value = errorm;
  572.     return value;
  573. }
  574.  
  575. static char *
  576. getkill(void)        /* return some of the contents of the kill buffer */
  577. {
  578.     register SIZE_T size;    /* max number of chars to return */
  579.     static char value[NSTRING];    /* temp buffer for value */
  580.  
  581.     if (kbs[0].kbufh == NULL)
  582.         /* no kill buffer....just a null string */
  583.         value[0] = EOS;
  584.     else {
  585.         /* copy in the contents... */
  586.         if (kbs[0].kused < NSTRING)
  587.             size = kbs[0].kused;
  588.         else
  589.             size = NSTRING - 1;
  590.         (void)strncpy(value, (char *)(kbs[0].kbufh->d_chunk), size);
  591.         value[size] = EOS;
  592.     }
  593.  
  594.     /* and return the constructed value */
  595.     return(value);
  596. }
  597.  
  598. static void
  599. FindVar(        /* find a variables type and name */
  600. char *var,        /* name of var to get */
  601. VDESC *vd)        /* structure to hold type and ptr */
  602. {
  603.     register UVAR *p;
  604.     register int vnum;    /* subscript in variable arrays */
  605.     register int vtype;    /* type to return */
  606.  
  607. fvar:
  608.     vtype = vnum = ILLEGAL_NUM;
  609.     vd->v_ptr = 0;
  610.  
  611.     if (!var[1]) {
  612.         vd->v_type = vtype;
  613.         return;
  614.     }
  615.     switch (var[0]) {
  616.  
  617.         case '$': /* check for legal enviromnent var */
  618.             for (vnum = 0; envars[vnum] != 0; vnum++)
  619.                 if (strcmp(&var[1], envars[vnum]) == 0) {
  620.                     vtype = TKENV;
  621.                     break;
  622.                 }
  623. #if !SMALLER
  624.             if (vtype == ILLEGAL_NUM) {
  625.                 VALARGS    args;
  626.  
  627.                 if (is_mode_name(&var[1], TRUE, &args) == TRUE) {
  628.                     vnum  = MODE_NUM;
  629.                     vtype = TKENV;
  630.                 }
  631.             }
  632. #endif
  633.             break;
  634.  
  635.         case '%': /* check for existing legal user variable */
  636.             for (p = user_vars; p != 0; p = p->next)
  637.                 if (!strcmp(var+1, p->u_name)) {
  638.                     vtype = TKVAR;
  639.                     vnum  = USER_NUM;
  640.                     vd->v_ptr = p;
  641.                     break;
  642.                 }
  643.             if (vd->v_ptr == 0) {
  644.                 if ((p = typealloc(UVAR)) != 0
  645.                  && (p->u_name = strmalloc(var+1)) != 0) {
  646.                     p->next    = user_vars;
  647.                     p->u_value = 0;
  648.                     user_vars  = vd->v_ptr = p;
  649.                     vtype = TKVAR;
  650.                     vnum  = USER_NUM;
  651.                 }
  652.             }
  653.             break;
  654.  
  655.         case '&':    /* indirect operator? */
  656.             if (strncmp(var, "&ind", FUNC_NAMELEN) == 0) {
  657.                 /* grab token, and eval it */
  658.                 execstr = token(execstr, var, EOS);
  659.                 (void)strcpy(var, tokval(var));
  660.                 goto fvar;
  661.             }
  662.     }
  663.  
  664.     /* return the results */
  665.     vd->v_num = vnum;
  666.     vd->v_type = vtype;
  667. }
  668.  
  669. /*
  670.  * Handles name-completion for variables.  Note that since the first character
  671.  * can be either a '$' or '%', we'll postpone name-completion until we've seen
  672.  * a '$'.
  673.  */
  674. static int
  675. vars_complete(
  676. int    c,
  677. char    *buf,
  678. unsigned *pos)
  679. {
  680.     int    status;
  681.     if (buf[0] == '$') {
  682.         *pos -= 1;    /* account for leading '$', not in tables */
  683.         status = kbd_complete(FALSE, c, buf+1, pos,
  684.                 (const char *)list_of_modes(), sizeof(char *));
  685.         *pos += 1;
  686.     } else {
  687.         if (c != NAMEC) /* cancel the unget */
  688.             unkeystroke(c);
  689.         status = TRUE;
  690.     }
  691.     return status;
  692. }
  693.  
  694. int
  695. setvar(int f, int n)        /* set a variable */
  696.     /* note: numeric arg can overide prompted value */
  697. {
  698.     register int status;    /* status return */
  699.     static TBUFF *var;
  700.  
  701.     /* first get the variable to set.. */
  702.     if (var == 0)
  703.         tb_scopy(&var, "");
  704.     status = kbd_reply("Variable to set: ", &var,
  705.         mode_eol, '=', KBD_NOEVAL|KBD_LOWERC, vars_complete);
  706.     if (status != TRUE)
  707.         return(status);
  708.     return PromptAndSet(tb_values(var), f, n);
  709. }
  710.  
  711. static int
  712. PromptAndSet(const char *name, int f, int n)
  713. {
  714.     register int status;    /* status return */
  715.     VDESC vd;        /* variable num/type */
  716.     char var[NLINE];
  717.     char prompt[NLINE];
  718.     char value[NLINE];    /* value to set variable to */
  719.  
  720.     /* check the legality and find the var */
  721.     FindVar(strcpy(var, name), &vd);
  722.  
  723.     /* if its not legal....bitch */
  724.     if (vd.v_type == ILLEGAL_NUM) {
  725.         mlforce("[No such variable as '%s']", var);
  726.         return(FALSE);
  727.     } else if (vd.v_type == TKENV && vd.v_num == MODE_NUM) {
  728.         VALARGS    args;
  729.         (void)find_mode(var+1, -TRUE, &args);
  730.         set_end_string('=');
  731.         return adjvalueset(var+1, TRUE, -TRUE, &args);
  732.     }
  733.  
  734.     /* get the value for that variable */
  735.     if (f == TRUE)
  736.         (void)strcpy(value, l_itoa(n));
  737.     else {
  738.         value[0] = EOS;
  739.         (void)lsprintf(prompt, "Value of %s: ", var);
  740.         status = mlreply(prompt, value, sizeof(value));
  741.         if (status != TRUE)
  742.             return(status);
  743.     }
  744.  
  745.     /* and set the appropriate value */
  746.     status = SetVarValue(&vd, value);
  747.  
  748.     if (status == ABORT)
  749.         mlforce("[Variable %s is readonly]", var);
  750.     else if (status != TRUE)
  751.         mlforce("[Cannot set %s to %s]", var, value);
  752.     /* and return it */
  753.     return(status);
  754. }
  755.  
  756. int
  757. stenv(const char *name, const char *value)
  758. {
  759.     register int status;    /* status return */
  760.     VDESC vd;        /* variable num/type */
  761.     char var[NLINE];
  762.  
  763.     /* check the legality and find the var */
  764.     var[0] = '$';
  765.     strcpy(var+1, name);
  766.     FindVar(var, &vd);
  767.     if (vd.v_type == ILLEGAL_NUM) {
  768.         return(FALSE);
  769.     }
  770.     /* and set the appropriate value */
  771.     status = SetVarValue(&vd, value);
  772.     return status;
  773. }
  774.  
  775. /* entrypoint from modes.c, used to set environment variables */
  776. #if OPT_EVAL
  777. int
  778. set_variable(const char *name)
  779. {
  780.     char    temp[NLINE];
  781.     if (*name != '$')
  782.         (void) strcat(strcpy(temp, "$"), name);
  783.     else
  784.         (void) strcpy(temp, name);
  785.     return PromptAndSet(temp, FALSE, 0);
  786. }
  787. #endif
  788.  
  789. static int
  790. SetVarValue(    /* set a variable */
  791. VDESC *var,    /* variable to set */
  792. const char *value)    /* value to set to */
  793. {
  794.     register UVAR *vptr;
  795.     register int vnum;    /* ordinal number of var referenced */
  796.     register int vtype;    /* type of variable to set */
  797.     register int status;    /* status return */
  798.     register int c;        /* translated character */
  799.  
  800.     /* simplify the vd structure (we are gonna look at it a lot) */
  801.     vptr = var->v_ptr;
  802.     vnum = var->v_num;
  803.     vtype = var->v_type;
  804.  
  805.     /* and set the appropriate value */
  806.     status = TRUE;
  807.     switch (vtype) {
  808.     case TKVAR: /* set a user variable */
  809.         FreeIfNeeded(vptr->u_value);
  810.         if ((vptr->u_value = strmalloc(value)) == 0)
  811.             status = FALSE;
  812.         break;
  813.  
  814.     case TKENV: /* set an environment variable */
  815.         status = TRUE;    /* by default */
  816.         If( EVCURCOL )
  817.             status = gotocol(TRUE, atoi(value));
  818.  
  819.         ElseIf( EVCURLINE )
  820.             status = gotoline(TRUE, atoi(value));
  821.  
  822.         ElseIf( EVFLICKER )
  823.             flickcode = stol(value);
  824.  
  825.         ElseIf( EVCURWIDTH )
  826. #if DISP_X11 || DISP_NTWIN
  827.             gui_resize(atoi(value), term.t_nrow);
  828. #else
  829.             status = newwidth(TRUE, atoi(value));
  830. #endif
  831.  
  832.         ElseIf( EVPAGELEN )
  833. #if DISP_X11 || DISP_NTWIN
  834.             gui_resize(term.t_ncol, atoi(value));
  835. #else
  836.             status = newlength(TRUE, atoi(value));
  837. #endif
  838.  
  839.         ElseIf( EVCBUFNAME )
  840.             if (curbp) {
  841.                 set_bname(curbp, value);
  842.                 curwp->w_flag |= WFMODE;
  843.             }
  844.  
  845.         ElseIf( EVCFNAME )
  846.             if (curbp) {
  847.                 ch_fname(curbp, value);
  848.                 curwp->w_flag |= WFMODE;
  849.             }
  850.  
  851.         ElseIf( EVSRES )
  852.             status = TTrez(value);
  853.  
  854.         ElseIf( EVDEBUG )
  855.             macbug = stol(value);
  856.  
  857.         ElseIf( EVSTATUS )
  858.             cmdstatus = stol(value);
  859.  
  860.         ElseIf( EVPALETTE )
  861.             status = set_palette(value);
  862.  
  863.         ElseIf( EVLASTKEY )
  864.             lastkey = l_strtol(value);
  865.  
  866.         ElseIf( EVCURCHAR )
  867.             if (curbp == NULL || b_val(curbp,MDVIEW))
  868.                 status = rdonly();
  869.             else {
  870.                 mayneedundo();
  871.                 (void)ldelete(1L, FALSE); /* delete 1 char */
  872.                 c = l_strtol(value);
  873.                 if (c == '\n')
  874.                     status = lnewline();
  875.                 else
  876.                     status = linsert(1, c);
  877.                 (void)backchar(FALSE, 1);
  878.             }
  879.  
  880. #if OPT_CRYPT
  881.         ElseIf( EVCRYPTKEY )
  882.             if (cryptkey != 0)
  883.                 free(cryptkey);
  884.             cryptkey = strmalloc(value);
  885.             ue_crypt((char *)NULL, 0);
  886.             ue_crypt(cryptkey, strlen(cryptkey));
  887. #endif
  888.         ElseIf( EVDISCMD )
  889.             discmd = stol(value);
  890.  
  891.         ElseIf( EVSEED )
  892.             seed = atoi(value);
  893.  
  894.         ElseIf( EVDISINP )
  895.             disinp = stol(value);
  896.  
  897.         ElseIf( EVWLINES )
  898.             status = resize(TRUE, atoi(value));
  899.  
  900.         ElseIf( EVCWLINE )
  901.             status = forwline(TRUE, atoi(value) - getwpos());
  902.  
  903. #if OPT_MLFORMAT
  904.         ElseIf( EVMLFORMAT )
  905.             SetEnv(&modeline_format, value);
  906.             upmode();
  907. #endif
  908.  
  909.         ElseIf( EVFWD_SEARCH )
  910.             last_srch_direc = stol(value) ? FORWARD : REVERSE;
  911.  
  912.         ElseIf( EVSEARCH )
  913.             (void)strcpy(pat, value);
  914.             FreeIfNeeded(gregexp);
  915.             gregexp = regcomp(pat, b_val(curbp, MDMAGIC));
  916.  
  917.         ElseIf( EVREPLACE )
  918.             (void)strcpy(rpat, value);
  919.  
  920.         ElseIf( EVTPAUSE )
  921.             term.t_pause = atoi(value);
  922.  
  923.         ElseIf( EVLINE )     status = putctext((CHARTYPE)0, value);
  924.         ElseIf( EVWORD )    status = putctext(vl_nonspace, value);
  925.         ElseIf( EVIDENTIF )    status = putctext(vl_ident, value);
  926.         ElseIf( EVQIDENTIF )    status = putctext(vl_qident, value);
  927.         ElseIf( EVPATHNAME )    status = putctext(vl_pathn, value);
  928.  
  929. #if SYS_WINNT && defined(DISP_NTWIN)
  930.         ElseIf( EVFONT ) status = ntwinio_font_frm_str(value, FALSE);
  931. #endif
  932. #if OPT_SHELL
  933. #if DISP_X11
  934.         ElseIf( EVFONT ) status = x_setfont(value);
  935.         ElseIf( EVTITLE ) x_set_window_name(value);
  936.         ElseIf( EVICONNAM ) x_set_icon_name(value);
  937.         ElseIf( EVXDISPLAY ) SetEnv(&x_display, value);
  938.         ElseIf( EVXSHELL ) SetEnv(&x_shell, value);
  939. #endif
  940.         ElseIf( EVCWD )
  941.             status = set_directory(value);
  942.  
  943.         ElseIf( EVSHELL )
  944.             SetEnv(&shell, value);
  945.  
  946.         ElseIf( EVDIRECTORY )
  947.             SetEnv(&directory, value);
  948. #endif
  949.  
  950.         ElseIf( EVHELPFILE )
  951.             SetEnv(&helpfile, value);
  952.  
  953.         ElseIf( EVSTARTUP_FILE )
  954.             SetEnv(&startup_file, value);
  955.  
  956.         ElseIf( EVSTARTUP_PATH )
  957.             SetEnv(&startup_path, value);
  958.  
  959. #if OPT_PROCEDURES
  960.         ElseIf( EVCDHOOK )     (void)strcpy(cdhook, value);
  961.         ElseIf( EVRDHOOK )     (void)strcpy(readhook, value);
  962.         ElseIf( EVWRHOOK )     (void)strcpy(writehook, value);
  963.         ElseIf( EVBUFHOOK )    (void)strcpy(bufhook, value);
  964.         ElseIf( EVEXITHOOK )   (void)strcpy(exithook, value);
  965. #endif
  966.  
  967. #if OPT_COLOR
  968.         ElseIf( EVNCOLORS )    status = set_ncolors(atoi(value));
  969. #endif
  970.  
  971.         ElseIf( EVNTILDES )
  972.             ntildes = atoi(value);
  973.             if (ntildes > 100)
  974.                 ntildes = 100;
  975.  
  976.         Otherwise
  977.             /* EVABUFNAME */
  978.             /* EVBLENGTH */
  979.             /* EVPROGNAME */
  980.             /* EVPATCHLEVEL */
  981.             /* EVVERSION */
  982.             /* EVMATCH */
  983.             /* EVKILL */
  984.             /* EVPENDING */
  985.             /* EVLLENGTH */
  986.             /* EVMAJORMODE */
  987.             /* EVMODIFIED */
  988.             /* EVPROCESSID */
  989.             /* EVRAM */
  990.             /* EVMODE */
  991.             /* EVOS */
  992.             status = ABORT;    /* must be readonly */
  993.         EndIf
  994.         break;
  995.     }
  996. #if    OPT_DEBUGMACROS
  997.     /* if $debug == TRUE, every assignment will echo a statment to
  998.        that effect here. */
  999.  
  1000.     if (macbug) {
  1001.         char    outline[NLINE];
  1002.         (void)strcpy(outline, "(((");
  1003.  
  1004.         /* assignment status */
  1005.         (void)strcat(outline, ltos(status));
  1006.         (void)strcat(outline, ":");
  1007.  
  1008.         /* variable name */
  1009.         if (var->v_type == TKENV) {
  1010.             (void)strcat(outline, "&");
  1011.             (void)strcat(outline, envars[var->v_num]);
  1012.         } else if (var->v_type == TKENV) {
  1013.             (void)strcat(outline, "%");
  1014.             (void)strcat(outline, var->v_ptr->u_name);
  1015.         }
  1016.         (void)strcat(outline, ":");
  1017.  
  1018.         /* and lastly the value we tried to assign */
  1019.         (void)strcat(outline, value);
  1020.         (void)strcat(outline, ")))");
  1021.  
  1022.  
  1023.         /* write out the debug line */
  1024.         mlforce("%s",outline);
  1025.         (void)update(TRUE);
  1026.  
  1027.         /* and get the keystroke to hold the output */
  1028.         if (ABORTED(keystroke())) {
  1029.             mlforce("[Macro aborted]");
  1030.             status = FALSE;
  1031.         }
  1032.     }
  1033. #endif
  1034.     return(status);
  1035. }
  1036. #endif
  1037.  
  1038. const char *
  1039. skip_cblanks(const char *src)
  1040. {
  1041.     while (isSpace(*src))
  1042.         src++;
  1043.     return src;
  1044. }
  1045.  
  1046. const char *
  1047. skip_cstring(const char *src)
  1048. {
  1049.     return src + strlen(src);
  1050. }
  1051.  
  1052. const char *
  1053. skip_ctext(const char *src)
  1054. {
  1055.     while (*src != EOS && !isSpace(*src))
  1056.         src++;
  1057.     return src;
  1058. }
  1059.  
  1060. /* If we've #define'd const, it's because it doesn't work.  Conversely, if
  1061.  * it's not #define'd, we really need distinct string functions.
  1062.  */
  1063. #ifndef const
  1064. char *
  1065. skip_blanks(char *src)
  1066. {
  1067.     while (isSpace(*src))
  1068.         src++;
  1069.     return src;
  1070. }
  1071.  
  1072. char *
  1073. skip_string(char *src)
  1074. {
  1075.     return src + strlen(src);
  1076. }
  1077.  
  1078. char *
  1079. skip_text(char *src)
  1080. {
  1081.     while (*src != EOS && !isSpace(*src))
  1082.         src++;
  1083.     return src;
  1084. }
  1085. #endif
  1086.  
  1087. #if OPT_COLOR
  1088. void
  1089. set_ctrans(const char *thePalette)
  1090. {
  1091.     int n = 0, value;
  1092.     char *next;
  1093.  
  1094.     while (*thePalette != EOS) {
  1095.         thePalette = skip_cblanks(thePalette);
  1096.         value = (int) strtol(thePalette, &next, 0);
  1097.         if (next == thePalette)
  1098.             break;
  1099.         thePalette = next;
  1100.         ctrans[n] = value;
  1101.         if (++n >= NCOLORS)
  1102.             break;
  1103.     }
  1104. }
  1105. #endif
  1106.  
  1107. /*
  1108.  * This function is used in several terminal drivers.
  1109.  */
  1110. #if OPT_EVAL || OPT_COLOR
  1111. int
  1112. set_palette(const char *value)
  1113. {
  1114.     palstr = tb_scopy(&palstr, value);
  1115. #if OPT_COLOR
  1116.     if (term.t_setpal != null_t_setpal) {
  1117.         TTspal(tb_values(palstr));
  1118.         vile_refresh(FALSE,0);
  1119.         return TRUE;
  1120.     }
  1121.     return FALSE;
  1122. #else
  1123.     return TRUE;
  1124. #endif
  1125. }
  1126. #endif
  1127.  
  1128. /*    l_itoa:    integer to ascii string.......... This is too
  1129.         inconsistent to use the system's    */
  1130.  
  1131. char *
  1132. l_itoa(int i)        /* integer to translate to a string */
  1133. {
  1134.     static char result[INTWIDTH+1];    /* resulting string */
  1135.     (void)lsprintf(result,"%d",i);
  1136.     return result;
  1137. }
  1138.  
  1139.  
  1140. /* like strtol, but also allow character constants */
  1141. #if OPT_EVAL
  1142. static int
  1143. l_strtol(const char *s)
  1144. {
  1145.     if (s[0] == '\'' &&
  1146.         s[2] == '\'' &&
  1147.         s[3] == EOS)
  1148.         return s[1];
  1149.     return (int)strtol(s, (char **)0, 0);
  1150. }
  1151. #endif
  1152.  
  1153. int
  1154. toktyp(            /* find the type of a passed token */
  1155. const char *tokn)    /* token to analyze */
  1156. {
  1157.  
  1158.     /* no blanks!!! */
  1159.     if (tokn[0] == EOS)
  1160.         return(TKNUL);
  1161.  
  1162.     /* a numeric literal? */
  1163.     if (isDigit(tokn[0]))
  1164.         return(TKLIT);
  1165.  
  1166.     if (tokn[0] == '"')
  1167.         return(TKSTR);
  1168.  
  1169.     /* if it's any other single char, it must be itself */
  1170.     if (tokn[1] == EOS)
  1171.         return(TKCMD);
  1172.  
  1173. #if ! SMALLER
  1174.     switch (tokn[0]) {
  1175.         case '"':    return(TKSTR);
  1176.  
  1177.         case '~':    return(TKDIR);
  1178.         case '@':    return(TKARG);
  1179.         case '<':    return(TKBUF);
  1180.         case '$':    return(TKENV);
  1181.         case '%':    return(TKVAR);
  1182.         case '&':    return(TKFUN);
  1183.         case '*':    return(TKLBL);
  1184.  
  1185.         default:    return(TKCMD);
  1186.     }
  1187. #else
  1188.     return(TKCMD);
  1189. #endif
  1190. }
  1191.  
  1192. const char *
  1193. tokval(                /* find the value of a token */
  1194. const char *tokn)        /* token to evaluate */
  1195. {
  1196. #if OPT_EVAL
  1197.     register int status;    /* error return */
  1198.     register BUFFER *bp;    /* temp buffer pointer */
  1199.     register B_COUNT blen;    /* length of buffer argument */
  1200.     register int distmp;    /* temporary discmd flag */
  1201.     int    oclexec;
  1202.     static char buf[NSTRING];/* string buffer for some returns */
  1203.  
  1204.     switch (toktyp(tokn)) {
  1205.         case TKNUL:    return("");
  1206.  
  1207.         case TKARG:    /* interactive argument */
  1208.                 {
  1209.                 static char tkargbuf[NSTRING];
  1210.  
  1211.                 oclexec = clexec;
  1212.  
  1213.                 distmp = discmd;    /* echo it always! */
  1214.                 discmd = TRUE;
  1215.                 clexec = FALSE;
  1216.                 status = kbd_string(tokval(&tokn[1]), tkargbuf,
  1217.                         sizeof(buf), '\n',
  1218.                         KBD_EXPAND|KBD_QUOTES,
  1219.                         no_completion);
  1220.                 discmd = distmp;
  1221.                 clexec = oclexec;
  1222.  
  1223.                 if (status == ABORT)
  1224.                     return(errorm);
  1225.                 return(tkargbuf);
  1226.                 }
  1227.  
  1228.         case TKBUF:    /* buffer contents fetch */
  1229.  
  1230.                 /* grab the right buffer */
  1231.                 if ((bp = find_b_name(tokval(&tokn[1]))) == NULL)
  1232.                     return(errorm);
  1233.  
  1234.                 /* if the buffer is displayed, get the window
  1235.                    vars instead of the buffer vars */
  1236.                 if (bp->b_nwnd != 0) {
  1237.                     curbp->b_dot = DOT;
  1238.                 }
  1239.  
  1240.                 /* make sure we are not at the end */
  1241.                 if (is_header_line(bp->b_dot,bp))
  1242.                     return(errorm);
  1243.  
  1244.                 /* grab the line as an argument */
  1245.                 blen = llength(bp->b_dot.l);
  1246.                 if (blen > bp->b_dot.o)
  1247.                     blen -= bp->b_dot.o;
  1248.                 else
  1249.                     blen = 0;
  1250.                 if (blen > NSTRING)
  1251.                     blen = NSTRING;
  1252.                 (void)strncpy(buf,
  1253.                     bp->b_dot.l->l_text + bp->b_dot.o,
  1254.                     (SIZE_T)blen);
  1255.                 buf[blen] = (char)EOS;
  1256.  
  1257.                 /* and step the buffer's line ptr
  1258.                     ahead a line */
  1259.                 bp->b_dot.l = lforw(bp->b_dot.l);
  1260.                 bp->b_dot.o = 0;
  1261.  
  1262.                 /* if displayed buffer, reset window ptr vars*/
  1263.                 if (bp->b_nwnd != 0) {
  1264.                     DOT.l = curbp->b_dot.l;
  1265.                     DOT.o = 0;
  1266.                     curwp->w_flag |= WFMOVE;
  1267.                 }
  1268.  
  1269.                 /* and return the spoils */
  1270.                 return(buf);
  1271.  
  1272.         case TKVAR:    return(gtusr(tokn+1));
  1273.         case TKENV:    return(gtenv(tokn+1));
  1274.         case TKFUN:    return(gtfun(tokn+1));
  1275.         case TKDIR:
  1276. #if SYS_UNIX
  1277.                 return(lengthen_path(strcpy(buf,tokn)));
  1278. #else
  1279.                 return(errorm);
  1280. #endif
  1281.         case TKLBL:    return(l_itoa(gtlbl(tokn)));
  1282.         case TKLIT:    return(tokn);
  1283.         case TKSTR:    return(tokn+1);
  1284.         case TKCMD:    return(tokn);
  1285.     }
  1286.     return errorm;
  1287. #else
  1288.     return (toktyp(tokn) == TKSTR) ? tokn+1 : tokn;
  1289. #endif
  1290. }
  1291.  
  1292. /*
  1293.  * Return true if the argument is one of the strings that we accept as a
  1294.  * synonym for "true".
  1295.  */
  1296. int
  1297. is_truem(const char *val)
  1298. {
  1299.     char    temp[8];
  1300.     (void)mklower(strncpy0(temp, val, sizeof(temp)));
  1301.     return (!strcmp(temp, "yes")
  1302.        ||   !strcmp(temp, "true")
  1303.        ||   !strcmp(temp, "t")
  1304.        ||   !strcmp(temp, "y")
  1305.        ||   !strcmp(temp, "on"));
  1306. }
  1307.  
  1308. /*
  1309.  * Return true if the argument is one of the strings that we accept as a
  1310.  * synonym for "false".
  1311.  */
  1312. int
  1313. is_falsem(const char *val)
  1314. {
  1315.     char    temp[8];
  1316.     (void)mklower(strncpy0(temp, val, sizeof(temp)));
  1317.     return (!strcmp(temp, "no")
  1318.        ||   !strcmp(temp, "false")
  1319.        ||   !strcmp(temp, "f")
  1320.        ||   !strcmp(temp, "n")
  1321.        ||   !strcmp(temp, "off"));
  1322. }
  1323.  
  1324. #if OPT_EVAL || DISP_X11
  1325. int
  1326. stol(            /* convert a string to a numeric logical */
  1327. const char *val)    /* value to check for stol */
  1328. {
  1329.     /* check for logical values */
  1330.     if (is_falsem(val))
  1331.         return(FALSE);
  1332.     if (is_truem(val))
  1333.         return(TRUE);
  1334.  
  1335.     /* check for numeric truth (!= 0) */
  1336.     return((atoi(val) != 0));
  1337. }
  1338. #endif
  1339.  
  1340. #if OPT_EVAL
  1341. /* use this as a wrapper when evaluating an array index, etc., that cannot
  1342.  * be negative.
  1343.  */
  1344. static SIZE_T
  1345. s2size(char *s)
  1346. {
  1347.     int    n = atoi(s);
  1348.     if (n < 0)
  1349.         n = 0;
  1350.     return n;
  1351. }
  1352.  
  1353. /* use this to return a pointer to the string after the n-1 first characters */
  1354. static char *
  1355. s2offset(char *s, char *n)
  1356. {
  1357.     SIZE_T    len = strlen(s) + 1;
  1358.     UINT    off = s2size(n);
  1359.     if (off > len)
  1360.         off = len;
  1361.     if (off == 0)
  1362.         off = 1;
  1363.     return s + (off - 1);
  1364. }
  1365.  
  1366. LINE *
  1367. label2lp (BUFFER *bp, const char *label)
  1368. {
  1369.     LINE *glp;
  1370.     LINE *result = 0;
  1371.     size_t len = strlen(label);
  1372.  
  1373.     if (len > 1) {
  1374.         for_each_line(glp, bp) {
  1375.             int need = len + 1;
  1376.             if (glp->l_used >= need
  1377.              && glp->l_text[0] == '*'
  1378.              && !memcmp(&glp->l_text[1], label, len)) {
  1379.                 result = glp;
  1380.                 break;
  1381.             }
  1382.         }
  1383.     }
  1384.     return(result);
  1385. }
  1386.  
  1387. /* ARGSUSED */
  1388. static int
  1389. gtlbl(                /* find the line number of the given label */
  1390. const char *tokn)        /* label name to find */
  1391. {
  1392.     LINE *lp = label2lp(curbp, tokn);
  1393.     int result = 0;
  1394.  
  1395.     if (lp != 0)
  1396.         result = line_no(curbp, lp);
  1397.     return(result);
  1398. }
  1399.  
  1400. static char *
  1401. ltos(        /* numeric logical to string logical */
  1402. int val)    /* value to translate */
  1403. {
  1404.     if (val)
  1405.         return(truem);
  1406.     else
  1407.         return(falsem);
  1408. }
  1409. #endif
  1410.  
  1411. #if OPT_EVAL || !SMALLER
  1412. char *
  1413. mkupper(        /* make a string upper case */
  1414. char *str)        /* string to upper case */
  1415. {
  1416.     char *sp;
  1417.  
  1418.     sp = str;
  1419.     while (*sp) {
  1420.         if (isLower(*sp))
  1421.             *sp = toUpper(*sp);
  1422.         ++sp;
  1423.     }
  1424.     return(str);
  1425. }
  1426. #endif
  1427.  
  1428. char *
  1429. mklower(        /* make a string lower case */
  1430. char *str)        /* string to lower case */
  1431. {
  1432.     char *sp;
  1433.  
  1434.     sp = str;
  1435.     while (*sp) {
  1436.         if (isUpper(*sp))
  1437.             *sp = toLower(*sp);
  1438.         ++sp;
  1439.     }
  1440.     return(str);
  1441. }
  1442.  
  1443. char *
  1444. mktrimmed(register char *str)    /* trim whitespace */
  1445. {
  1446.     char *base = str;
  1447.     register char *dst = str;
  1448.  
  1449.     while (*str != EOS) {
  1450.         if (isSpace(*str)) {
  1451.             if (dst != base)
  1452.                 *dst++ = ' ';
  1453.             str = skip_blanks(str);
  1454.         } else {
  1455.             *dst++ = *str++;
  1456.         }
  1457.     }
  1458.     if (dst != base
  1459.      && isSpace(dst[-1]))
  1460.          dst--;
  1461.     *dst = EOS;
  1462.     return base;
  1463. }
  1464.  
  1465. int
  1466. absol(int x)        /* take the absolute value of an integer */
  1467. {
  1468.     return(x < 0 ? -x : x);
  1469. }
  1470.  
  1471. #if OPT_EVAL
  1472. static int
  1473. ernd(void)        /* returns a random integer */
  1474. {
  1475.     seed = absol(seed * 1721 + 10007);
  1476.     return(seed);
  1477. }
  1478.  
  1479. static int
  1480. sindex(            /* find pattern within source */
  1481. const char *sourc,    /* source string to search */
  1482. const char *pattern)    /* string to look for */
  1483. {
  1484.     int it = 0;        /* assume no match at all.. */
  1485.     const char *sp;        /* ptr to current position to scan */
  1486.     const char *csp;    /* ptr to source string during comparison */
  1487.     const char *cp;        /* ptr to place to check for equality */
  1488.  
  1489.     /* scanning through the source string */
  1490.     sp = sourc;
  1491.     while (*sp) {
  1492.         /* scan through the pattern */
  1493.         cp = pattern;
  1494.         csp = sp;
  1495.         while (*cp) {
  1496.             if (!eq(*cp, *csp))
  1497.                 break;
  1498.             ++cp;
  1499.             ++csp;
  1500.         }
  1501.  
  1502.         /* was it a match? */
  1503.         if (*cp == 0) {
  1504.             it = (int)(sp - sourc) + 1;
  1505.             break;
  1506.         }
  1507.         ++sp;
  1508.     }
  1509.  
  1510.     return(it);
  1511. }
  1512.  
  1513. #endif /* OPT_EVAL */
  1514.  
  1515. #if NO_LEAKS
  1516. void
  1517. ev_leaks(void)
  1518. {
  1519. #if OPT_EVAL
  1520.     register UVAR *p;
  1521.     while ((p = user_vars) != 0) {
  1522.         user_vars = p->next;
  1523.         free(p->u_value);
  1524.         free(p->u_name);
  1525.         free((char *)p);
  1526.     }
  1527.     FreeAndNull(shell);
  1528.     FreeAndNull(directory);
  1529. #if DISP_X11
  1530.     FreeAndNull(x_display);
  1531.     FreeAndNull(x_shell);
  1532. #endif
  1533. #endif
  1534. }
  1535. #endif    /* NO_LEAKS */
  1536.