home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / XDME / Src / Mod / Alias.c next >
Encoding:
C/C++ Source or Header  |  1996-09-27  |  23.9 KB  |  955 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     alias.c
  5.  
  6.     DESCRIPTION
  7.     macros for DME/XDME
  8.  
  9.     NOTES
  10.     a part of that path is in command.c
  11.  
  12.     BUGS
  13.     <none known>
  14.  
  15.     TODO
  16.     -/-
  17.  
  18.     EXAMPLES
  19.     -/-
  20.  
  21.     SEE ALSO
  22.     command.c
  23.  
  24.     INDEX
  25.  
  26.     HISTORY
  27.     <see RCS-File>
  28.  
  29.  
  30. ******************************************************************************/
  31.  
  32. /*
  33. **  (C)Copyright 1992 by Bernd Noll for null/zero-soft
  34. **  All Rights Reserved
  35. **
  36. **  RCS Header: $Id: alias.c,v 1.65 92/11/09 12:47:29 b_noll Exp $
  37. **
  38. **  compiling with
  39. **  "#define PATCH_NULL"
  40. **  "#define PATCH_MACROS"
  41. **  causes that module to be used
  42. **
  43. *!*********************************************************************
  44. *!
  45. *!  MACROS - OVERVIEW
  46. **
  47. **  this option allows translation of alias.c
  48. **  and enables a change in do_command() to allow macro-execution
  49. **  and (perhaps) one in main() to initialize the macro-lists
  50. *!
  51. *!  the module supports several commands:
  52. *!  SETMACRO        definition of a new macro
  53. *!  UNSETMACRO        deletion of a macro
  54. *!
  55. *!  SETMACROVAR     definition of a macro's local variable
  56. *!  UNSETMACROVAR    deletion of suh a variable
  57. *!            (at the end of a macrocall all its local variables
  58. *!             are deleted automatically)
  59. *!
  60. ***********************************************************************
  61. **
  62. **  Implementation:
  63. **
  64. **  At the moment macros are stored in MACRO_NUM Lists, which
  65. **  are selected with the 1st char of the macro's name
  66. **  to speed up search-operations
  67. **
  68. **  All names are switched to lowercase, so there should be
  69. **  no case sensitivity
  70. **
  71. **  please note, that there is acess to "av[]" and to several functions of
  72. **  the module "varsbases" in this module, so porting to another program
  73. **  than DME might need some changes.
  74. **
  75. */
  76.  
  77.  
  78. /**************************************
  79.         Includes
  80. **************************************/
  81. #define MACRO struct MacroNode /* trick 17 * OPAQUE */
  82. #include "defs.h"
  83. #include "AVL.h"
  84.  
  85.  
  86.  
  87. /**************************************
  88.       Interne Defines & Struktures
  89. **************************************/
  90. /*
  91. ** U might use MACRO like an opaque type
  92. */
  93.  
  94.  
  95. struct MacroNode {
  96.     struct Node Node;   /* includes a ptr to the macro-name */
  97.     char*        Body;   /* statements to be executed at a macro-call (this all must fit in one line) */
  98.     short        NArgs;  /* 0..7 number of arguments to be given from do_command */
  99.     short        NFlags; /* PERHAPS FUTURE: 0..n number of local-flags to be supported */
  100.     char        freeme; /* NOT USED ANY MORE 0/1 flag if the macro is builtin or user-defined */
  101.     char        killme; /* 0/1 flag if he maxro shall be deleted after termination of its last macrocall */
  102.     short        NCalls; /* it seems to be necessary to forbid all deletions of an active macro */
  103. };
  104.  
  105.  
  106. struct MacroArg {
  107.     struct MinNode     ma_Node;     /* hook for recursion-stack */
  108.     struct MacroNode*ma_Macro;     /* a reference to the called macro w/ all its data */
  109.     VarRoot      ma_Locals;     /* AVL-Tree or List of Local Variables */ /* we could also have a ptr to an array of ptrs instead of a list, but then it might be necessary to use one more parameter for SETMACRO */
  110.     char*         ma_Arguments[2];/* array of ptr to string; there must always be at least two entries: a 1st one referencing the macroname and a last one == NULL */
  111. };
  112.  
  113. /**************************************
  114.        Prototypes & Exports
  115. **************************************/
  116.  
  117. Prototype void    do_setmacro    (void);
  118. Prototype void    do_unsetmacro    (void);
  119. Prototype void    do_setmacrovar    (void);
  120. Prototype void    do_unsetmacrovar(void);
  121. Prototype void    do_retmacro    (void);
  122. Prototype void    do_macrosave    (void);
  123. Prototype void    do_macroload    (void);
  124. Prototype void    SetMacroVar    (char* name, char* value);
  125. Prototype MACRO*getmacro    (char* name);
  126. Prototype int    callmacro    (MACRO*);
  127. Prototype int    nummacroargs    (MACRO*);
  128. Prototype char* getmacroarg    (char* name);
  129. Prototype char* getmacrovar    (char* name);
  130. Prototype void    DelMacros    (void);
  131. Prototype int    SetMacro    (char* name, char* body, int nargs);
  132.  
  133. Prototype int     savemacros     (FILE *);          /* PATCH_NULL [25 Jan 1993] : proto'd for pack.c */
  134. Prototype int     loadmacros     (FILE *, int *);   /* PATCH_NULL [25 Jan 1993] : proto'd for pack.c */
  135. Prototype int     GetDefMacros     (void);            /* PATCH_NULL [25 Jan 1993] : proto'd for pack.c */
  136.  
  137. /*
  138. **  usually I use a global Struct that contains all important
  139. **  variables - so the Macrolists too, that is to allow
  140. **  switching between several environments in future
  141. **  if that global structure is not used, we can support our
  142. **  own - local - variable, else we must access the lists via a
  143. **  macro.
  144. **  the argstack is not touched by that division, as command flow cannot
  145. **  be splitted
  146. **  !WARNING!    it CAN be splitted when using asynchroneous Rexx-ports
  147. **        but when writing that module, i did not intend to
  148. **        use really async rexx-commands
  149. **
  150. **  NOTE
  151. */
  152.  
  153. /**************************************
  154.         Internal Variables
  155. **************************************/
  156.     /*
  157.     **    *argstack contains all data which is created during one macro-call
  158.     **    *delenda is a delete-buffer for all macros, will have been removed
  159.     **     from their lists, but cannot deleted, as there is a prior call to
  160.     **     not returned; they are deleted then aftermacro-termination or
  161.     **     in exit_macros.
  162.     */
  163. static struct TreeNode* macros = NULL;    /* ... OF MACRO */
  164. static struct TreeNode* delenda= NULL;    /* ... OF MACRO */
  165. static MLIST argstack;            /* ... OF struct MacroArg */
  166. char  MacroBreak = 0;            /* internal possibility to terminate a macro */ /* PATCH_NULL [08 Mar 1993] : removed "static" */
  167.  
  168. /* extern int count_tree (APTR); */
  169.  
  170. /**********************************************
  171. **
  172. **  Definition and deletion of Macros
  173. **
  174. **********************************************/
  175.  
  176.  
  177. /*
  178. **  FreeMacro()
  179. **  DelMacro()
  180. **    2 help-Functions of do_unsetmacro (and exit_macros)
  181. **
  182. **    DelMacro() should delete only Macros, which are not in use
  183. **    for that reason it checks usecount, and if its not 0, the
  184. **    macro is put into another list and marked to be killed by
  185. **    callmacro() after execution.
  186. */
  187.  
  188. static void
  189. FreeMacro(MACRO* m)
  190. {
  191.     if (m->freeme) {                    /* if that macro is not a builtin one, */
  192.     free(m->Node.ln_Name);          /* free it and its contents */
  193.     free(m->Body);
  194.     free(m);
  195.     } /* if */
  196. } /* FreeMacro */
  197.  
  198.  
  199. static void
  200. DelMacro(char* name)
  201. {
  202.     MACRO* m;
  203.  
  204.     if ((m = getmacro(name))) {         /* find the node representing the macro ... */
  205. /* printf ("D:%s\n", name); */
  206.     AVL_Remove (¯os, (APTR)m);  /* , remove it from its tree ... */
  207.     if (!m->NCalls) {               /* and if it is not in use */
  208.         FreeMacro(m);               /* ... free its contents */
  209.     } else {            /* ... else put it into a certain kill-list */
  210.         m->killme++;        /* ... and mark it to be killed */
  211.         AVL_Append (&delenda, (APTR)m);
  212.     } /* if */
  213.     } /* if */
  214. } /* DelMacro */
  215.  
  216.  
  217.  
  218. /*
  219. **  SetMacro()
  220. **    a help-Function of do_setmacro (and maybe init_macros)
  221. **    (it is also called by packages.mergpack)
  222. **    which creates a new macro-node and fills copies of the parameters
  223. **
  224. */
  225.  
  226. int
  227. SetMacro(char* name, char* body, int nargs)
  228. {
  229.     MACRO* m;
  230.  
  231.     if (nargs >= NARGS) {
  232.     error ("too many arguments specified for macro");
  233.     return(0);
  234.     } /* if too many args */
  235.  
  236.     DelMacro(name);                                         /* for sure: remove all macros of the same name */
  237.  
  238.     if ((m = malloc(sizeof(MACRO)))) {                      /* allocate a macro-structure... */
  239.     setmem(m, sizeof(MACRO),0);
  240.     if ((m->Node.ln_Name = strdup(name))) {             /* ... the name ... */
  241.         if ((m->Body = strdup(body))) {                 /* ... and the body, */
  242.         m->NArgs= nargs;                /* fill in all values,  */
  243.         m->freeme = 1;
  244.         AVL_Append (¯os, (APTR)m);              /* and append the structure to a certain macro-list */
  245.         return(1);
  246.         } /* if block copied */
  247.         free(m->Node.ln_Name);                          /* if anything went wrong */
  248.     } /* if name copied */                    /* free all allocated frags */
  249.     free(m);                                            /* and set an error */
  250.     } /* if struct allocated */
  251.     nomemory();
  252.     return(0);
  253. } /* SetMacro */
  254.  
  255.  
  256.  
  257. /**********************************************
  258. **
  259. **  Access to Macros' arguments and local variables
  260. **
  261. **********************************************/
  262.  
  263.  
  264.  
  265. /*
  266. **  getmacrovar()
  267. **    get a local variable of the current(== last) macrocall
  268. **    we are supposing that only one process has access to resources
  269. **    that function is meant to be interface for getvar()
  270. */
  271.  
  272. char*
  273. getmacrovar(char* name)
  274. {
  275.     struct MacroArg* n = NULL;
  276.  
  277.     if (!(n = GetHead(&argstack))) /* PATCH_NULL [03 Apr 1993] */
  278.     { /* this function can not work if not called from within a macrocall */
  279.     return(NULL);
  280.     } /* if */
  281.  
  282.     return(GetVarFrom (&n->ma_Locals, name));
  283. } /* getmacrovar */
  284.  
  285.  
  286. /*
  287. **  SetMacroVar()
  288. **    a help-function of do_setmacrovar()
  289. **    and an interface to settypedvar()
  290. */
  291.  
  292. void
  293. SetMacroVar(char* name, char* value)
  294. {
  295.     struct MacroArg* n = NULL;
  296.  
  297.     if (!(n = GetHead(&argstack))) { /* this function can not work if not called from within a macrocall */
  298.     abort2();
  299.     } /* if */
  300.  
  301.     SetVarInto (&n->ma_Locals, name, value);
  302. } /* SetMacroVar */
  303.  
  304.  
  305.  
  306. /*
  307. **  getmacroarg()
  308. **    get an parameter of the current(== last) macrocall
  309. **    we are supposing that only one process has access to resources
  310. **    so we only have to check the topmost element of argstack
  311. *!  NOTE:   ARGUMENTS to a macro are READ-ONLY,
  312. *!        You can't alter their values from the body of the called macro
  313. *!
  314. */
  315.  
  316. char*
  317. getmacroarg(char* name)
  318. {
  319.     struct MacroArg* n = NULL;
  320.     int num;
  321.     char* res;
  322.  
  323.     if (!(n = GetHead(&argstack))) { /* this function can not work if not called from within a macrocall */
  324.     return(NULL);
  325.     } /* if */
  326.  
  327.     if ((strncmp(name,"arg",3) != 0) || (!is_number(name+3))) {     /* and it responds only to names of the type "ARGx" with x in /N */
  328.     return(NULL);
  329.     } /* if */
  330.     num = atoi(name+3);
  331.  
  332.     if (n->ma_Macro->NArgs>=num) {                                     /* if the last called function has an arg ARGx */
  333.     if ((res = strdup (n->ma_Arguments[num]))) {                   /* and U can duplicate it, then return the copy */
  334.         return(res);
  335.     } else {
  336.         nomemory();
  337.         abort(NULL);
  338.     } /* if (not) malloced res */
  339.     } else {
  340.     abort(NULL);
  341.     } /* if (not) exists argX */
  342. } /* getmacroarg */
  343.  
  344.  
  345.  
  346.  
  347. /**********************************************
  348. **
  349. **  Usage of Macros
  350. **
  351. **  for calls from do_command the sequence must
  352. **  be like that:
  353. **
  354. **  if (m=getmacro) then
  355. **    for i=1 to nummacroargs(m) do
  356. **        put nextarg to av[i]
  357. **    od;
  358. **    callmacro(m);
  359. **  fi;
  360. **
  361. **  callmacro() pushes av[i] onto argstack and
  362. **  clears them, then locks the macro and
  363. **  calls do_command with a copy of the
  364. **  macro's block
  365. **  when the execution returns, av[i] are
  366. **  restored and topof argstack is cleared
  367. **
  368. **********************************************/
  369.  
  370.  
  371.  
  372. /*
  373. **  callmacro()
  374. **    Call a Macro as interface from do_command()
  375. **    (first you must have got a "handle" via getmacro())
  376. */
  377.  
  378. int
  379. callmacro(MACRO* m)
  380. {
  381.     struct MacroArg* n       = NULL;
  382.     char** args = NULL;
  383.     char*  com    = NULL;
  384.     int ret    = 0;
  385.     int i;
  386.     int len    = m->NArgs*4+sizeof(struct MacroArg);
  387.  
  388.     n    = (struct MacroArg*)malloc(len);                     /* allocate space for the stack-element... */
  389.     com = strdup(m->Body);                      /* and duplicate the macro's body */
  390.  
  391.     if (n && com) {
  392.     setmem(n,len,0);                        /* clear all data */
  393.     AddHead((LIST*)&argstack,(NODE*)n);     /* and push the struct to argstack */
  394.  
  395.     InitVars (&n->ma_Locals);                  /* for use with encapsulated local variables we must initialize their list */
  396.  
  397.     av[0] = m->Node.ln_Name;        /* define argslot 0 - it might be asked during execution, and perhaps it was not set in do_command */
  398.     args = n->ma_Arguments;            /* then put all arguments into the struct */
  399.     for (i = m->NArgs; i >= 0; i--) {       /* and clear their global values */
  400.         args[i] = av[i];
  401.         av[i] = NULL;
  402.     } /* for */
  403.  
  404.                         /* [25 Jan 1993] : line added */
  405.     n->ma_Macro = m;
  406.     m->NCalls++;                /* disable deletion of that macro during execution */
  407.  
  408.     MacroBreak = 0;             /* clear the return - flag */
  409.  
  410.     ret = do_command(com);                  /* and call the macrobody (execute only the copy, as do_command might destroy the data) */
  411.     if (MacroBreak) {
  412.         ret = 1-ret;
  413.         globalflags.Abortcommand = MacroBreak-1;
  414.         MacroBreak     = 0;
  415.     } /* if */
  416.  
  417.     for (i = m->NArgs; i >= 0; i--) {       /* after the call restore the global values of all args, ... */
  418.         av[i] = args[i];
  419.     } /* for */
  420.     m->NCalls--;                /* and enable deletion of that macro after execution */
  421.     if (m->NCalls == 0 && m->killme) {      /* if we must delete the macro, do it */
  422.         AVL_Remove(&delenda, (APTR)m);
  423.         FreeMacro(m);
  424.     } /* if */
  425.  
  426.     DelAllVarsFrom (&n->ma_Locals);            /* delete all local variables ... */
  427.  
  428.     Remove((NODE*)n);                       /* and pop the margs-struct from argstack */
  429.     } else {
  430.     nomemory();
  431.     } /* if */
  432.  
  433.     if (n)                                      /* and free anything you allocated */
  434.     free(n);
  435.     if (com)
  436.     free(com);
  437.  
  438.     return(ret);
  439. } /* callmacro */
  440.  
  441.  
  442.  
  443. /*
  444. **  getmacro()
  445. **
  446. **    Find a Function of a given Name
  447. **    so macros can be tested for existance and user can get a ptr to a "Handle"
  448. **    that function is part of the interface to do_command()
  449. */
  450.  
  451. MACRO*
  452. getmacro(char* name)
  453. {
  454.     MACRO* m;
  455.  
  456.     m = (MACRO*)AVL_Find (¯os, name);
  457.     return(m);
  458. } /* getmacro */
  459.  
  460.  
  461. #if 0
  462. /*
  463. **  That function might be used as an interface for getvar
  464. **  to access the contents of a macro
  465. */
  466.  
  467. char*
  468. GetFuncBody(char* name)
  469. {
  470.     MACRO* m = NULL;
  471.     char* str = NULL;
  472.  
  473.     if (m = (MACRO*)getmacro(name)) {
  474.     str = strdup(m->Body);
  475.     } /* if */
  476.     return(str);
  477. } /* GetFuncBody */
  478. #endif /* NOT_DEF */
  479.  
  480.  
  481.  
  482. /*
  483. **  nummacroargs()
  484. **    Get the Number of Arguments of a Macro
  485. **    that function is used by do_command to get informations
  486. **    how many argslots to fill
  487. */
  488.  
  489. int
  490. nummacroargs(MACRO* m)
  491. {
  492.     return(m->NArgs);
  493. } /* nummacroargs */
  494.  
  495.  
  496.  
  497. /**********************************************
  498. **
  499. **  Initial Access to Macros
  500. **
  501. **
  502. **********************************************/
  503.  
  504.  
  505.  
  506. /*
  507. **  resmacros
  508. **    that structure shows all builtin macros
  509. **    which are defined at program start
  510. **    they are initialized via GetDefMacros
  511. */
  512.  
  513. typedef struct _mres
  514. {
  515.     char * name;
  516.     char * body;
  517.     int   numargs;
  518. } MRES;
  519.  
  520. static CONST MRES resmacros[] =
  521. {
  522.      /*  name,        block,              args */
  523.  
  524.     { "alias",       "setmacro   $arg1 0 $arg2", 2 },
  525.     { "aslload",     "arpload",                  0 },
  526.     { "aslinsfile",  "arpinsfile",               0 },
  527.     { "aslfont",     "arpfont",                  0 },
  528.     { "aslsave",     "arpsave",                  0 },
  529.     /* { "asl",     "arp",                  0 }, */
  530.     { "unalias",     "unsetmacro $arg1",         1 },
  531.     { "firstwindow", "select f",                 0 },
  532.     { "lastwindow",  "select l",                 0 },
  533.     { "nextwindow",  "select n",                 0 },
  534.     { "prevwindow",  "select p",                 0 },
  535.     { "so",          "if m saveold",             0 },
  536.     { NULL,      NULL,                 0 }
  537. }; /* resmacros */
  538.  
  539.  
  540. /*
  541. **  GetDefMacros
  542. **    initialize the builtin default-macros
  543. */
  544.  
  545. int
  546. GetDefMacros (void)
  547. {
  548.     int i;
  549.  
  550.     for (i = 0; resmacros[i].name; i++) {
  551.     if (!SetMacro(resmacros[i].name, resmacros[i].body, resmacros[i].numargs)) {
  552.         return (0);                 /* PATCH_NULL [25 Jan 1993] : line added */
  553.     } /* if error */        /* PATCH_NULL [25 Jan 1993] : line added */
  554.     } /* for all builtins */
  555.  
  556.     return (1);
  557. } /* GetDefMacros */
  558.  
  559.  
  560.  
  561.  
  562. /* That static variable is needed to communicate between savesinglemacro and savemacros */
  563. static FILE * mfi;
  564.  
  565. void savesinglemacro (MACRO * m)
  566. {
  567.     if (m && mfi) {
  568.     fprintf (mfi, "\tMACRO %s\n", m->Node.ln_Name);
  569.     if (m->NArgs) {
  570.         fprintf (mfi, "\t ARGS %d\n", m->NArgs);
  571.     } /* if */
  572.     fprintf (mfi, "\t BODY %s\n", m->Body);
  573.     } /* if */
  574. } /* savesinglemacro */
  575.  
  576.  
  577.  
  578.  
  579. int savemacros (FILE * fo)
  580. {
  581.     fprintf(fo, "MACROS START\n");
  582.  
  583.     mfi = fo;
  584.     AVL_ScanTree (¯os, (APTR)savesinglemacro, 1);
  585.  
  586.     fprintf(fo, "MACROS END\n");
  587.     return (1);
  588. } /* savemacros */
  589.  
  590.  
  591.  
  592. int loadmacros (FILE * fi, int * lineno)
  593. {
  594.     char * buf;
  595.     char   nmacro [128];
  596.     char   nargs  [128];
  597.     char   body   [2*LINE_LENGTH];
  598.  
  599.     buf = getnextcomline(fi, lineno);
  600. /* printf("read %s\n", buf); */
  601.     if (!buf) {
  602.     abort(0);
  603.     } /* if */
  604.     if (strncmp(buf, "MACROS START", 12) != 0) {
  605.     error ("No Macrostart header");
  606.     abort(0);
  607.     } /* if */
  608.  
  609.     nmacro[0] = 0;
  610.     nargs [0] = 0;
  611.     body  [0] = 0;
  612.  
  613.     while (globalflags.Abortcommand == 0) {
  614.     buf = getnextcomline(fi, lineno);
  615. /* printf("read %s\n", buf); */
  616.     if (!buf) {
  617.         abort(0);
  618.     } /* if */
  619.  
  620.     if (strncmp(buf, "MACROS END", 10) == 0) {
  621.         return(1);
  622.     } else if (strncmp(buf, "MACRO ", 6) == 0) {
  623.         buf += 6;
  624.         strncpy(nmacro, buf, 128);
  625. /* printf ("\nMACRO:", buf, 1); */
  626. /* printf (buf, 1); */
  627.     } else if (strncmp(buf, "ARGS ", 5) == 0) {
  628.         buf += 5;
  629.         if (nargs[0] != 0) {
  630.         error("%s:\nDeclared numargs not w/in a Macro", av[0]);
  631.         abort(0);
  632.         } /* if */
  633.         strncpy(nargs, buf, 128);
  634.     } else if (strncmp(buf, "BEGIN", 5) == 0) {
  635.         int len = 0;
  636.  
  637.         buf += 5;
  638.         while (*buf && *buf<33) buf++;
  639.         if (nmacro[0] == 0) {
  640.         error("<%s:\nDeclared Body w/out Macro", av[0]);
  641.         abort(0);
  642.         } /* if */
  643.  
  644.         if (*buf) {
  645.         len = strlen(buf);
  646.         strcpy (body, buf);
  647.         } /* if */
  648.  
  649.         while ((!globalflags.Abortcommand) && (buf = getnextcomline(fi, lineno))) {
  650.         char * inter = &body[len];
  651. /* printf ("reading %s\n", buf); */
  652.         if (strncmp (buf, "END", 3) == 0) {
  653. /* printf ("setting %s\n", body); */
  654.             goto setit;
  655.         } /* if */
  656.         len += strlen(buf)+1;
  657.         if (len < 2*LINE_LENGTH) {
  658.             *inter = ' ';
  659.             strcpy(inter+1, buf);
  660.         } else {
  661.             error ("%s:\nmacro-body too long", av[0]);
  662.         } /* if */
  663.         } /* while */
  664.         goto retfail;
  665.  
  666.     } else if (strncmp(buf, "BODY", 4) == 0 && (buf[4] < 0x21)) {
  667. /* printf ("B:%s\n", buf + 4); */
  668.         buf += 4;
  669.         if (*buf) buf++;
  670.         if (nmacro[0] == 0) {
  671.         error("<%s:\nDeclared Body w/out Macro", av[0]);
  672.         abort(0);
  673.         } /* if */
  674.         strncpy(body, buf, 2*LINE_LENGTH);
  675. setit:
  676.         av[1] = nmacro;
  677.         av[2] = nargs[0] ? nargs : "0";
  678.         av[3] = body;
  679. /* printf (";", nmacro); */
  680.         do_setmacro();
  681.         nmacro[0] = 0;
  682.         nargs [0] = 0;
  683.     } else {
  684.         error ("%s:\nunknown identifier '%s'", av[0], buf);
  685.     } /* if types */
  686.     } /* while not ready */
  687.  
  688. retfail:
  689.     return(0);
  690. } /* loadmacros */
  691.  
  692.  
  693.  
  694.  
  695.  
  696. /***************************************************
  697.  
  698.         COMMAND INTERFACE
  699.  
  700. ***************************************************/
  701.  
  702.  
  703. /*
  704. *! >SETMACROVAR name value
  705. *! >SMV     name value
  706. *!    define a local variable for the current macro-call
  707. *!    all local vars will be deleted at the end of a macro-execution
  708. *!    (SMV is a shortcut for SETMACROVAR as we can't define a short
  709. *!     macro for that command)
  710. *!
  711. */
  712.  
  713. void
  714. do_setmacrovar()
  715. {
  716.     SetMacroVar(av[1], av[2]);
  717. } /* do_setmacrovar */
  718.  
  719.  
  720. /*
  721. *! >UNSETMACROVAR name
  722. *!    drop a local variable before the end of the current macro-call
  723. *!    all local vars will be deleted at the end of a macro-execution
  724. *!    so that command may be obsolete
  725. *!
  726. */
  727.  
  728. void
  729. do_unsetmacrovar()
  730. {
  731.     struct MacroArg* n = NULL;
  732.  
  733.     if (!(n = GetHead(&argstack))) { /* this function can not work if not called from within a macrocall */
  734.     abort2();
  735.     } /* if */
  736.  
  737.     DelVarFromTree (&n->ma_Locals, av[1]);
  738. } /* do_unsetmacrovar */
  739.  
  740.  
  741. /*
  742. *! >RET
  743. *!    Terminate the current macro
  744. *!
  745. */
  746.  
  747. void do_retmacro (void)
  748. {
  749.     MacroBreak = globalflags.Abortcommand ? 2 : 1;
  750.     globalflags.Abortcommand = 1;
  751. } /* do_retmacro */
  752.  
  753.  
  754. /*
  755. *! >SETMACRO macroname numargs body
  756. *!    create a macro definition
  757. *!    please note that a macro-body is read twice once on definition
  758. *!    and once on execution (variables should be excaped so)
  759. *!
  760. *!    after such a definition it is possible to use macroname like
  761. *!    any DME-command; the following numargs expressions are used
  762. *!    as the macros variables, they can be accessed for read with
  763. *!    $arg0-$arg<numargs> (not for write)($arg0 returnes the macro's
  764. *!    name)
  765. *!
  766. *!  BUG:    if numargs is not a number then this command
  767. *!        will assume a value of "0"
  768. *!
  769. *!  WARNING:    the synopsis of that command MIGHT change in near future, as
  770. *!        I am thinking about use of macros' local flags or static vars
  771. *!        so there might come up another number of local-flags ->
  772. *!        SETMACRO name numargs NUMFLAGS|LIST-OF-NAMES body
  773. *!
  774. */
  775.  
  776. void
  777. do_setmacro()
  778. {
  779.     /* printf ("%d\n", */
  780.     SetMacro(av[1], av[3], atoi(av[2]));
  781. } /* do_setmacro */
  782.  
  783.  
  784. /*
  785. *!  >UNSETMACRO name
  786. *!    remove a macro definition
  787. *!
  788. */
  789.  
  790. void
  791. do_unsetmacro()
  792. {
  793.     DelMacro(av[1]);
  794. } /* do_unsetmacro */
  795.  
  796.  
  797. /*
  798. *!  >MACROSAVE filename
  799. *!    save the current macros into a file of a special format
  800. *!
  801. */
  802.  
  803. void do_macrosave (void)
  804. {
  805.     FILE * fo = NULL;
  806.  
  807.     if ((fo = fopen(av[1], "w"))) {
  808.     savemacros(fo);
  809.     fclose(fo);
  810.     } else {
  811.     error ("%s:\nCan't open file %s for output", av[0], av[1]);
  812.     abort2();
  813.     } /* if */
  814. } /* do_macrosave */
  815.  
  816.  
  817. /*
  818. *!  >MACROLOAD filename
  819. *!    read a special macrofile
  820. *!
  821. */
  822.  
  823. void do_macroload (void)
  824. {
  825.     FILE * fi      = NULL;
  826.     int    lineno = 0;
  827.  
  828.     if ((fi = fopen(av[1], "r"))) {
  829.     loadmacros(fi, &lineno);
  830.     fclose(fi);
  831.     } else {
  832.     error ("%s:\nCan't open file %s for input", av[0], av[1]);
  833.     globalflags.Abortcommand = 1;
  834.     } /* if */
  835. } /* do_macrosave */
  836.  
  837.  
  838.  
  839. #ifdef STATIC_COM
  840.  
  841. void* lockmvar (char *name) {
  842.     if (!(n = GetHead(&argstack))) { /* this function can not work if not called from within a macrocall */
  843.     return(NULL);
  844.     } /* if */
  845.  
  846.     return(AVL_Find (&n->ma_Locals, name));
  847. } /* lockmvar */
  848.  
  849.  
  850. char *macrobody(MACRO *handle) {
  851.     return handle->body;
  852. }
  853.  
  854.  
  855.  
  856.  
  857.  
  858. #endif
  859.  
  860. #ifdef PATCH_NULL /* PATCH_NULL < 24-06-94 */
  861. /* **************************************************
  862.     STATIC XDME Command Interface
  863. ************************************************** //
  864.  
  865. //        Name    #Args Function        Flags
  866.  
  867. //        Name  Pri Lock     Unlock    Call       NArgs
  868. :FX:COMTREE maro    1 getmacro return0    callmacro  nummacroargs
  869.  
  870. //        Name  Pri Lock      Unlock  Get        Set     Unset
  871. :FX:VARTREE marg    1 getmacroarg free      retval    return0 return0
  872. :FX:VARTREE mvar    1 lockmvar      return0 nodeget   nodeset return0
  873. :FX:VARTREE mbody  -1 getmacro      return0 macrobody return0 return0
  874.  
  875. // **************************************************
  876.     DYNAMIC XDME Command Interface
  877. ************************************************** */
  878.  
  879.  
  880. /*
  881. **  ALIAS_init ()
  882. **
  883. **    Init All Macro-Stuff
  884. **        init all name-lists
  885. **        init the arg-stack
  886. **        enable the builtin macros (if macros are global)
  887. **
  888. **    That function has to be called at programstart
  889. **    (that is done by the line below)
  890. */
  891.  
  892. static const
  893. struct CommandNode ALIAS_Commands[] = {
  894.     { ENODE("setmacro"),      3, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacro      },
  895.     { ENODE("unsetmacro"),    1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unsetmacro    },
  896.     { ENODE("ret"),           0, CF_VWM|CF_ICO|CF_COK, (FPTR)do_retmacro      },
  897.     { ENODE("smv"),           2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacrovar   },
  898.     { ENODE("setmacrovar"),   2, CF_VWM|CF_ICO|CF_COK, (FPTR)do_setmacrovar   },
  899.     { ENODE("unsetmacrovar"), 1, CF_VWM|CF_ICO|CF_COK, (FPTR)do_unsetmacrovar },
  900.     { ENODE("macroload"),     1,        CF_VWM|CF_ICO, (FPTR)do_macroload     }, /* tester */
  901.     { ENODE("macrosave"),     1,        CF_VWM|CF_ICO, (FPTR)do_macrosave     }  /* tester */
  902. };
  903.  
  904.  
  905. MK_AUTOINIT( ALIAS_Init )
  906. {
  907.     int i;
  908.  
  909.     /* ---- init the local structures */
  910.     macros  = NULL;
  911.     delenda = NULL;
  912.     NewList ((LIST*)&argstack);
  913.  
  914. #ifndef PATCH_PACK
  915.     GetDefMacros ();
  916. #endif /* PATCH_PACK */
  917.  
  918.     for (i = sizeof (ALIAS_Commands)/sizeof (struct CommandNode) - 1;i >= 0; --i) {
  919.     COM_Add (&ALIAS_Commands[i]);
  920.     } /* for */
  921. } /* ALIAS_Init */
  922.  
  923.  
  924. #if 0
  925.  
  926. MK_AUTOEXIT( ALIAS_Exit )
  927. {
  928.     int i;
  929.     APTR lock;
  930.     for (i = sizeof (ALIAS_Commands)/sizeof (struct CommandNode) - 1;i >= 0; --i) {
  931.     if (lock = COM_Lock (ALIAS_Commands[i].cn_Name))
  932.         COM_Remove (lock);
  933. } /* ALIAS_Exit */
  934. #endif
  935. #else
  936.  
  937. Prototype int init_macros (void);
  938.  
  939.  
  940. int init_macros (void) {
  941.     NewList ((LIST*)&argstack);
  942.  
  943.     delenda = NULL;
  944.     macros  = NULL;
  945.  
  946.     return GetDefMacros ();
  947.  
  948. } /* init_macros */
  949. #endif
  950.  
  951. /******************************************************************************
  952. *****  ENDE macros.c
  953. ******************************************************************************/
  954.  
  955.