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