home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / unsupprt / guide / src / libguide / gio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  23.7 KB  |  1,421 lines

  1. /*
  2.  * This file is a product of Sun Microsystems, Inc. and is provided for
  3.  * unrestricted use provided that this legend is included on all tape
  4.  * media and as a part of the software program in whole or part.  Users
  5.  * may copy or modify this file without charge, but are not authorized to
  6.  * license or distribute it to anyone else except as part of a product
  7.  * or program developed by the user.
  8.  * 
  9.  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12.  * 
  13.  * This file is provided with no support and without any obligation on the
  14.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  15.  * modification or enhancement.
  16.  * 
  17.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
  19.  * OR ANY PART THEREOF.
  20.  * 
  21.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22.  * or profits or other special, indirect and consequential damages, even
  23.  * if Sun has been advised of the possibility of such damages.
  24.  * 
  25.  * Sun Microsystems, Inc.
  26.  * 2550 Garcia Avenue
  27.  * Mountain View, California  94043
  28.  */
  29.  
  30. #ifndef lint
  31. static char     sccsid[] = "@(#)gio.c    2.29 91/10/15 Copyright 1989 Sun Microsystems";
  32. #endif
  33.  
  34. /*
  35.  * GUIDE Intermediate Language (GIL) file input / output interface.
  36.  *
  37.  * This file implements the functions required to read and write GIL
  38.  * files.  The GIL syntax is based on Lisp so that they may be read
  39.  * directly into a Lisp or Scheme interpreter.
  40.  *
  41.  * Many of these functions return a string to indicate the begin or
  42.  * end of a special sequence in the GIL syntax, for example, a list.
  43.  * Internally it is common to only use the first character returned.
  44.  * I did it this way so the functions are consistent and to allow 
  45.  * for flexibility in the future.
  46.  */
  47.  
  48. #include <stdio.h>
  49. #include <ctype.h>
  50. #include <sys/param.h>
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <errno.h>
  54. #include <string.h>
  55. #include <varargs.h>
  56. #include <malloc.h>
  57. #include "guide.h"
  58. #include "gio.h"
  59.  
  60. /*
  61.  * Delimiter for a full name.
  62.  */
  63. #define DELIMITER    ':'
  64.  
  65. /*
  66.  * File pointers.
  67.  */
  68. static FILE    *Inp = stdin;
  69. static FILE    *Outp = stdout;
  70.  
  71. /*
  72.  * Internal state variables.
  73.  */
  74. static char     Indent[12];            /* indent string */
  75. static int    Indent_level;
  76. static int      Newline = TRUE;            /* TRUE if on new output line */
  77. static char    Buf[MAXPATHLEN];        /* work buffer */
  78.  
  79. /*
  80.  * System error message definitions.
  81.  */
  82. extern int      sys_nerr;
  83. extern char    *sys_errlist[];
  84.  
  85. /*
  86.  * Internal function declarations.
  87.  */
  88. int        gil_version();
  89. void        skip_comments();
  90. char           *get_token();
  91.  
  92. /*
  93.  * Return the string representation of a boolean.
  94.  */
  95. char    *
  96. #ifdef __STDC__
  97. gio_boolean_string(int b)
  98. #else
  99. gio_boolean_string(b)
  100.     int             b;
  101. #endif
  102. {
  103.     return b ? gio_true_string() : gio_false_string();
  104. }
  105.  
  106. /*
  107.  * Close the input file.
  108.  */
  109. void
  110. gio_close_input()
  111. {
  112.     if (Inp != stdin)
  113.     {
  114.         fclose(Inp);
  115.         Inp = stdin;
  116.     }
  117. }
  118.  
  119. /*
  120.  * Close the output file.
  121.  */
  122. void
  123. gio_close_output()
  124. {
  125.     if (Outp != stdout)
  126.     {
  127.         fflush(Outp);
  128.         ftruncate(fileno(Outp), ftell(Outp));
  129.         fclose(Outp);
  130.         Outp = stdout;
  131.     }
  132. }
  133.  
  134. /*
  135.  * Return the comment string.
  136.  */
  137. char           *
  138. gio_comment_string()
  139. {
  140.     return ";";
  141. }
  142.  
  143. /*
  144.  * Return the boolean false string.
  145.  */
  146. char           *
  147. gio_false_string()
  148. {
  149.     return "nil";
  150. }
  151.  
  152. /*
  153.  * Return the file begin string.
  154.  */
  155. char           *
  156. gio_file_begin_string()
  157. {
  158.     return "(";
  159. }
  160.  
  161. /*
  162.  * Return the file end string.
  163.  */
  164. char           *
  165. gio_file_end_string()
  166. {
  167.     return ")";
  168. }
  169.  
  170. /*
  171.  * Get a boolean from the input file.  Returns TRUE if successful.
  172.  */
  173. int
  174. #ifdef __STDC__
  175. gio_get_boolean(int *b)
  176. #else
  177. gio_get_boolean(b)
  178.     int           *b;
  179. #endif
  180. {
  181.     char           *p = get_token();
  182.  
  183.     if (strcmp(p, gio_true_string()) == 0)
  184.     {
  185.         *b = TRUE;
  186.         return TRUE;
  187.     }
  188.     if (strcmp(p, gio_false_string()) == 0)
  189.     {
  190.         *b = FALSE;
  191.         return TRUE;
  192.     }
  193.     return FALSE;
  194. }
  195.  
  196. /*
  197.  * Return whether we are at end-of-file.
  198.  */
  199. int
  200. gio_get_eof()
  201. {
  202.     int        ch;
  203.  
  204.     while (isspace(ch = fgetc(Inp)))
  205.         ;
  206.     if (ch == EOF)
  207.         return TRUE;
  208.     ungetc(ch, Inp);
  209.     return FALSE;
  210. }
  211.  
  212. /*
  213.  * Get the start of the file.  Returns TRUE if successful.
  214.  */
  215. int
  216. gio_get_file_begin()
  217. {
  218.     int        ch;
  219.  
  220.     while (isspace(ch = fgetc(Inp)))
  221.         ;
  222.     if (ch == *gio_file_begin_string())
  223.         return TRUE;
  224.     ungetc(ch, Inp);
  225.     return FALSE;
  226. }
  227.  
  228. /*
  229.  * Get the end of the file.  Returns TRUE if successful.
  230.  */
  231. int
  232. gio_get_file_end()
  233. {
  234.     int        ch;
  235.  
  236.     while (isspace(ch = fgetc(Inp)))
  237.         ;
  238.     if (ch == *gio_file_end_string())
  239.         return TRUE;
  240.     ungetc(ch, Inp);
  241.     return FALSE;
  242. }
  243.  
  244. /*
  245.  * Get a handler from the input file.  Returns TRUE if successful.
  246.  * Sets the string pointer to a buffer allocated with malloc if the string
  247.  * is not empty, otherwise NULL.  Handler could be a quoted string
  248.  * for special language cases (PostScript, Lisp, etc...) or just
  249.  * a simple name for C.
  250.  */
  251. int
  252. #ifdef __STDC__
  253. gio_get_handler(char **s)
  254. #else
  255. gio_get_handler(s)
  256.     char          **s;
  257. #endif
  258. {
  259. #define    INC        32
  260.     int        ch;
  261.     int        lth;            /* string length */
  262.     int        c = 0;            /* string count */
  263.  
  264.     while (isspace(ch = fgetc(Inp)))
  265.         ;
  266.     ungetc(ch, Inp);
  267.  
  268.     if (ch != *gio_string_begin_string())
  269.         return gio_get_name(s);
  270.     else
  271.     {
  272.         *s = malloc(lth = INC);
  273.         *s[c++] = fgetc(Inp);
  274.         while (((ch = fgetc(Inp)) != EOF) &&
  275.                (ch != *gio_string_end_string()))
  276.         {
  277.             if (c + 2 == lth)
  278.                 *s = realloc(*s, lth += INC);
  279.             if (ch == '\\')
  280.                 ch = fgetc(Inp);
  281.             (*s)[c++] = (char) ch;
  282.         }
  283.         (*s)[c] = *gio_string_end_string();
  284.         (*s)[c+1] = '\0';
  285.         return TRUE;
  286.     }
  287. #undef INC
  288. }
  289.  
  290. /*
  291.  * Get an integer from the input file.  Returns TRUE if successful.
  292.  */
  293. int
  294. #ifdef __STDC__
  295. gio_get_integer(int *i)
  296. #else
  297. gio_get_integer(i)
  298.     int           *i;
  299. #endif
  300. {
  301.     char           *p = get_token();
  302.     char           *q;
  303.     long        l = strtol(p, &q, 10);
  304.  
  305.     if (p != q)
  306.     {
  307.         *i = (int) l;
  308.         return TRUE;
  309.     }
  310.     return FALSE;
  311. }
  312.  
  313. /*
  314.  * Get a keyword from the input file.  Returns TRUE if successful.
  315.  * The keyword is returned in a static buffer.
  316.  */
  317. int
  318. #ifdef __STDC__
  319. gio_get_keyword(char **s)
  320. #else
  321. gio_get_keyword(s)
  322.     char           **s;
  323. #endif
  324. {
  325.     *s = get_token();
  326.     return TRUE;
  327. }
  328.  
  329. /*
  330.  * Get a list as a string from the input file.  Returns TRUE if successful.
  331.  * Sets the string pointer to a buffer allocated with malloc if the string
  332.  * is not empty, otherwise NULL.
  333.  */
  334. int
  335. #ifdef __STDC__
  336. gio_get_list(char **s)
  337. #else
  338. gio_get_list(s)
  339.     char          **s;
  340. #endif
  341. {
  342. #define    INC        32
  343.     int        ch;
  344.     int        lth;            /* string length */
  345.     int        c;            /* string count */
  346.  
  347.     while (isspace(ch = fgetc(Inp)))
  348.         ;
  349.     if (ch != *gio_list_begin_string())
  350.     {
  351.         ungetc(ch, Inp);
  352.         return FALSE;
  353.     }
  354.  
  355.     if (gio_get_list_end())
  356.     {
  357.         *s = NULL;
  358.         return TRUE;
  359.     }
  360.  
  361.     *s = malloc(lth = INC);
  362.     for (c = 0; (ch = fgetc(Inp)) != *gio_list_end_string(); c++)
  363.     {
  364.         if (c + 1 == lth)
  365.             *s = realloc(*s, lth += INC);
  366.         if (ch == '\\')
  367.             ch = fgetc(Inp);
  368.         (*s)[c] = (char) ch;
  369.     }
  370.     (*s)[c] = '\0';
  371.     return TRUE;
  372. #undef INC
  373. }
  374.  
  375. /*
  376.  * Get the start of a list from the input file.  Returns TRUE if successful.
  377.  */
  378. int
  379. gio_get_list_begin()
  380. {
  381.     int        ch;
  382.  
  383.     while (isspace(ch = fgetc(Inp)))
  384.         ;
  385.     if (ch == *gio_list_begin_string())
  386.         return TRUE;
  387.     ungetc(ch, Inp);
  388.     return FALSE;
  389. }
  390.  
  391. /*
  392.  * Get the end of a list from the input file.  Returns TRUE if successful.
  393.  */
  394. int
  395. gio_get_list_end()
  396. {
  397.     int        ch;
  398.  
  399.     while (isspace(ch = fgetc(Inp)))
  400.         ;
  401.     if (ch == *gio_list_end_string())
  402.         return TRUE;
  403.     ungetc(ch, Inp);
  404.     return FALSE;
  405. }
  406.  
  407. /*
  408.  * Get a symbol from the input file.  Returns TRUE if successful.
  409.  * Sets the string pointer to a buffer allocated with malloc if the string
  410.  * is not empty, otherwise NULL.
  411.  */
  412. int
  413. #ifdef __STDC__
  414. gio_get_name(char **s)
  415. #else
  416. gio_get_name(s)
  417.     char          **s;
  418. #endif
  419. {
  420.     char           *p = get_token();
  421.  
  422.     if (strcmp(p, gio_false_string()) == 0)
  423.         *s = NULL;
  424.     else {
  425.         *s = malloc(strlen(p) + 1);
  426.         strcpy(*s, p);
  427.     }
  428.     return TRUE;
  429. }
  430.  
  431.  
  432. /*
  433.  * Get the full name of an object in a gil file.
  434.  * The syntax of a full name is:
  435.  *     (name)        when the object is top-level;
  436.  *     (parent name)    when the object is not top-level;
  437.  *    (parent name "item")    when the object is a setting or
  438.  *                menu item.
  439.  */
  440. int
  441. #ifdef __STDC__
  442. gio_get_full_name(char **parent, char **name, char **item)
  443. #else
  444. gio_get_full_name(parent, name, item)
  445.     char    **parent;
  446.     char    **name;
  447.     char    **item;
  448. #endif
  449. {
  450.     char    *tmp1, *tmp2;
  451.  
  452.     *parent = NULL;
  453.     *name = NULL;
  454.     *item = NULL;
  455.  
  456.     if (!gio_get_list_begin())
  457.         return FALSE;
  458.  
  459.     if (!gio_get_name(&tmp1))
  460.         return FALSE;
  461.  
  462.     if (gio_get_list_end())
  463.     {
  464.         *name = (char *)malloc(strlen(tmp1)+1);
  465.         strcpy(*name, tmp1);
  466.         return TRUE;
  467.     }
  468.  
  469.     if (gio_get_string(&tmp2))
  470.     {
  471.         *name = (char *)malloc(strlen(tmp1)+1);
  472.         *item = (char *)malloc(strlen(tmp2)+1);
  473.         strcpy(*name, tmp1);
  474.         strcpy(*item, tmp2);
  475.         if (!gio_get_list_end())
  476.             return FALSE;
  477.         return TRUE;
  478.     }
  479.     
  480.     *parent = (char *)malloc(strlen(tmp1)+1);
  481.     strcpy(*parent, tmp1);
  482.     free(tmp1);
  483.     if (gio_get_name(&tmp1))
  484.     {
  485.         *name = (char *)malloc(strlen(tmp1)+1);
  486.         if (!gio_get_list_end())
  487.             if (gio_get_string(&tmp2))
  488.             {
  489.                 *item = (char *)malloc(strlen(tmp2)+1);
  490.                 strcpy(*name, tmp1);
  491.                 strcpy(*item, tmp2);
  492.                 if (gio_get_list_end())
  493.                     return TRUE;
  494.                 return FALSE;
  495.             }
  496.         strcpy(*name, tmp1);
  497.         return TRUE;
  498.     }
  499.     return FALSE;
  500. }
  501.  
  502.  
  503. /*
  504.  * Get the full name of an object in a project file.
  505.  * The syntax of a full name is:
  506.  *     interface:name        when the object is top-level;
  507.  *     interface:parent:name    when the object is not top-level;
  508.  *    interface:parent:name:"item"    when the object is a setting or
  509.  *                menu item.
  510.  */
  511. int
  512. #ifdef __STDC__
  513. gio_get_proj_full_name(char **interface, char **parent,
  514.                char **name, char **item)
  515. #else
  516. gio_get_proj_full_name(interface, parent, name, item)
  517.     char    **interface;
  518.     char    **parent;
  519.     char    **name;
  520.     char    **item;
  521. #endif
  522. {
  523.     char    *tmp1, *tmp2;
  524.  
  525.     *interface = NULL;
  526.     *parent = NULL;
  527.     *name = NULL;
  528.     *item = NULL;
  529.  
  530.     if (!gio_get_list_begin())
  531.         return FALSE;
  532.  
  533.     if (!gio_get_name(&tmp1))
  534.         return FALSE;
  535.     *interface = (char *)malloc(strlen(tmp1)+1);
  536.     strcpy(*interface, tmp1);
  537.     free(tmp1);
  538.  
  539.     if (!gio_get_name(&tmp1))
  540.         return FALSE;
  541.  
  542.     if (gio_get_list_end())
  543.     {
  544.         *name = (char *)malloc(strlen(tmp1)+1);
  545.         strcpy(*name, tmp1);
  546.         return TRUE;
  547.     }
  548.  
  549.     if (gio_get_string(&tmp2))
  550.     {
  551.         *name = (char *)malloc(strlen(tmp1)+1);
  552.         *item = (char *)malloc(strlen(tmp2)+1);
  553.         strcpy(*name, tmp1);
  554.         strcpy(*item, tmp2);
  555.         if (!gio_get_list_end())
  556.             return FALSE;
  557.         return TRUE;
  558.     }
  559.     
  560.     *parent = (char *)malloc(strlen(tmp1)+1);
  561.     strcpy(*parent, tmp1);
  562.     free(tmp1);
  563.     if (gio_get_name(&tmp1))
  564.     {
  565.         *name = (char *)malloc(strlen(tmp1)+1);
  566.         if (!gio_get_list_end())
  567.             if (gio_get_string(&tmp2))
  568.             {
  569.                 *item = (char *)malloc(strlen(tmp2)+1);
  570.                 strcpy(*name, tmp1);
  571.                 strcpy(*item, tmp2);
  572.                 if (gio_get_list_end())
  573.                     return TRUE;
  574.                 return FALSE;
  575.             }
  576.         strcpy(*name, tmp1);
  577.         return TRUE;
  578.     }
  579.     return FALSE;
  580.  
  581. }
  582.  
  583.  
  584. /*
  585.  * Get the start of an object from the input file.  Returns TRUE if successful.
  586.  */
  587. int
  588. gio_get_object_begin()
  589. {
  590.     int        ch;
  591.  
  592.     while (isspace(ch = fgetc(Inp)))
  593.         ;
  594.     if (ch == *gio_object_begin_string())
  595.         return TRUE;
  596.     ungetc(ch, Inp);
  597.     return FALSE;
  598. }
  599.  
  600. /*
  601.  * Get the end of an object from the input file.  Returns TRUE if successful.
  602.  */
  603. int
  604. gio_get_object_end()
  605. {
  606.     int        ch;
  607.  
  608.     while (isspace(ch = fgetc(Inp)))
  609.         ;
  610.     if (ch == *gio_object_end_string())
  611.         return TRUE;
  612.     ungetc(ch, Inp);
  613.     return FALSE;
  614. }
  615.  
  616. /*
  617.  * Get a string from the input file.  Returns TRUE if successful.
  618.  * Sets the string pointer to a buffer allocated with malloc if the string
  619.  * is not empty, otherwise NULL.
  620.  */
  621. int
  622. #ifdef __STDC__
  623. gio_get_string(char **s)
  624. #else
  625. gio_get_string(s)
  626.     char          **s;
  627. #endif
  628. {
  629. #define    INC        32
  630.     int        ch;
  631.     int        lth;    /* string length */
  632.     int        c = 0;    /* string count */
  633.  
  634.     while (isspace(ch = fgetc(Inp)))
  635.         ;
  636.     if (ch != *gio_string_begin_string())
  637.     {
  638.         ungetc(ch, Inp);
  639.         return FALSE;
  640.     }
  641.  
  642.     if (gio_get_string_end())
  643.     {
  644.         *s = NULL;
  645.         return TRUE;
  646.     }
  647.  
  648.     *s = malloc(lth = INC);
  649.     while (((ch = fgetc(Inp)) != EOF) && (ch != *gio_string_end_string()))
  650.     {
  651.         if (c + 1 == lth)
  652.             *s = realloc(*s, lth += INC);
  653.         if (ch == '\\')
  654.             ch = fgetc(Inp);
  655.         (*s)[c++] = (char) ch;
  656.     }
  657.     (*s)[c] = '\0';
  658.     return TRUE;
  659. #undef INC
  660. }
  661.  
  662. /*
  663.  * Get the start of a string from the input file.  Returns TRUE if successful.
  664.  */
  665. int
  666. gio_get_string_begin()
  667. {
  668.     int        ch;
  669.  
  670.     while (isspace(ch = fgetc(Inp)))
  671.         ;
  672.     if (ch == *gio_string_begin_string())
  673.         return TRUE;
  674.     ungetc(ch, Inp);
  675.     return FALSE;
  676. }
  677.  
  678. /*
  679.  * Get the end of a string from the input file.  Returns TRUE if successful.
  680.  */
  681. int
  682. gio_get_string_end()
  683. {
  684.     int        ch;
  685.  
  686.     if ((ch = fgetc(Inp)) == *gio_string_end_string())
  687.         return TRUE;
  688.     ungetc(ch, Inp);
  689.     return FALSE;
  690. }
  691.  
  692. /*
  693.  * Write an integer to the output file.
  694.  */
  695. char           *
  696. #ifdef __STDC__
  697. gio_integer_string(int i)
  698. #else
  699. gio_integer_string(i)
  700.     int             i;
  701. #endif
  702. {
  703.     sprintf(Buf, "%d", i);
  704.     return Buf;
  705. }
  706.  
  707. /*
  708.  * Return the string representation of a keyword.
  709.  */
  710. char    *
  711. #ifdef __STDC__
  712. gio_keyword_string(char *s)
  713. #else
  714. gio_keyword_string(s)
  715.     char           *s;
  716. #endif
  717. {
  718.     return s;
  719. }
  720.  
  721. /*
  722.  * Return the list begin string.
  723.  */
  724. char           *
  725. gio_list_begin_string()
  726. {
  727.     return "(";
  728. }
  729.  
  730. /*
  731.  * Return the list end string.
  732.  */
  733. char           *
  734. gio_list_end_string()
  735. {
  736.     return ")";
  737. }
  738.  
  739. /*
  740.  * Return the string representation of a name.
  741.  */
  742. char           *
  743. #ifdef __STDC__
  744. gio_name_string(char *s)
  745. #else
  746. gio_name_string(s)
  747.     char           *s;
  748. #endif
  749. {
  750.     return s ? s : gio_false_string();
  751. }
  752.  
  753. /*
  754.  * Return the object begin string.
  755.  */
  756. char           *
  757. gio_object_begin_string()
  758. {
  759.     return "(";
  760. }
  761.  
  762. /*
  763.  * Return the object end string.
  764.  */
  765. char           *
  766. gio_object_end_string()
  767. {
  768.     return ")";
  769. }
  770.  
  771. /*
  772.  * Open an input file.  Returns NULL if successful, otherwise an error
  773.  * message.
  774.  */
  775. char           *
  776. #ifdef __STDC__
  777. gio_open_gil_input(char *name)
  778. #else
  779. gio_open_gil_input(name)
  780.     char           *name;
  781. #endif
  782. {
  783.     int    v;
  784.     char    *errmsg;
  785.  
  786.     /*
  787.      * If the input file exists and is the correct version, open it
  788.      * and skip leading comments.
  789.      */
  790.     if (Inp = fopen(name, "r"))
  791.     {
  792.         v = gil_version(Inp);
  793.         if ((v != 0) && (v <= G_VERSION))
  794.         {
  795.             skip_comments(Inp);
  796.             return NULL;
  797.         }
  798.         else
  799.             errmsg = "unrecognized file format"; /* No dgettext() wrapper on purpose */
  800.     }
  801.     else
  802.         errmsg = sys_errlist[errno]; 
  803.  
  804.     /*
  805.      * Otherwise, return an error message.
  806.      */
  807.     sprintf(Buf, "%s: %s", name, errmsg);
  808.  
  809.     return Buf;
  810. }
  811.  
  812. /*
  813.  * Open an output file.  Returns NULL if successful, otherwise an error
  814.  * message.
  815.  */
  816. char           *
  817. #ifdef __STDC__
  818. gio_open_gil_output(char *outfile)
  819. #else
  820. gio_open_gil_output(outfile)
  821.     char           *outfile;
  822. #endif
  823. {
  824.     struct stat    statbuf;
  825.     int        version_written = FALSE;
  826.  
  827.     /* 
  828.      * Look for the specified output file.
  829.      */
  830.     if (stat(outfile, &statbuf) != OK)
  831.     {
  832.         /* Output file does not exits.  Open a new one.
  833.          */
  834.         if (Outp = fopen(outfile, "w"))
  835.         {
  836.             /* First line is the version number.
  837.              */
  838.             fprintf(Outp, "%s%d\n", G_VERSION_PREFIX, G_VERSION);
  839.             return NULL;
  840.         }
  841.         else
  842.             goto ERROR_EXIT;
  843.     }
  844.     /*
  845.      * The output file exists.  Make sure we can successfully open it 
  846.      * before backing it up.
  847.      */
  848.     if (Outp = fopen(outfile, "a"))
  849.     {
  850.         char        backup[MAXPATHLEN];
  851.         FILE        *bakp = NULL;
  852.         char        *comment = gio_comment_string();
  853.         int        len = strlen(comment);
  854.  
  855.         /*
  856.          * Rename existing file to a backup and start a new output file.
  857.          */
  858.         fclose(Outp);
  859.         sprintf(backup, "%s.BAK", outfile);
  860.         if ((rename(outfile, backup) != OK) ||
  861.             !(bakp = fopen(backup, "r")) ||
  862.             !(Outp = fopen(outfile, "w")))
  863.             goto ERROR_EXIT; /* file access error */
  864.  
  865.         /* 
  866.          * Ignore any unrelated leading text until first comment (eg.
  867.          * garbage from mailtool).
  868.          */
  869.         while (fgets(Buf, sizeof (Buf), bakp) &&
  870.                strncmp(Buf, comment, len) != 0)
  871.             ;
  872.         /*
  873.          * Preserve any comments.
  874.          */
  875.         do
  876.         {
  877.             if (!version_written)
  878.             {
  879.                 /* First comment is always version number.
  880.                  */
  881.                 fprintf(Outp, "%s%d\n",
  882.                     G_VERSION_PREFIX,
  883.                     G_VERSION);
  884.                 version_written = TRUE;
  885.             }
  886.             else
  887.                 fputs(Buf, Outp);
  888.         }
  889.         while (fgets(Buf, sizeof (Buf), bakp) &&
  890.                strncmp(Buf, comment, len) == 0);
  891.  
  892.         fclose(bakp);
  893.         return NULL;
  894.     }
  895.  
  896.  ERROR_EXIT:
  897.     /*
  898.      * Return a message if unsuccessful.
  899.      */
  900.     sprintf(Buf, "%s: %s", outfile, sys_errlist[errno]);
  901.     return Buf;
  902. }
  903.  
  904.  
  905. /*
  906.  * Open an input proj file.  Returns NULL if successful, otherwise an error
  907.  * message.
  908.  */ 
  909. char    *
  910. #ifdef __STDC__
  911. gio_open_proj_input(char *name)
  912. #else
  913. gio_open_proj_input(name)
  914.     char    *name;
  915. #endif
  916. {
  917.     return gio_open_gil_input(name);
  918. }
  919.  
  920.  
  921. /*
  922.  * Open an output proj file.  Returns NULL if successful, otherwise an error
  923.  * message.
  924.  */
  925. char    *
  926. #ifdef __STDC__
  927. gio_open_proj_output(char *name)
  928. #else
  929. gio_open_proj_output(name)
  930.     char    *name;
  931. #endif
  932. {
  933.     return gio_open_gil_output(name);
  934. }
  935.  
  936.  
  937. /*
  938.  * Open an input resource file.    Returns NULL is successful, otherwise
  939.  * an error message.
  940.  */
  941. char    *
  942. #ifdef __STDC__
  943. gio_open_resfile_input(char *name)
  944. #else
  945. gio_open_resfile_input(name)
  946.     char    *name;
  947. #endif
  948. {
  949.     return gio_open_gil_input(name);
  950. }
  951.  
  952. /*
  953.  * Open an output file.  Returns NULL if successful, otherwise an error
  954.  * message.
  955.  */
  956. char           *
  957. #ifdef __STDC__
  958. gio_open_output(char *name)
  959. #else
  960. gio_open_output(name)
  961.     char           *name;
  962. #endif
  963. {
  964.     if (Outp = fopen(name, "w"))
  965.         return NULL;
  966.  
  967.     sprintf(Buf, "%s: %s", name, sys_errlist[errno]);
  968.     return Buf;
  969. }
  970.  
  971. /*
  972.  * fprintf to the current output file.
  973.  */
  974. #ifdef __STDC__
  975. void
  976. gio_printf(char *fmt, ...)
  977. #else
  978. void
  979. gio_printf(fmt, va_alist)
  980.     char    *fmt;
  981.     va_dcl
  982. #endif
  983. {
  984.     va_list        args;
  985.  
  986.     if (Newline)
  987.         fputs(Indent, Outp);
  988.  
  989.     va_start(args);
  990.     Newline = fmt[strlen(fmt) - 1] == '\n';
  991.     vfprintf(Outp, fmt, args);
  992.     va_end(args);
  993. }
  994.  
  995. /*
  996.  * Write a character to the output file, preceeded by the indent string if we
  997.  * are on a new line.
  998.  */
  999. void
  1000. #ifdef __STDC__
  1001. gio_putc(char c)
  1002. #else
  1003. gio_putc(c)
  1004.     char            c;
  1005. #endif
  1006. {
  1007.     if (Newline)
  1008.         fputs(Indent, Outp);
  1009.     fputc(c, Outp);
  1010.     Newline = c == '\n';
  1011. }
  1012.  
  1013. /*
  1014.  * Write characters to the output file, preceeded by the indent string if we
  1015.  * are on a new line.
  1016.  */
  1017. void
  1018. #ifdef __STDC__
  1019. gio_puts(char *s)
  1020. #else
  1021. gio_puts(s)
  1022.     char           *s;
  1023. #endif
  1024. {
  1025.     if (Newline)
  1026.         fputs(Indent, Outp);
  1027.     fputs(s, Outp);
  1028.     Newline = s[strlen(s) - 1] == '\n';
  1029. }
  1030.  
  1031. /*
  1032.  * Write a boolean to the output file.
  1033.  */
  1034. void
  1035. #ifdef __STDC__
  1036. gio_put_boolean(int b)
  1037. #else
  1038. gio_put_boolean(b)
  1039.     int             b;
  1040. #endif
  1041. {
  1042.     gio_puts(b ? gio_true_string() : gio_false_string());
  1043. }
  1044.  
  1045. /*
  1046.  * Write an integer to the output file.
  1047.  */
  1048. void
  1049. #ifdef __STDC__
  1050. gio_put_float(double d)
  1051. #else
  1052. gio_put_float(d)
  1053.     double    d;
  1054. #endif
  1055. {
  1056.     sprintf(Buf, "%f", d);
  1057.     gio_puts(Buf);
  1058. }
  1059.  
  1060. /*
  1061.  * Write an integer to the output file.
  1062.  */
  1063. void
  1064. #ifdef __STDC__
  1065. gio_put_integer(int i)
  1066. #else
  1067. gio_put_integer(i)
  1068.     int             i;
  1069. #endif
  1070. {
  1071.     sprintf(Buf, "%d", i);
  1072.     gio_puts(Buf);
  1073. }
  1074.  
  1075. /*
  1076.  * Write a keyword to the output file.
  1077.  */
  1078. void
  1079. #ifdef __STDC__
  1080. gio_put_keyword(char *s)
  1081. #else
  1082. gio_put_keyword(s)
  1083.     char        *s;
  1084. #endif
  1085. {
  1086.     gio_puts(s);
  1087. }
  1088.  
  1089. /*
  1090.  * Write a handler to the output file.
  1091.  */
  1092. void
  1093. #ifdef __STDC__
  1094. gio_put_handler(char *s)
  1095. #else
  1096. gio_put_handler(s)
  1097.     char           *s;
  1098. #endif
  1099. {
  1100.     char    *newstr;
  1101.     char    *p;
  1102.  
  1103.     if (s && (s[0] == *gio_string_begin_string()) &&
  1104.         (s[strlen(s)-1] == *gio_string_end_string())) {
  1105.         newstr = malloc(strlen(s) + 1);
  1106.         strcpy(newstr, s);
  1107.         newstr[strlen(s)-1] = '\0';
  1108.  
  1109.         fputc(*gio_string_begin_string(), Outp);
  1110.         for (p = newstr+1; *p; p++) {
  1111.             if ((*p == *gio_string_end_string()) || (*p == '\\'))
  1112.                 fputc('\\', Outp);
  1113.             fputc(*p, Outp);
  1114.         }
  1115.         fputc(*gio_string_end_string(), Outp);
  1116.         free(newstr);
  1117.     } else
  1118.         gio_put_name(s);
  1119. }
  1120.  
  1121. /*
  1122.  * Write a name list to the output file.
  1123.  */
  1124. void
  1125. #ifdef __STDC__
  1126. gio_put_name(char *s)
  1127. #else
  1128. gio_put_name(s)
  1129.     char           *s;
  1130. #endif
  1131. {
  1132.     gio_puts(s ? s : gio_false_string());
  1133. }
  1134.  
  1135. /*
  1136.  * Write a full name to the output file.
  1137.  */
  1138. void
  1139. #ifdef __STDC__
  1140. gio_put_full_name(char *parent, char *name, char *item)
  1141. #else
  1142. gio_put_full_name(parent, name, item)
  1143.     char        *parent;
  1144.     char        *name;
  1145.     char        *item;
  1146. #endif
  1147. {
  1148.     gio_puts(gio_list_begin_string());
  1149.     if (parent)
  1150.     {
  1151.         gio_puts(parent);
  1152.         gio_putc(' ');
  1153.     }
  1154.     if (name)
  1155.     {
  1156.         gio_puts(name);
  1157.     }
  1158.     if (item)
  1159.     {
  1160.         gio_putc(' ');
  1161.         gio_put_string(item);
  1162.     }
  1163.     gio_puts(gio_list_end_string());
  1164.     gio_putc('\n');
  1165. }
  1166.  
  1167. /*
  1168.  * Write a full name (the project form) to the output file.
  1169.  */
  1170. void
  1171. #ifdef __STDC__
  1172. gio_put_proj_full_name(char *interface, char *parent, char *name, char *item)
  1173. #else
  1174. gio_put_proj_full_name(interface, parent, name, item)
  1175.     char        *interface;
  1176.     char        *parent;
  1177.     char        *name;
  1178.     char        *item;
  1179. #endif
  1180. {
  1181.     gio_puts(gio_list_begin_string());
  1182.  
  1183.     if (interface)
  1184.      {
  1185.         gio_puts(interface);
  1186.         gio_putc(' ');
  1187.     }
  1188.     if (parent)
  1189.     {
  1190.         gio_puts(parent);
  1191.         gio_putc(' ');
  1192.     }
  1193.     if (name)
  1194.     {
  1195.         gio_puts(name);
  1196.     }
  1197.     if (item)
  1198.     {
  1199.         gio_putc(' ');
  1200.         gio_put_string(item);
  1201.     }
  1202.  
  1203.     gio_puts(gio_list_end_string());
  1204.     gio_putc('\n');
  1205. }
  1206.  
  1207.  
  1208. /*
  1209.  * Write a string to the output file.
  1210.  */
  1211. void
  1212. #ifdef __STDC__
  1213. gio_put_string(char *s)
  1214. #else
  1215. gio_put_string(s)
  1216.     char           *s;
  1217. #endif
  1218. {
  1219.     gio_puts(gio_string_begin_string());
  1220.     gio_put_string_to_file(s);
  1221.     gio_puts(gio_string_end_string());
  1222. }
  1223.  
  1224. /*
  1225.  * Write a string to the output file.
  1226.  */
  1227. void
  1228. #ifdef __STDC__
  1229. gio_put_string_to_file(char *s)
  1230. #else
  1231. gio_put_string_to_file(s)
  1232.     char           *s;
  1233. #endif
  1234. {
  1235.     register char    *p;
  1236.  
  1237.     if (s)
  1238.         for (p = s; *p; p++) {
  1239.             if (*p == *gio_string_end_string() ||
  1240.                 *p == '\\')
  1241.                 fputc('\\', Outp);
  1242.             fputc(*p, Outp);
  1243.         }
  1244. }
  1245.  
  1246. /*
  1247.  * Set the current indent level of the output file.
  1248.  */
  1249. void
  1250. #ifdef __STDC__
  1251. gio_set_indent(int level)
  1252. #else
  1253. gio_set_indent(level)
  1254.     int             level;
  1255. #endif
  1256. {
  1257.     register int    i;
  1258.  
  1259.     for (i = 0; i != level; i++)
  1260.         Indent[i] = '\t';
  1261.  
  1262.     Indent[i] = NULL;
  1263.     Indent_level = level;
  1264. }
  1265.  
  1266. /*
  1267.  * Get the current indent level of the output file.
  1268.  */
  1269. int
  1270. gio_get_indent()
  1271. {
  1272.     return Indent_level;
  1273. }
  1274.  
  1275. /*
  1276.  * Return the string begin string.
  1277.  */
  1278. char           *
  1279. gio_string_begin_string()
  1280. {
  1281.     return "\"";
  1282. }
  1283.  
  1284. /*
  1285.  * Return the string end string.
  1286.  */
  1287. char           *
  1288. gio_string_end_string()
  1289. {
  1290.     return "\"";
  1291. }
  1292.  
  1293. /*
  1294.  * Return the string representation of a string.  Truncates the string if
  1295.  * it is too long.
  1296.  */
  1297. char    *
  1298. #ifdef __STDC__
  1299. gio_string_string(char *s)
  1300. #else
  1301. gio_string_string(s)
  1302.     char           *s;
  1303. #endif
  1304. {
  1305.     char           *p;
  1306.     int        i = 0;
  1307.  
  1308.     Buf[i++] = *gio_string_begin_string();
  1309.     if (s)
  1310.         for (p = s; *p && i < MAXPATHLEN - 4; p++)
  1311.         {
  1312.             if (*p == *gio_string_end_string())
  1313.                 Buf[i++] = '\\';
  1314.             Buf[i++] = *p;
  1315.         }
  1316.     Buf[i++] = *gio_string_end_string();
  1317.     Buf[i] = '\0';
  1318.     return Buf;
  1319. }
  1320.  
  1321. /*
  1322.  * Return the boolean true string.
  1323.  */
  1324. char           *
  1325. gio_true_string()
  1326. {
  1327.     return "t";
  1328. }
  1329.  
  1330. /*
  1331.  * Internal utility functions.
  1332.  */
  1333.  
  1334. /*
  1335.  * Get the next token from the input stream.  It is assumed that we
  1336.  * are not at end-of-file.
  1337.  */
  1338. static char *
  1339. get_token()
  1340. {
  1341.     int        ch;
  1342.     int        c = 0;            /* character count */
  1343.  
  1344.     while (isspace(ch = fgetc(Inp)))
  1345.         ;
  1346.     do {
  1347.         if (c < sizeof (Buf) - 1)
  1348.             Buf[c++] = (char) ch;
  1349.     } while (!isspace(ch = fgetc(Inp)) && ch != ')');
  1350.  
  1351.     ungetc(ch, Inp);
  1352.     Buf[c] = '\0';
  1353.     return Buf;
  1354. }
  1355.  
  1356. /*
  1357.  * Return whether a file contains a GIL file.  Returns non-0 version
  1358.  * number if true, otherwise FALSE.  Leaves file positioned at the
  1359.  * beginning of first comment (should be version number).
  1360.  */
  1361. static int
  1362. #ifdef __STDC__
  1363. gil_version(FILE *fp)
  1364. #else
  1365. gil_version(fp)
  1366.     FILE           *fp;
  1367. #endif
  1368. {
  1369.     char    *ascii_version_num;
  1370.     char    *tmp;
  1371.     long    int_version_num;
  1372.     long    first_char;
  1373.     int    version = 0;
  1374.     int    len = strlen(G_VERSION_PREFIX);
  1375.  
  1376.     rewind(fp);
  1377.     while(fgets(Buf, sizeof (Buf), fp))
  1378.     {
  1379.         /* Ignore lines until a GIL prefix is found.
  1380.          */
  1381.         if (strncmp(Buf, G_VERSION_PREFIX, len) == 0)
  1382.         {
  1383.             /* Prefix matched.  Point to the version number and
  1384.              * convert it to an integer.
  1385.              */
  1386.             first_char = ftell(fp);
  1387.             Buf[strlen(Buf)-1] = '\0';
  1388.             ascii_version_num = Buf + len;
  1389.             int_version_num = strtol(ascii_version_num, &tmp, 10);
  1390.  
  1391.             if(ascii_version_num != tmp)
  1392.                 version = (int) int_version_num;
  1393.             fseek(fp, first_char, 0);
  1394.             break;
  1395.         }
  1396.     }
  1397.     return version;
  1398. }
  1399.  
  1400. /*
  1401.  * Skip leading comments in a GIL file.
  1402.  */
  1403. static void
  1404. #ifdef __STDC__
  1405. skip_comments(FILE *fp)
  1406. #else
  1407. skip_comments(fp)
  1408.     FILE           *fp;
  1409. #endif
  1410. {
  1411.     long        pos;
  1412.  
  1413.     for (;;) {
  1414.         pos = ftell(fp);
  1415.         if (!fgets(Buf, sizeof (Buf), fp) ||
  1416.             Buf[0] != *gio_comment_string())
  1417.             break;
  1418.     }
  1419.     fseek(fp, pos, 0);
  1420. }
  1421.