home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / YADME10.LHA / YADME10 / src / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-19  |  26.5 KB  |  809 lines

  1.  
  2. /*
  3.  * COMMAND.C
  4.  *
  5.  *      (C)Copyright 1987 by Matthew Dillon, All Rights Reserved
  6.  *
  7.  * )c                single character (typing)
  8.  * 'c                single character (typing)
  9.  * `string'          string of characters w/ embedded `' allowed!
  10.  * (string)             same thing w/ embedded () allowed!
  11.  * \c                override
  12.  *
  13.  * name arg arg      command name. The arguments are interpreted as strings
  14.  *                   for the command.
  15.  *
  16.  * $scanf            macro insert scanf'd variable
  17.  * $filename         macro insert current file name
  18.  * $fname            macro insert current name part of filename
  19.  * $fpath            macro insert complete path of current filname (2.0 only) or path part of filename
  20.  * $currentline      macro insert entire contents of current line
  21.  * $colno            macro insert column number of cursor
  22.  * $lineno           macro insert line number of cursor
  23.  * $margin           macro insert current margin setting
  24.  * $modified         macro insert 0/1 modified flag
  25.  * $rexxport         macro insert rexx port name
  26.  *
  27.  * Any string arguments not part of a command are considered to be typed
  28.  * text.
  29.  */
  30.  
  31. #include "defs.h"
  32. #include <ctype.h>
  33.  
  34.  
  35. typedef struct Process PROC;
  36.  
  37. extern int foundcmd;       /* control for implicit ARexx macro invocation   */
  38. extern int cmderr;         /* global command error flag for do_rexx()'s use */
  39. extern char RexxHostName[]; /* duh... TJM */
  40.  
  41. #define CF_COK  1   /*  Can be executed while in command line mode      */
  42. #define CF_PAR  2   /*  ESCIMM special flag.. save rest of command line */
  43.                     /*  so it can be executed after user entry          */
  44.  
  45. #define CF_ICO  4   /*  OK to execute if iconified, else uniconify first*/
  46.  
  47. #define BTOCP(val, type)    ((type)((long)val << 2))
  48.  
  49. typedef void (*FPTR) ARGS((long));
  50.  
  51. typedef struct {
  52.     char *name;    /* command name       */
  53.     ubyte args;
  54.     ubyte flags;
  55.     void (*func) ARGS((long));  /* function           */
  56. } COMM;
  57.  
  58. /*============================================================================*/
  59.  
  60. /*
  61.  *  WLEFT/WRIGHT will check command line mode themselves, and thus can
  62.  *  be marked flags=1 even though they can change the line number.
  63.  *
  64.  *  No more than 255 commands may exist unless you change the type of hindex[]
  65.  *
  66.  *  Command names MUST be sorted by their first character
  67.  */
  68.  
  69. static unsigned char hindex[26];    /*  alpha hash into table   */
  70.  
  71.         /*        args flags    */
  72.  
  73. static COMM Comm[] = {
  74.     "addpath",       1, CF_COK, (FPTR)do_addpath,
  75.     "appendsave",    1, CF_COK, (FPTR)do_appendsave,
  76.     "aslfont",       0,      0, (FPTR)do_aslfont,
  77.     "aslinsfile",    0,      0, (FPTR)do_aslinsfile,
  78.     "aslload",       0,      0, (FPTR)do_aslload,
  79.     "aslsave",       0,      0, (FPTR)do_aslsave,
  80.     "back",          0, CF_COK, (FPTR)do_bs,
  81.     "backtab",       0, CF_COK, (FPTR)do_backtab,
  82.     "bappendsave",   0, CF_COK, (FPTR)do_bappendsave,
  83.     "bcopy",         0,      0, (FPTR)do_bcopy,
  84.     "bdelete",       0,      0, (FPTR)do_bdelete,
  85.     "bend",          0,      0, (FPTR)do_bend,
  86.     "bgpen",         1,      0, (FPTR)do_bgpen,
  87.     "block",         0,      0, (FPTR)do_block,    /* checks com name for mode */
  88.     "blocktype",     1,      0, (FPTR)do_blocktype,
  89.     "bmove",         0,      0, (FPTR)do_bmove,
  90.     "bottom",        0,      0, (FPTR)do_bottom,
  91.     "bs",            0, CF_COK, (FPTR)do_bs,
  92.     "bsave",         1, CF_COK, (FPTR)do_bsave,
  93.     "bsource",       0,      0, (FPTR)do_bsource,
  94.     "bstart",        0,      0, (FPTR)do_bstart,
  95.     "cd",            1, CF_COK, (FPTR)do_cd,
  96.     "chfilename",    1,      0, (FPTR)do_chfilename,
  97.     "clear",         0,      0, (FPTR)do_clear,
  98.     "col",           1, CF_COK, (FPTR)do_col,
  99.     "copy",          0,      0, (FPTR)do_copy,
  100.     "ctags",         0, CF_ICO, (FPTR)do_ctags,
  101.     "cut",           0,      0, (FPTR)do_cut,
  102.     "del",           0, CF_COK, (FPTR)do_del,
  103.     "deline",        0,      0, (FPTR)do_deline,
  104.     "down",          0,      0, (FPTR)do_down,
  105.     "downadd",       0,      0, (FPTR)do_downadd,
  106.     "downfast",      0,      0, (FPTR)do_downfast,
  107.     "esc",           0, CF_COK, (FPTR)do_esc,
  108.     "escimm",        1, CF_PAR, (FPTR)do_esc,
  109.     "execute",       1, CF_ICO, (FPTR)do_execute,
  110.     "fgpen",         1,      0, (FPTR)do_fgpen,
  111.     "find",          1,      0, (FPTR)do_find,     /* checks com name for mode */
  112.     "findfile",      1,      0, (FPTR)do_findfile,
  113.     "findmatch",     0, CF_COK, (FPTR)do_findmatch,
  114.     "findr",         2,      0, (FPTR)do_findr,    /* checks com name for mode */
  115.     "findstr",       1, CF_COK, (FPTR)do_findstr,  /* checks com name for mode */
  116.     "first",         0, CF_COK, (FPTR)do_firstcolumn,
  117.     "firstnb",       0, CF_COK, (FPTR)do_firstnb,
  118.     "goto",          1,      0, (FPTR)do_goto,
  119.     "hgbgpen",       1,      0, (FPTR)do_hgbgpen,
  120.     "hgpen",         1,      0, (FPTR)do_hgpen,
  121.     "iconify",       0, CF_ICO, (FPTR)do_iconify,
  122.     "if",            2, CF_COK, (FPTR)do_if,
  123.     "ifelse",        3, CF_COK, (FPTR)do_if,
  124.     "ignorecase",    1, CF_COK, (FPTR)do_ignorecase,
  125.     "insertmode",    1, CF_COK, (FPTR)do_insertmode,
  126.     "insfile",       1,      0, (FPTR)do_edit,
  127.     "insline",       0,      0, (FPTR)do_insline,
  128.     "join",          0,      0, (FPTR)do_join,
  129.     "join2",         0,      0, (FPTR)do_join2,
  130.     "justify",       1,      0, (FPTR)do_justify,
  131.     "last",          0, CF_COK, (FPTR)do_lastcolumn,
  132.     "left",          0, CF_COK, (FPTR)do_left,
  133.     "map",           2, CF_COK, (FPTR)do_map,
  134.     "margin",        1, CF_COK, (FPTR)do_margin,
  135.     "menuon",        0,      0, (FPTR)do_menuon,
  136.     "menuoff",       0,      0, (FPTR)do_menuoff,
  137.     "menuadd",       3,      0, (FPTR)do_menuadd,
  138.     "menudel",       2,      0, (FPTR)do_menudel,
  139.     "menudelhdr",    1,      0, (FPTR)do_menudelhdr,
  140.     "menuclear",     0,      0, (FPTR)do_menuclear,
  141.     "modified",      1,      0, (FPTR)do_modified,
  142.     "newfile",       1,      0, (FPTR)do_edit,     /* checks com name for mode */
  143.     "newwindow",     0, CF_ICO, (FPTR)do_newwindow,
  144.     "next",          0,      0, (FPTR)do_find,
  145.     "nextr",         0,      0, (FPTR)do_findr,
  146.     "noflushmem",    0,      0, (FPTR)do_noflushmem,
  147.     "null",          0, CF_COK, (FPTR)do_null,
  148.     "openwindow",    1, CF_ICO, (FPTR)do_openwindow,
  149.     "pagedown",      0,      0, (FPTR)do_page,
  150.     "pageset",       1,      0, (FPTR)do_page,
  151.     "pageup",        0,      0, (FPTR)do_page,
  152.     "paste",         0,      0, (FPTR)do_paste,
  153.     "ping",          1, CF_ICO, (FPTR)do_ping,
  154.     "pong",          1,      0, (FPTR)do_pong,
  155.     "popmark",       0,      0, (FPTR)do_popmark,
  156.     "prev",          0,      0, (FPTR)do_find,
  157.     "prevr",         0,      0, (FPTR)do_findr,
  158.     "progresswnd",   1,      0, (FPTR)do_progresswnd,
  159.     "purgemark",     0,      0, (FPTR)do_purgemark,
  160.     "pushmark",      0,      0, (FPTR)do_pushmark,
  161.     "quit",          0, CF_ICO, (FPTR)do_quit,
  162.     "recall",        0, CF_COK, (FPTR)do_recall,
  163.     "ref",           0,      0, (FPTR)do_refs,
  164.     "reformat",      0,      0, (FPTR)do_reformat,
  165.     "reload",        0,      0, (FPTR)do_reload,
  166.     "remeol",        0, CF_COK, (FPTR)do_remeol,
  167.     "rempath",       1, CF_COK, (FPTR)do_rempath,
  168.     "repeat",        2, CF_ICO|CF_COK, (FPTR)do_repeat,
  169.     "repstr",        1, CF_COK, (FPTR)do_findstr,
  170.     "reqfind",       0,      0, (FPTR)do_reqfind,
  171.     "reqfont",       0,      0, (FPTR)do_reqfont,
  172.     "reqgoto",       0,      0, (FPTR)do_reqgoto,
  173.     "reqinsfile",    0,      0, (FPTR)do_reqinsfile,
  174.     "reqload",       0,      0, (FPTR)do_reqload,
  175.     "reqmargin",     0,      0, (FPTR)do_reqmargin,
  176.     "reqparcol",     0,      0, (FPTR)do_reqparcol,
  177.     "reqreplace",    0,      0, (FPTR)do_reqreplace,
  178.     "reqsave",       0,      0, (FPTR)do_reqsave,
  179.     "reqtabstop",    0,      0, (FPTR)do_reqtabstop,
  180.     "resettoggle",   1, CF_COK, (FPTR)do_toggle,
  181.     "resize",        2,      0, (FPTR)do_resize,
  182.     "return",        0, CF_COK, (FPTR)do_return,   /* special meaning in command line mode */
  183.     "right",         0, CF_COK, (FPTR)do_right,
  184.     "rx",            1,      0, (FPTR)do_rx,       /* explicit ARexx macro invocation      */
  185.     "rx1",           2,      0, (FPTR)do_rx1,      /* explicit, with 1 arg  to ARexx macro */
  186.     "rx2",           3,      0, (FPTR)do_rx2,      /* explicit, with 2 args to ARexx macro */
  187.     "saveas",        1, CF_ICO|CF_COK, (FPTR)do_saveas,
  188.     "saveclip",      0,      0, (FPTR)do_saveclip,
  189.     "saveconfig",    0, CF_ICO|CF_COK, (FPTR)do_saveconfig,
  190.     "savemap",       1, CF_ICO|CF_COK, (FPTR)do_savemap,  /* checks com name for mode */
  191.     "saveold",       0, CF_ICO|CF_COK, (FPTR)do_save,
  192.     "savesmap",      1, CF_ICO|CF_COK, (FPTR)do_savemap,
  193.     "savetabs",      1, CF_ICO|CF_COK, (FPTR)do_savetabs,
  194.     "scanf",         1, CF_COK, (FPTR)do_scanf,
  195.     "screenbottom",  0,      0, (FPTR)do_screenbottom,
  196.     "screentop",     0,      0, (FPTR)do_screentop,
  197.     "scrollup",      0,      0, (FPTR)do_scrollup,
  198.     "scrolldown",    0,      0, (FPTR)do_scrolldown,
  199.     "set",           2, CF_ICO|CF_COK, (FPTR)do_set,
  200.     "setenv",        2, CF_ICO|CF_COK, (FPTR)do_setenv,
  201.     "setfont",       2,      0, (FPTR)do_setfont,
  202.     "setparcol",     1, CF_COK, (FPTR)do_setparcol,
  203.     "settoggle",     1, CF_COK, (FPTR)do_toggle,
  204.     "source",        1, CF_COK, (FPTR)do_source,
  205.     "split",         0,      0, (FPTR)do_split,
  206.     "swapmark",      0,      0, (FPTR)do_swapmark,
  207.     "tab",           0, CF_COK, (FPTR)do_tab,
  208.     "tabstop",       1, CF_COK, (FPTR)do_tabstop,
  209.     "title",         1,      0, (FPTR)do_title,
  210.     "tlate",         1, CF_COK, (FPTR)do_tlate,
  211.     "toggle",        1, CF_COK, (FPTR)do_toggle,
  212.     "tomouse",       0,      0, (FPTR)do_tomouse,
  213.     "top",           0,      0, (FPTR)do_top,
  214.     "tpen",          1,      0, (FPTR)do_tpen,
  215.     "unblock",       0,      0, (FPTR)do_block,
  216.     "undeline",      0,      0, (FPTR)do_undeline,
  217.     "undo",          0,      0, (FPTR)do_undo,
  218.     "unjustify",     0,      0, (FPTR)do_unjustify,
  219.     "unmap",         1, CF_ICO|CF_COK, (FPTR)do_unmap,
  220.     "unset",         1, CF_ICO|CF_COK, (FPTR)do_unset,
  221.     "unsetenv",      1, CF_ICO|CF_COK, (FPTR)do_unsetenv,
  222.     "up",            0,      0, (FPTR)do_up,
  223.     "updatetitle",   1,      0, (FPTR)do_updatetitle,
  224.     "upfast",        0,      0, (FPTR)do_upfast,
  225.     "while",         2, CF_ICO|CF_COK, (FPTR)do_if,
  226.     "window",        1,      0, (FPTR)do_window,
  227.     "wleft",         0, CF_COK, (FPTR)do_wleft,
  228.     "wordwrap",      1, CF_COK, (FPTR)do_wordwrap,
  229.     "wright",        0, CF_COK, (FPTR)do_wright,
  230.     NULL, 0, 0, NULL
  231. };
  232.  
  233. void init_command(void)
  234. {
  235.     short hi;
  236.     COMM *comm;
  237.  
  238.     hi = sizeof(Comm)/sizeof(Comm[0]) - 2;
  239.     comm = Comm + hi;
  240.  
  241.     while (hi >= 0) {
  242.         hindex[comm->name[0] - 'a'] = hi;
  243.         --hi;
  244.         --comm;
  245.     }
  246. }
  247.  
  248. #define MAXIA   5
  249.  
  250. int do_command(char *str)
  251. {
  252.     char *arg;
  253.     char *aux1, *aux2;
  254.     char *repstr[MAXIA];
  255.     char quoted;
  256.     short repi = 0;
  257.     short i, j;
  258.     static int level;
  259.  
  260.     if (++level > 20) {
  261.         title("Recursion Too Deep!");
  262.         --level;
  263.         foundcmd = 1;   /* to prevent us from trying an ARexx macro */
  264.         return(0);
  265.     }
  266.     while (arg = breakout(&str, "ed, &aux1)) {
  267.         if (quoted) {
  268.             if (Ep->iconmode)
  269.                 uniconify();
  270.             text_write(arg);
  271.             foundcmd = 1;               /* MMW 1.45 */
  272.             goto loop;
  273.         }
  274.         for (i = 0; arg[i]; ++i)
  275.         {
  276.             if (isupper(arg[i]))
  277.                 arg[i] += 'a' - 'A';
  278.         }
  279.  
  280.         if (islower(arg[0]))
  281.         {
  282.             COMM *comm = &Comm[hindex[arg[0]-'a']];
  283.             for (; comm->name && comm->name[0] == arg[0]; ++comm) {
  284.                 if (strcmp(arg, comm->name) == 0) {
  285.                     foundcmd = 1;
  286.                     av[0] = (ubyte *)comm->name;
  287.                     for (j = 1; j <= comm->args; ++j) {
  288.                         av[j] = (ubyte *)breakout(&str, "ed, &aux2);
  289.                         if (aux2) {
  290.                             if (repi == MAXIA) {
  291.                                 free(aux2);
  292.                                 title("Command too complex");
  293.                                 goto fail;
  294.                             } else {
  295.                                 repstr[repi++] = aux2;
  296.                             }
  297.                         }
  298.                         if (!av[j]) {
  299.                             title("Bad argument");
  300.                             goto fail;
  301.                         }
  302.                     }
  303.                     av[j] = NULL;   /* end of arglist */
  304.                     if ((comm->flags & CF_COK) || !Comlinemode) {
  305.                         if (comm->flags & CF_PAR) {
  306.                             if (Partial)
  307.                                 free(Partial);
  308.                             Partial = (char *)malloc(strlen(str)+1);
  309.                             strcpy(Partial, str);
  310.                             str += strlen(str);     /*  skip string */
  311.                         }
  312.                         if (Ep->iconmode && !(comm->flags & CF_ICO))
  313.                             uniconify();
  314.                         (*comm->func)(-1);
  315.                     }
  316.                     if (Abortcommand)
  317.                         goto fail;
  318.                     goto loop;
  319.                 }
  320.             }
  321.         }
  322.  
  323.         /* Command not found, check for macro   */
  324.  
  325.         {
  326.             char *str;
  327.             int ret;
  328.             if ((str = keyspectomacro(arg)) || (str = menutomacro(arg))) {
  329.                 str = (char *)strcpy(malloc(strlen(str)+1), str);
  330.                 ret = do_command(str);
  331.                 free(str);
  332.                 if (ret) {
  333.                     foundcmd = 1;   /* dunno about this yet for ARexx macros */
  334.                     goto loop;
  335.                 }
  336.                 goto fail;
  337.             }
  338.         }
  339.  
  340.         /* Command still not found, check for public macro  */
  341.         /* code to be added */
  342.  
  343.         do_rxImplied(arg, str);
  344. fail:
  345.         --level;
  346.         while (--repi >= 0)
  347.             free(repstr[repi]);
  348.         if (aux1)
  349.             free(aux1);
  350.         return(0);
  351. loop:
  352.         if (aux1)
  353.             free(aux1);
  354.     }
  355.     --level;
  356.     while (--repi >= 0)
  357.         free(repstr[repi]);
  358.     return(1);
  359. }
  360.  
  361. void do_null(void)
  362. {
  363. }
  364.  
  365. void do_source(void)
  366. {
  367.     char buf[256];
  368.     FILE *fi;
  369.     char *str;
  370.     BPTR oldlock = CurrentDir(DupLock((BPTR)Ep->dirlock));
  371.  
  372.     if (fi = fopen(av[1], "r")) {
  373.         setvbuf(fi, NULL, _IOFBF, 8192);  /* KL */
  374.         while (fgets(buf, 256, fi)) {
  375.             if (buf[0] == '#')
  376.                 continue;
  377.             for (str = buf; *str; ++str) {
  378.                 if (*str == 9)
  379.                     *str = ' ';
  380.             }
  381.             if (str > buf && str[-1] == '\n')
  382.                 str[-1] = 0;
  383.             do_command(buf);
  384.         }
  385.         fclose(fi);
  386.     } else {
  387.         if (av[0])
  388.             title("File not found");
  389.     }
  390.     UnLock(CurrentDir(oldlock));
  391. }
  392.  
  393.  
  394. void do_quit(void)
  395. {
  396.     extern char Quitflag;
  397.  
  398.     Quitflag = 1;
  399. }
  400.  
  401. void do_execute(void)
  402. {
  403.     BPTR oldlock = CurrentDir((BPTR)Ep->dirlock);
  404.     BPTR NilFH = Open("null:", 1006);
  405.     PROC *proc = (PROC *)FindTask(NULL);
  406.  
  407.     if (NilFH) {
  408.         void *oldConsoleTask = proc->pr_ConsoleTask;
  409.         proc->pr_ConsoleTask = (APTR)BTOCP(NilFH, struct FileHandle *)->fh_Port;
  410.         Execute(av[1], NilFH, NilFH);
  411.         proc->pr_ConsoleTask = oldConsoleTask;
  412.         Close(NilFH);
  413.     } else {
  414.         title("NULL: device required for (execute)");
  415.     }
  416.     CurrentDir(oldlock);
  417. }
  418.  
  419. /*
  420.  * repeat X command
  421.  *
  422.  * Since repeat takes up 512+ stack, it should not be nested more than
  423.  * twice.
  424.  *
  425.  * (if X is not a number it can be abbr. with 2 chars)
  426.  *
  427.  * X =  N     -number of repeats
  428.  *      line  -current line # (lines begin at 1)
  429.  *      lbot  -#lines to the bottom, inc. current
  430.  *      cleft -column # (columns begin at 0)
  431.  *              (thus is also chars to the left)
  432.  *      cright-#chars to eol, including current char
  433.  *      tr    -#char positions to get to next tab stop
  434.  *      tl    -#char positions to get to next backtab stop
  435.  */
  436.  
  437. #define SC(a,b) ((a)<<8|(b))
  438.  
  439. void do_repeat(void)
  440. {
  441.     ubyte *ptr = av[1];
  442.     unsigned long n;
  443.     char buf1[256];
  444.     char buf2[256];
  445.  
  446.     breakreset();
  447.     strcpy(buf1, av[2]);
  448.     switch((ptr[0]<<8)+ptr[1]) {
  449.     case SC('l','i'):
  450.         n = text_lineno();
  451.         break;
  452.     case SC('l','b'):
  453.         n = text_lines() - text_lineno() + 1;
  454.         break;
  455.     case SC('c','l'):
  456.         n = text_colno();
  457.         break;
  458.     case SC('c','r'):
  459.         n = text_cols() - text_colno();
  460.         break;
  461.     case SC('t','r'):
  462.         n = text_tabsize()-(text_colno() % text_tabsize());
  463.         break;
  464.     case SC('t','l'):
  465.         n = text_colno() % text_tabsize();
  466.         if (n == 0)
  467.             n = text_tabsize();
  468.         break;
  469.     default:
  470.         n = atoi(av[1]);
  471.         break;
  472.     }
  473.     while (n > 0) {
  474.         strcpy(buf2, buf1);
  475.         if (do_command(buf2) == 0 || breakcheck()) {
  476.             Abortcommand = 1;
  477.             break;
  478.         }
  479.         --n;
  480.     }
  481. }
  482.  
  483. /*
  484.  *  BREAKOUT()
  485.  *
  486.  *  Break out the next argument.  The argument is space delimited and
  487.  *  might be quoted with `' or (), or single quoted as 'c or )c
  488.  *
  489.  *  Also:       $var        -variable insertion
  490.  *              ^c          -control character
  491.  */
  492.  
  493. char *breakout(char **ptr, char *quoted, char **paux)
  494. {
  495.     char *str = *ptr;
  496.     char *base;
  497.     short count;
  498.     char opc;
  499.     char clc;
  500.     char immode;
  501.     char isaux;
  502.     char buf[256];
  503.     short di;
  504.  
  505.     {
  506.         short z = 0;
  507.  
  508.         count = z;
  509.         opc   = z;
  510.         clc   = z;
  511.         immode= z;
  512.         isaux = z;
  513.         di    = z;
  514.     }
  515.  
  516.     *quoted = 0;
  517.     *paux = NULL;
  518.     while (*str == ' ')
  519.         ++str;
  520.     if (!*str)
  521.         return(NULL);
  522.  
  523.     *ptr = str;
  524.     base = str;
  525.     while (*str) {
  526.         if (immode) {
  527.             if (di != sizeof(buf)-1)
  528.                 buf[di++] = *str;
  529.             ++str;
  530.             continue;
  531.         }
  532.         if (count == 0) {
  533.             if (*str == ' ')
  534.                 break;
  535.             if (*str == '\'' || *str == ')')
  536.                 clc = *str;
  537.             if (*str == '`') {
  538.                 opc = '`';
  539.                 clc = '\'';
  540.             }
  541.             if (*str == '(') {
  542.                 opc = '(';
  543.                 clc = ')';
  544.             }
  545.         }
  546.         if (*str == opc) {
  547.             ++count;
  548.             if (str == *ptr) {
  549.                 *quoted = 1;
  550.                 base = ++str;
  551.                 continue;
  552.             }
  553.         }
  554.         if (*str == clc) {
  555.             --count;
  556.             if (count == 0 && *quoted)     /*  end of argument     */
  557.                 break;
  558.             if (str == *ptr && count < 0) {
  559.                 immode = 1;
  560.                 *quoted = 1;
  561.                 base = ++str;
  562.                 continue;
  563.             }
  564.         }
  565.  
  566.         /*
  567.          *  $varname $(varname) $`varname'.  I.E. three forms are allowed,
  568.          *  which allows one to insert the string almost anywhere.  The
  569.          *  first form names are limited to alpha-numerics, '-', and '_'.
  570.          */
  571.  
  572.         if (*str == '$') {
  573.             char *ptr;
  574.             char *tmpptr;
  575.             char c, ce;
  576.             short len;
  577.  
  578.             ce = 0;                         /*  first form  */
  579.             ++str;                          /*  skip $      */
  580.             if (*str == '(') {              /*  second form */
  581.                 ce = ')';
  582.                 ++str;
  583.             } else if (*str == '`') {       /*  third form  */
  584.                 ce = '\'';
  585.                 ++str;
  586.             }
  587.             ptr = str;                      /*  start of varname    */
  588.             if (ce) {                       /*  until end char OR   */
  589.                 while (*ptr && *ptr != ce)
  590.                     ++ptr;
  591.             } else {                        /*  smart end-varname   */
  592.                 while (isalnum(*ptr) ||
  593.                         *ptr == '-' || *ptr == '_' ) {
  594.                     ++ptr;
  595.                 }
  596.             }
  597.             len = ptr - str;                /*  length of variable  */
  598.  
  599.             c = *ptr; *ptr = 0;             /*  temp. terminate \0  */
  600.             if (strcmp(str, "scanf") == 0) {
  601.                 *ptr = c;
  602.                 isaux = 1;
  603.                 if (di + strlen(String) < sizeof(buf)-1) {
  604.                     strcpy(buf + di, String);
  605.                     di += strlen(buf + di);
  606.                 }
  607.                 str += len;                 /*  next string pos     */
  608.                 if (ce)
  609.                     ++str;
  610.                 continue;
  611.             }
  612.             if (strcmp(str, "fpath") == 0) {
  613.                 short i;
  614.                 for (i = strlen(Ep->Name); i >= 0; --i) {
  615.                     if (Ep->Name[i] == ':' || Ep->Name[i] == '/')
  616.                         break;
  617.                 }
  618.                 ++i;
  619.                 *ptr = c;
  620.                 isaux = 1;
  621.                 if (di + i < sizeof(buf)-1) {
  622.                     movmem(Ep->Name, buf + di, i);
  623.                     buf[di+i] = 0;
  624.                     /* KLUDGE ALERT! */ /* copied from asl stuff... */
  625.                     if(FReq){ /* if os >= 2.0, attempt to fully expand path */
  626.                         BPTR oldlock = CurrentDir(Ep->dirlock);
  627.                         BPTR lock = Lock(buf+di,ACCESS_READ);
  628.                         if (lock) {
  629.                             if (NameFromLock(lock, buf+di, sizeof(buf)-1-di)!=DOSTRUE) {
  630.                                 movmem(Ep->Name, buf + di, i);
  631.                                 buf[di+i] = 0;
  632.                             }
  633.                             else {
  634.                                 i = strlen(buf+di);
  635.                                 if(buf[di+i-1] != '/' && buf[di+i-1] != ':' && di+i+1 < sizeof(buf)-1) {
  636.                                     buf[di+i] = '/';
  637.                                     buf[di+(++i)] = 0;
  638.                                 }
  639.                             }
  640.                             UnLock(lock);
  641.                         }
  642.                         CurrentDir(oldlock);
  643.                     }
  644.                     di += i;
  645.                 }
  646.                 str += len;
  647.                 if (ce)
  648.                     ++str;
  649.                 continue;
  650.             }
  651.             if (strcmp(str, "fname") == 0) {
  652.                 short i;
  653.                 short j;
  654.                 for (i = strlen(Ep->Name); i >= 0; --i) {
  655.                     if (Ep->Name[i] == ':' || Ep->Name[i] == '/')
  656.                         break;
  657.                 }
  658.                 ++i;
  659.                 j = strlen(Ep->Name + i);
  660.                 *ptr = c;
  661.                 isaux = 1;
  662.                 if (di + j < sizeof(buf)-1) {
  663.                     movmem(Ep->Name + i, buf + di, j);
  664.                     di += j;
  665.                     buf[di] = 0;
  666.                 }
  667.                 str += len;
  668.                 if (ce)
  669.                     ++str;
  670.                 continue;
  671.             }
  672.             if (strcmp(str, "filename") == 0) {
  673.                 *ptr = c;
  674.                 isaux = 1;
  675.                 if (di + strlen(Ep->Name) < sizeof(buf)-1) {
  676.                     strcpy(buf + di, Ep->Name);
  677.                     di += strlen(buf + di);
  678.                 }
  679.                 str += len;
  680.                 if (ce)
  681.                     ++str;
  682.                 continue;
  683.             }
  684.             if (strcmp(str, "colno") == 0) {
  685.                 *ptr = c;
  686.                 isaux = 1;
  687.                 if (di < sizeof(buf)-8) {
  688.                     sprintf(buf + di, "%ld", Ep->Column + 1);
  689.                     di += strlen(buf + di);
  690.                 }
  691.                 str += len;
  692.                 if (ce)
  693.                     ++str;
  694.                 continue;
  695.             }
  696.             if (strcmp(str, "lineno") == 0) {
  697.                 *ptr = c;
  698.                 isaux = 1;
  699.                 if (di < sizeof(buf)-8) {
  700.                     sprintf(buf + di, "%ld", Ep->Line + 1);
  701.                     di += strlen(buf + di);
  702.                 }
  703.                 str += len;
  704.                 if (ce)
  705.                     ++str;
  706.                 continue;
  707.             }
  708.             if (strcmp(str, "margin") == 0) {                       /* MMW */
  709.                 *ptr = c;
  710.                 isaux = 1;
  711.                 if (di < sizeof(buf)-8) {
  712.                     sprintf(buf + di, "%ld", Ep->Margin);
  713.                     di += strlen(buf + di);
  714.                 }
  715.                 str += len;
  716.                 if (ce)
  717.                     ++str;
  718.                 continue;
  719.             }
  720.             if (strcmp(str, "modified") == 0) {                       /* MMW */
  721.                 *ptr = c;
  722.                 isaux = 1;
  723.                 if (di < sizeof(buf)-8) {
  724.                     sprintf(buf + di, "%ld", Ep->Modified ? 1 : 0);
  725.                     di += strlen(buf + di);
  726.                 }
  727.                 str += len;
  728.                 if (ce)
  729.                     ++str;
  730.                 continue;
  731.             }
  732.             if (strcmp(str, "currentline") == 0) {
  733.                 short i;
  734.  
  735.                 *ptr = c;
  736.                 isaux = 1;
  737.                 if (di < sizeof(buf)-8) {
  738.                     for (i = strlen(Current) - 1; i >= 0 && Current[i] == ' '; --i);
  739.                     ++i;
  740.                     if (i > 0)
  741.                         strncpy(buf + di, Current, i);
  742.                     *(buf + di + i) = 0;
  743.                     di += strlen(buf + di);
  744.                 }
  745.                 str += len;
  746.                 if (ce)
  747.                     ++str;
  748.                 continue;
  749.             }
  750.             if (!strcmp(str, "rexxport")) {         /* TJM */
  751.                 *ptr = c;
  752.                 isaux = 1;
  753.                 if (di + strlen(RexxHostName) < sizeof(buf)-1) {
  754.                     strcpy(buf + di, RexxHostName);
  755.                     di += strlen(buf + di);
  756.                 }
  757.                 str += len;
  758.                 if (ce)
  759.                     ++str;
  760.                 continue;
  761.             }
  762.  
  763.             if (tmpptr = getvar(str)) {
  764.                 ptr = tmpptr;
  765.                 str[len] = c;
  766.                 isaux = 1;
  767.                 if (di + strlen(ptr) < sizeof(buf)-1) {
  768.                     strcpy(buf + di, ptr);
  769.                     di += strlen(buf + di);
  770.                 }
  771.                 str += len;
  772.                 if (ce)
  773.                     ++str;
  774.                 free(ptr);
  775.                 continue;
  776.             }
  777.             *ptr = c;
  778.             --str;
  779.             if (ce)
  780.                 --str;
  781.         }
  782.         if (*str == '^' && (str[1] & 0x1F)) {
  783.             ++str;
  784.             *str &= 0x1F;
  785.             isaux = 1;
  786.         }
  787.         if (*str == '\\' && str[1]) {
  788.             ++str;
  789.             isaux = 1;
  790.         }
  791.         buf[di++] = *str++;
  792.     }
  793.     buf[di++] = 0;
  794.     if (isaux) {
  795.         *paux = malloc(di);
  796.         strcpy(*paux, buf);
  797.         base = *paux;
  798.     }
  799.     if (*str) {             /*  space ended */
  800.         *str = '\0';
  801.         *ptr = str + 1;     /*  next arg    */
  802.     } else {
  803.         *ptr = str;         /*  last arg    */
  804.     }
  805.     return(base);
  806. }
  807.  
  808.  
  809.