home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / fish / disks / d1070.lha / Programs / ADoc / source / mactab.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-14  |  15.3 KB  |  698 lines

  1. /*                                                               -*- C -*-
  2.  *  MACTAB.C
  3.  *
  4.  *  (c)Copyright 1995 by Tobias Ferber,  All Rights Reserved
  5.  *
  6.  *  This file is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published
  8.  *  by the Free Software Foundation; either version 1 of the License,
  9.  *  or (at your option) any later version.
  10.  *
  11.  *  This file is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; see the file COPYING.  If not, write to
  18.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* $VER: $Id: mactab.c,v 1.2 1995/03/20 18:07:47 tf Exp $ */
  22.  
  23. #include <ctype.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27.  
  28. #include "mactab.h"
  29.  
  30. /* repair buggy realloc() implementation */
  31. #define my_realloc(ptr,size)  ( (ptr) ? realloc(ptr,size) : malloc(size) )
  32.  
  33. /* #of macro entries added when expanding dynamically */
  34. #define MACRESIZE  10
  35.  
  36. /* bytesize of a macro table for `n' macros */
  37. #define MACTABSIZE(n)  (size_t)( 2*(n) * sizeof(char *) + 2 )
  38.  
  39. typedef struct macnode {
  40.   struct macnode *succ, *pred;
  41.   int handle;           /* a unique macnode handle */
  42.   int reserved, used;   /* #of macros allocated (reserved) and used in mactab */
  43.   char **mactab;        /* the mactro table for strexpand() */
  44. } macnode_t;
  45.  
  46.  
  47. /* globals += */
  48. static int new_handle= 1;
  49. static macnode_t *maclist= (macnode_t *)0;
  50.  
  51. static macnode_t *macnode_head(macnode_t *this) { return (this && this->pred) ? macnode_head(this->pred) : this; }
  52. static macnode_t *macnode_tail(macnode_t *this) { return (this && this->succ) ? macnode_tail(this->succ) : this; }
  53.  
  54. /* expand the `macnode.mactab' table for `num_macros' macros */
  55. static int macnode_expand(macnode_t *this, int num_macros)
  56. {
  57.   int result= 0;
  58.  
  59.   if(this)
  60.   {
  61.     char **new= (char **)my_realloc( (void *)(this->mactab), MACTABSIZE(this->reserved + num_macros) );
  62.  
  63.     if(new)
  64.     {
  65.       this->mactab= new;
  66.       result= (this->reserved += num_macros);
  67.     }
  68.   }
  69.  
  70.   return result;
  71. }
  72.  
  73.  
  74. /* allocate a new `macnode_t' structure with a `mactab' holding `num_macros' macros */
  75. static macnode_t *macnode_new(int num_macros)
  76. {
  77.   macnode_t *new= (macnode_t *)malloc( sizeof(macnode_t) );
  78.  
  79.   if(new)
  80.   {
  81.     new->succ     =
  82.     new->pred     = (macnode_t *)0;
  83.  
  84.     new->reserved =
  85.     new->used     = 0;
  86.  
  87.     new->mactab   = (char **)0;
  88.  
  89.     /* allocate the macro table */
  90.     if( macnode_expand(new,num_macros) )
  91.     {
  92.       /* set the last mactro to NIL */
  93.       new->mactab[0] =
  94.       new->mactab[1] = (char *)0;
  95.  
  96.       /* give this macnode a handle */
  97.       new->handle= new_handle++;
  98.     }
  99.     else /* !new->mactab */
  100.     {
  101.       free(new);
  102.       new= (macnode_t *)0;
  103.     }
  104.   }
  105.  
  106.   return new;
  107. }
  108.  
  109.  
  110. /* remove `this' from the `maclist' -- return `this' */
  111. static macnode_t *macnode_remove(macnode_t *this)
  112. {
  113.   if(this)
  114.   {
  115.     if(this->pred)
  116.       this->pred->succ= this->succ;
  117.  
  118.     else
  119.       maclist= this->succ;
  120.  
  121.     if(this->succ)
  122.       this->succ->pred= this->pred;
  123.  
  124.     this->pred =
  125.     this->succ = (macnode_t *)0;
  126.   }
  127.  
  128.   return this;
  129. }
  130.  
  131.  
  132. /* add a macnode_t list `this' to the global `maclist' */
  133. static void macnode_add(macnode_t *this)
  134. {
  135.   if(this)
  136.   {
  137.     macnode_tail(this)->succ= maclist;
  138.     maclist= macnode_head(this);
  139.   }
  140. }
  141.  
  142.  
  143. /* remove `this' from the `maclist' and dispose it */
  144. static macnode_t *macnode_dispose(macnode_t *this)
  145. {
  146.   if(this)
  147.   {
  148.     macnode_remove(this);
  149.  
  150.     if(this->mactab)
  151.     {
  152.       int n;
  153.  
  154.       for(n=0; n < 2*this->used; n++)
  155.       {
  156.         if( (this->mactab)[n] )
  157.           free( (this->mactab)[n] );
  158.       }
  159.  
  160.       free(this->mactab);
  161.     }
  162.     free(this);
  163.   }
  164.   return (macnode_t *)0;
  165. }
  166.  
  167.  
  168. /* find the macnode_t in the `maclist' via handle */
  169. static macnode_t *macnode_find(int handle)
  170. {
  171.   macnode_t *this= maclist;
  172.  
  173.   while( this && (this->handle != handle) )
  174.     this= this->succ;
  175.  
  176.   return this;
  177. }
  178.  
  179.  
  180. /* get the pointer to a macro `lhs' in `this->mactab' or the pointer to a new entry */
  181. static char **macnode_getmac(macnode_t *this, char *lhs)
  182. {
  183.   char **tab= (char **)0;
  184.  
  185.   if(this && this->mactab && lhs && *lhs)
  186.   {
  187.     int n;
  188.  
  189.     for(n=0, tab= this->mactab; n < 2*this->used; n+=2, tab= &tab[2])
  190.     {
  191.       if( *tab && !strcmp(*tab,lhs) )
  192.         break;
  193.     }
  194.   }
  195.  
  196.   return tab;
  197. }
  198.  
  199.  
  200.  
  201. /* modify a macro `lhs' w/ value `rhs' in `this' macnode_t's `mactab'.
  202.    The `rhs' of an existing macro `lhs' is replaced with the given `rhs',
  203.    an `rhs' == (char *)0 can be used to remove `lhs' from `this->mactab'. */
  204.  
  205. static int macnode_setmac(macnode_t *this, char *lhs, char *rhs)
  206. {
  207.   int err= 0;
  208.  
  209.   if(this && lhs && *lhs)
  210.   {
  211.     char **ptr= macnode_getmac(this,lhs);
  212.  
  213.     if(ptr)
  214.     {
  215.       if(*ptr) /* we found the macro `lhs' at the position `ptr' */
  216.       {
  217.         /* free the old `rhs' value */
  218.         if(ptr[1])
  219.           free(ptr[1]);
  220.  
  221.         if(rhs) /* set the new `rhs' value */
  222.         {
  223.           ptr[1]= strdup(rhs);
  224.  
  225.           if(!ptr[1])
  226.             err= 3;
  227.         }
  228.  
  229.         else /* remove this macro */
  230.         {
  231.           if(ptr[0])
  232.             free(ptr[0]);
  233.  
  234.           while(ptr[2])
  235.           {
  236.             ptr[0]= ptr[2];
  237.             ptr[1]= ptr[3];
  238.  
  239.             ptr= &ptr[2];
  240.           }
  241.  
  242.           ptr[0]= ptr[1]= (char *)0;
  243.  
  244.           this->used--;
  245.         }
  246.       }
  247.  
  248.       else if(rhs) /* `lhs' is a new macro */
  249.       {
  250.         if(this->used + 1 > this->reserved)
  251.         {
  252.           /* resize the macro table (add MACRESIZE new macro entries) */
  253.           if( macnode_expand(this, MACRESIZE) == 0 )
  254.             err= 4;
  255.         }
  256.  
  257.         if(err == 0)
  258.         {
  259.           char *l= strdup(lhs);
  260.           char *r= strdup(rhs);
  261.  
  262.           if(l && r)
  263.           {
  264.             ptr= &(this->mactab)[2*this->used];
  265.  
  266.             ptr[0]= l;
  267.             ptr[1]= r;
  268.  
  269.             ptr[2]=
  270.             ptr[3]= (char *)0;
  271.  
  272.             this->used++;
  273.           }
  274.           else /* strdup() failed */
  275.           {
  276.             if(l) free(l);
  277.             if(r) free(r);
  278.  
  279.             err= 3;
  280.           }
  281.         }
  282.       }
  283.       /* otherwise this was a no-op (:< */
  284.     }
  285.     else err= 2;
  286.   }
  287.   else err= 1;
  288.  
  289.   return err;
  290. }
  291.  
  292. /*
  293. **  PUBLIC
  294. */
  295.  
  296.  
  297. /****** mactab/mactab ********************************************************
  298. *
  299. *   NAME
  300. *       mactab -- Get the macro table associated with a handle
  301. *
  302. *   SYNOPSIS
  303. *       table= mactab( handle );
  304. *
  305. *       char **mactab( int handle );
  306. *
  307. *   FUNCTION
  308. *       This function returns the macro table with the given handle `handle'.
  309. *       The returned macro table can be directly passed to strexpand().  This
  310. *       function will not fail if `handle' is a legal mactab handle.
  311. *
  312. *   INPUTS
  313. *       handle        - The handle of the macro table
  314. *
  315. *   RESULT
  316. *       table         - A macro table for strexpand()
  317. *
  318. *   EXAMPLE
  319. *       {
  320. *         \* create a new macro table *\
  321. *         int my_handle = mactab_new( 3 );
  322. *
  323. *         if(my_handle != 0)
  324. *         {
  325. *           \* initialize macros for a "ASCII->Texinfo" conversion *\
  326. *           int err= mactab_add( my_handle,   "@",  "@@"
  327. *                                             "{",  "@{",
  328. *                                             "}",  "@}",  (char *)0 );
  329. *           if(err == 0)
  330. *           {
  331. *             \* convert our `ascii_string' into Texinfo *\
  332. *             char *texi_string= strexpad( ascii_string, mactab(my_handle) );
  333. *
  334. *             if(texi_string)
  335. *             {
  336. *               \* print the converted string to stdout and dispose it *\
  337. *               puts(texi_string);
  338. *               free(texi_string);
  339. *             }
  340. *             else out_of_memory();
  341. *           }
  342. *           else out_of_memory();
  343. *
  344. *           \* free our macro table *\
  345. *           my_handle= mactab_dispose(my_handle);
  346. *         }
  347. *         else out_of_memory();
  348. *       }
  349. *
  350. *   NOTES
  351. *
  352. *   BUGS
  353. *
  354. *   SEE ALSO
  355. *       mactab_new(), mactab_add(), strexpand()
  356. *
  357. ******************************************************************************
  358. *
  359. *  get the macro table `mactab' of the macnode_t in `maclist' with handle `handle'
  360. */
  361.  
  362. char **mactab(int handle)
  363. {
  364.   macnode_t *this= macnode_find(handle);
  365.   return this ? this->mactab : (char **)0;
  366. }
  367.  
  368.  
  369. /****** mactab/mactab_new ****************************************************
  370. *
  371. *   NAME
  372. *       mactab_new -- Allocate a new macro table
  373. *
  374. *   SYNOPSIS
  375. *       handle= mactab_new( num_macros );
  376. *
  377. *       int mactab_new( int num_macros );
  378. *
  379. *   FUNCTION
  380. *       This function allocates a new macro table which offers enough room
  381. *       to hold `num_macros' macros plus one NULL entry.  The value of
  382. *       `num_macros' should be > 0, however if more macros are added, then
  383. *       the macro table will be expanded dynamically.
  384. *
  385. *   INPUTS
  386. *       num_macros    - The number of macros reserved for this macro table.
  387. *                       (should be > 0)
  388. *
  389. *   RESULT
  390. *       handle        - The handle of the allocated macro table or
  391. *                       0 in case of an error.
  392. *
  393. *   EXAMPLE
  394. *
  395. *   NOTES
  396. *
  397. *   BUGS
  398. *
  399. *   SEE ALSO
  400. *       mactab_dispose(), mactab(), mactab_add(), strexpand()
  401. *
  402. ******************************************************************************
  403. *
  404. *  allocate a new macnode_t and reserve `num_macros' macros in the mactab
  405. */
  406.  
  407. int mactab_new(int num_macros)
  408. {
  409.   macnode_t *this= macnode_new(num_macros);
  410.  
  411.   if(this)
  412.     macnode_add(this);
  413.  
  414.   return this ? this->handle : 0;
  415. }
  416.  
  417.  
  418. /****** mactab/mactab_dispose ************************************************
  419. *
  420. *   NAME
  421. *       mactab_dispose -- Free one (or all) macro tables
  422. *
  423. *   SYNOPSIS
  424. *       null_handle= mactab_dispose( handle );
  425. *
  426. *       int mactab_dispose( int handle );
  427. *
  428. *   FUNCTION
  429. *       This function removes the macro table associated with `handle'
  430. *       and returns all memory allocated for it to the system free pool.
  431. *       If a negative handle is passed to this function then *ALL*
  432. *       macro tables will be disposed.
  433. *
  434. *   INPUTS
  435. *       handle        - The handle of the macro table to delete or
  436. *                       `-1' to delete all macro tables.
  437. *
  438. *   RESULT
  439. *       null_handle   - a handle which is never associated with a
  440. *                       macro table.
  441. *
  442. *   EXAMPLE
  443. *
  444. *   NOTES
  445. *
  446. *   BUGS
  447. *
  448. *   SEE ALSO
  449. *       mactab_new(), mactab_remove()
  450. *
  451. ******************************************************************************
  452. *
  453. *  dispose the macnode_t with handle `handle' or all macnode_t's if handle < 0
  454. */
  455.  
  456. int mactab_dispose(int handle)
  457. {
  458.   if(handle > 0)
  459.   {
  460.     macnode_t *this= macnode_find(handle);
  461.  
  462.     if(this)
  463.       this= macnode_dispose(this);
  464.   }
  465.   else if(handle < 0)
  466.   {
  467.     while(maclist)
  468.     {
  469.       macnode_t *this= maclist;
  470.       maclist= maclist->succ;
  471.       macnode_dispose(this);
  472.     }
  473.   }
  474.  
  475.   return 0;
  476. }
  477.  
  478. /****** mactab/mactab_remove *************************************************
  479. *
  480. *   NAME
  481. *       mactab_remove -- Remove one or more macros from a macro table
  482. *
  483. *   SYNOPSIS
  484. *       error= mactab_remove( handle, macro1, macro2, ..., (char *)0 );
  485. *
  486. *       int mactab_remove( int handle, ... );
  487. *
  488. *   FUNCTION
  489. *       This function removes all given macros from the macro table associated
  490. *       with the handle `handle'.  The list of macro names must be terminated
  491. *       with a (char *)0.
  492. *
  493. *   INPUTS
  494. *       handle        - The handle of the macro table
  495. *       ...           - A list of macro names with a trailing (char *)0
  496. *
  497. *   RESULT
  498. *       error         - != 0 in case of an error,  0 otherwise
  499. *
  500. *   EXAMPLE
  501. *
  502. *   NOTES
  503. *
  504. *   BUGS
  505. *
  506. *   SEE ALSO
  507. *       mactab_get(), mactab_add(), mactab_dispose()
  508. *
  509. ******************************************************************************
  510. *
  511. *  delete the given macros from the `mactab' of the macnode with handle `handle'
  512. */
  513.  
  514. int mactab_remove(int handle, ...)
  515. {
  516.   int err= 0;
  517.  
  518.   macnode_t *this= macnode_find(handle);
  519.  
  520.   if(this)
  521.   {
  522.     char *lhs;
  523.  
  524.     va_list argp;
  525.     va_start(argp,handle);
  526.  
  527.     do {
  528.       lhs= va_arg(argp, char *);
  529.  
  530.       if(lhs && *lhs)
  531.       {
  532.         /* set the `rhs' of each macro `lhs' to NIL */
  533.         err= macnode_setmac(this, lhs, (char *)0);
  534.       }
  535.     } while(lhs && *lhs && !err);
  536.  
  537.     va_end(argp);
  538.   }
  539.   else err= 1;
  540.  
  541.   return err;
  542. }
  543.  
  544.  
  545. /****** mactab/mactab_add ****************************************************
  546. *
  547. *   NAME
  548. *       mactab_add -- Add one or more macros to a macro table
  549. *
  550. *   SYNOPSIS
  551. *       error= mactab_add( handle, macro1, value1, ..., (char *)0 );
  552. *
  553. *       int mactab_add( int handle, ... );
  554. *
  555. *   FUNCTION
  556. *       This function adds the given macros to the macro table associated with
  557. *       given handle `handle'.  A (char *)0 terminates the list of macro names
  558. *       and macro values.  A macro value (char *)0 can be used to remove this
  559. *       macro from the list of macros in this table and is equivalent to a
  560. *       mactab_remove() call for this macro name.
  561. *
  562. *   INPUTS
  563. *       handle        - The handle of the macro table
  564. *       ...           - A list of macro names and macro values with a
  565. *                       trailing (char *)0
  566. *
  567. *   RESULT
  568. *       error         - != 0 in case of an error,  0 otherwise
  569. *
  570. *   EXAMPLE
  571. *
  572. *   NOTES
  573. *
  574. *   BUGS
  575. *
  576. *   SEE ALSO
  577. *       mactab_remove(), mactab_new(), mactab_get(), mactab(), strexpand()
  578. *
  579. ******************************************************************************
  580. *
  581. *  add some macros to the `mactab' of the macnode_t with handle `handle'
  582. */
  583.  
  584. int mactab_add(int handle, ...)
  585. {
  586.   int err= 0;
  587.  
  588.   macnode_t *this= macnode_find(handle);
  589.  
  590.   if(this)
  591.   {
  592.     char *lhs, *rhs;
  593.  
  594.     va_list argp;
  595.     va_start(argp,handle);
  596.  
  597.     do {
  598.       lhs= va_arg(argp, char *);
  599.  
  600.       if(lhs && *lhs)
  601.       {
  602.         rhs= va_arg(argp, char *);
  603.         err= macnode_setmac(this,lhs,rhs);
  604.       }
  605.     } while(lhs && *lhs && !err);
  606.  
  607.     va_end(argp);
  608.   }
  609.   else err= 1;
  610.  
  611.   return err;
  612. }
  613.  
  614.  
  615. /****** mactab/mactab_get ****************************************************
  616. *
  617. *   NAME
  618. *       mactab_get -- Get the value of a macro
  619. *
  620. *   SYNOPSIS
  621. *       value= mactab_get( handle, name );
  622. *
  623. *       char *mactab_get( int handle, char *name );
  624. *
  625. *   FUNCTION
  626. *       This function returns the value of the macro `name' out of the table
  627. *       associated with the given handle `handle'.
  628. *
  629. *   INPUTS
  630. *       handle        - The handle of the macro table
  631. *       name          - The name of the macro
  632. *
  633. *   RESULT
  634. *       value         - The value of the macro `name' or 
  635. *                       (char *)0 if `name' was not found
  636. *
  637. *   EXAMPLE
  638. *
  639. *   NOTES
  640. *
  641. *   BUGS
  642. *
  643. *   SEE ALSO
  644. *       mactab_new(), mactab_add(), mactab()
  645. *
  646. ******************************************************************************
  647. *
  648. *  get the macro table `mactab' of the macnode_t in `maclist' with handle `handle'
  649. */
  650.  
  651. char *mactab_get(int handle, char *lhs)
  652. {
  653.   char *rhs= (char *)0;
  654.  
  655.   macnode_t *this= macnode_find(handle);
  656.  
  657.   if(this)
  658.   {
  659.     char **ptr= macnode_getmac(this,lhs);
  660.  
  661.     if(ptr && *ptr)
  662.       rhs= ptr[1];
  663.   }
  664.  
  665.   return rhs;
  666. }
  667.  
  668.  
  669. #ifdef DEBUG
  670. #include <stdio.h>
  671.  
  672. void mactab_debug(FILE *fp)
  673. {
  674.   macnode_t *this;
  675.  
  676.   for(this= maclist; this; this= this->succ)
  677.   {
  678.     char **tab= this->mactab;
  679.  
  680.     fprintf(fp,"handle %d:  (reserved: %d, used: %d)\n",this->handle, this->reserved, this->used);
  681.  
  682.     if(tab)
  683.     {
  684.       int n;
  685.  
  686.       for(n=0; n<this->used; n++)
  687.       {
  688.         fprintf(fp,"\t\"%s\"\t\"%s\"\n", tab[0] ? tab[0] : "(nil)", tab[1] ? tab[1] : "(nil)");
  689.         tab= &tab[2];
  690.       }
  691.     }
  692.  
  693.     fprintf(fp,"\n");
  694.   }
  695. }
  696.  
  697. #endif /* DEBUG */
  698.