home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / GENCONF.C < prev    next >
C/C++ Source or Header  |  1994-07-27  |  12KB  |  436 lines

  1. /* Copyright (C) 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* genconf.c */
  20. /* Generate configuration files */
  21. #include "stdpre.h"
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>        /* for calloc */
  25. #include <string.h>
  26.  
  27. /*
  28.  * This program generates a set of configuration files.
  29.  * Almost everything it does could be done by a shell program, except that
  30.  * (1) Unix shells are not compatible from one system to another,
  31.  * (2) the DOS shell is not equal to the task,
  32.  * (3) the VMS shell is radically different from all others.
  33.  *
  34.  * Usage:
  35.  *    genconf [-Z] [@]xxx.dev* [-f gconfigf.h] [-h gconfig.h]
  36.  *      [-p[l|L][u][e] pattern] [-l|o|lo|ol out.tr]
  37.  * &s in a pattern produces a space; && produces a \; &x, for any other
  38.  * character x, produces x.
  39.  */
  40.  
  41. /* This program has to use K&R C, so it will work with old compilers. */
  42. /* Unfortunately, we have to hack up the function definitions by hand. */
  43.  
  44. /* Structures for accumulating information */
  45. typedef struct string_item_s {
  46.     char *str;
  47.     int index;
  48. } string_item;
  49. typedef struct string_list_s {
  50.     int max_count, count;
  51.     string_item *items;
  52. } string_list;
  53. #define max_pattern 60
  54. typedef struct string_pattern_s {
  55.     bool upper_case;
  56.     bool drop_extn;
  57.     char pattern[max_pattern + 1];
  58. } string_pattern;
  59. typedef struct config_s {
  60.     int debug;
  61.     string_list resources;
  62.     string_list devs;
  63.     string_list fonts;
  64.     string_list headers;
  65.     string_list libs;
  66.     string_list libpaths;
  67.     string_list objs;
  68.     string_pattern lib_p;
  69.     string_pattern libpath_p;
  70.     string_pattern obj_p;
  71. } config;
  72. static const config init_config = {
  73.     0, { 100 }, { 100 }, { 200 }, { 20 }, { 50 }, { 50 }, { 300 }
  74. };
  75.  
  76. /* Forward definitions */
  77. int alloc_list(P1(string_list *));
  78. void parse_affix(P2(char *, const char *));
  79. int read_dev(P2(config *, const char *));
  80. int read_token(P3(char *, int, FILE *));
  81. int add_entry(P3(config *, char *, const char *));
  82. void sort_uniq(P1(string_list *));
  83. void write_list(P3(FILE *, const string_list *, const char *));
  84. void write_list_pattern(P3(FILE *, const string_list *, const string_pattern *));
  85.  
  86. main(argc, argv) int argc; char *argv[];
  87. {    config conf;
  88.     int i;
  89.  
  90.     /* Allocate string lists. */
  91.     conf = init_config;
  92.     alloc_list(&conf.resources);
  93.     alloc_list(&conf.devs);
  94.     alloc_list(&conf.fonts);
  95.     alloc_list(&conf.headers);
  96.     alloc_list(&conf.libs);
  97.     alloc_list(&conf.libpaths);
  98.     alloc_list(&conf.objs);
  99.  
  100.     /* Initialize patterns. */
  101.     conf.lib_p.upper_case = false;
  102.     conf.lib_p.drop_extn = false;
  103.     strcpy(conf.lib_p.pattern, "%s\n");
  104.     conf.libpath_p = conf.lib_p;
  105.     conf.obj_p = conf.lib_p;
  106.  
  107.     /* Process command line arguments. */
  108.     for ( i = 1; i < argc; i++ )
  109.     {    const char *arg = argv[i];
  110.         FILE *out;
  111.         int lib = 0, obj = 0;
  112.         if ( *arg != '-' )
  113.         {    read_dev(&conf, arg);
  114.             continue;
  115.         }
  116.         if ( i == argc - 1 )
  117.         {    fprintf(stderr, "Missing argument after %s.\n",
  118.                 arg);
  119.             exit(1);
  120.         }
  121.         switch ( arg[1] )
  122.         {
  123.         case 'p':
  124.         {    string_pattern *pat;
  125.             switch ( *(arg += 2) )
  126.             {
  127.             case 'l': pat = &conf.lib_p; break;
  128.             case 'L': pat = &conf.libpath_p; break;
  129.             default: pat = &conf.obj_p; arg--;
  130.             }
  131.             pat->upper_case = false;
  132.             pat->drop_extn = false;
  133.             if ( argv[i + 1][0] == '-' )
  134.                 strcpy(pat->pattern, "%s\n");
  135.             else
  136.             {    char *p, *q;
  137.                 for ( p = pat->pattern, q = argv[++i];
  138.                       (*p++ = *q++) != 0;
  139.                     )
  140.                  if ( p[-1] == '&' )
  141.                   switch ( *q )
  142.                 {
  143.                 case 's': p[-1] = ' '; q++; break;
  144.                 case '&': p[-1] = '\\'; q++; break;
  145.                 default: p--;
  146.                 }
  147.                 p[-1] = '\n';
  148.                 *p = 0;
  149.             }
  150.             for ( ; ; )
  151.               switch ( *++arg )
  152.             {
  153.             case 'u': pat->upper_case = true; break;
  154.             case 'e': pat->drop_extn = true; break;
  155.             case 0: goto pbreak;
  156.             default:
  157.                 fprintf(stderr, "Unknown switch %s.\n", arg);
  158.                 exit(1);
  159.             }
  160. pbreak:            if ( pat == &conf.obj_p )
  161.             {    conf.lib_p = *pat;
  162.                 conf.libpath_p = *pat;
  163.             }
  164.             continue;
  165.         case 'Z':
  166.             conf.debug = 1;
  167.             continue;
  168.         }
  169.         }
  170.         /* Must be an output file. */
  171.         out = fopen(argv[++i], "w");
  172.         if ( out == 0 )
  173.         {    fprintf(stderr, "Can't open %s for output.\n",
  174.                 argv[i]);
  175.             exit(1);
  176.         }
  177.         switch ( arg[1] )
  178.         {
  179.         case 'f':
  180.             fputs("/* This file was generated automatically by genconf.c. */\n", out);
  181.             fputs("/* For documentation, see gsconfig.c. */\n", out);
  182.             write_list(out, &conf.fonts,
  183.                    "font_(\"0.font_%s\",gsf_%s,zf_%s)\n");
  184.             break;
  185.         case 'h':
  186.             fputs("/* This file was generated automatically by genconf.c. */\n", out);
  187.             write_list(out, &conf.devs, "device_(gs_%s_device)\n");
  188.             sort_uniq(&conf.resources);
  189.             write_list(out, &conf.resources, "%s\n");
  190.             write_list(out, &conf.headers, "#include \"%s\"\n");
  191.             break;
  192.         case 'l':
  193.             lib = 1;
  194.             obj = arg[2] == 'o';
  195.             goto lo;
  196.         case 'o':
  197.             obj = 1;
  198.             lib = arg[2] == 'l';
  199. lo:            if ( obj )
  200.             {    sort_uniq(&conf.objs);
  201.                 write_list_pattern(out, &conf.objs, &conf.obj_p);
  202.             }
  203.             if ( lib )
  204.             {    write_list_pattern(out, &conf.libpaths, &conf.libpath_p);
  205.                 write_list_pattern(out, &conf.libs, &conf.lib_p);
  206.             }
  207.             break;
  208.         default:
  209.             fclose(out);
  210.             fprintf(stderr, "Unknown switch %s.\n", argv[i]);
  211.             exit(1);
  212.         }
  213.         fclose(out);
  214.     }
  215.  
  216.     exit(0);
  217. }
  218.  
  219. /* Allocate and initialize a string list. */
  220. int
  221. alloc_list(list) string_list *list;
  222. {    list->count = 0;
  223.     list->items =
  224.         (string_item *)calloc(list->max_count, sizeof(string_item));
  225.     return 0;
  226. }
  227.  
  228. /* Read and parse a .dev file. */
  229. int
  230. read_dev(pconf, arg) config *pconf; const char *arg;
  231. {    FILE *in;
  232. #define max_token 256
  233.     char token[max_token];
  234.     int len;
  235.     if ( pconf->debug )
  236.         printf("Reading %s;\n", arg);
  237.     if ( arg[0] == '@' )
  238.     {    in = fopen(arg + 1, "r");
  239.         if ( in == 0 )
  240.         {    fprintf(stderr, "Can't read %s.\n", arg + 1);
  241.             exit(1);
  242.         }
  243.         while ( (len = read_token(token, max_token, in)) > 0 )
  244.             read_dev(pconf, token);
  245.     }
  246.     else
  247.     {    char category[max_token];
  248.         in = fopen(arg, "r");
  249.         if ( in == 0 )
  250.         {    fprintf(stderr, "Can't read %s.\n", arg);
  251.             exit(1);
  252.         }
  253.         strcpy(category, "obj");
  254.         while ( (len = read_token(token, max_token, in)) > 0 )
  255.             add_entry(pconf, category, token);
  256.     }
  257. #undef max_token
  258.     fclose(in);
  259.     if ( len < 0 )
  260.     {    fprintf(stderr, "Token too long: %s.\n", token);
  261.         exit(1);
  262.     }
  263.     if ( pconf->debug )
  264.         printf("Finished %s.\n", arg);
  265.     return 0;
  266. }
  267.  
  268. /* Read a token from a file. */
  269. int
  270. read_token(token, max_len, in) char *token; int max_len; FILE *in;
  271. {    int len = 0;
  272.     for ( ; ; ) 
  273.     {    char ch = fgetc(in);
  274.         token[len] = 0;
  275.         if ( feof(in) )
  276.             return len;
  277.         if ( isspace(ch) )
  278.         {    if ( len > 0 )
  279.                 return len;
  280.             continue;
  281.         }
  282.         if ( len == max_len )
  283.             return -1;    /* token too long */
  284.         token[len++] = ch;
  285.     }
  286. }
  287.  
  288. /* Add an entry to a configuration. */
  289. int
  290. add_entry(pconf, category, item) config *pconf; char *category; const char *item;
  291. {    if ( item[0] == '-' )        /* set category */
  292.         strcpy(category, item + 1);
  293.     else                /* add to current category */
  294.     {    char str[80];
  295.         const char *pat = "%s";
  296.         char *rstr;
  297.         string_list *list = &pconf->resources;
  298.         int count;
  299.         if ( pconf->debug )
  300.             printf("Adding %s %s;\n", category, item);
  301.         /* Handle a few resources specially: */
  302.         if ( !strcmp(category, "dev") )
  303.             list = &pconf->devs;
  304.         else if ( !strcmp(category, "font") )
  305.             list = &pconf->fonts;
  306.         else if ( !strcmp(category, "header") )
  307.             list = &pconf->headers;
  308.         else if ( !strcmp(category, "include") )
  309.         {    strcpy(str, item);
  310.             strcat(str, ".dev");
  311.             read_dev(pconf, str);
  312.             return 0;
  313.         }
  314.         else if ( !strcmp(category, "lib") )
  315.             list = &pconf->libs;
  316.         else if ( !strcmp(category, "libpath") )
  317.             list = &pconf->libpaths;
  318.         else if ( !strcmp(category, "obj") )
  319.             list = &pconf->objs;
  320.         /* Now handle all other resources. */
  321.         else if ( !strcmp(category, "iodev") )
  322.             pat = "io_device_(gs_iodev_%s)";
  323.         else if ( !strcmp(category, "oper") )
  324.             pat = "oper_(%s_op_defs)";
  325.         else if ( !strcmp(category, "ps") )
  326.             pat = "psfile_(\"%s.ps\")";
  327.         else
  328.         {    fprintf(stderr, "Unknown category %s.\n", category);
  329.             exit(1);
  330.         }
  331.         sprintf(str, pat, item);
  332.         rstr = malloc(strlen(str) + 1);
  333.         strcpy(rstr, str);
  334.         count = list->count++;
  335.         list->items[count].index = count;
  336.         list->items[count].str = rstr;
  337.     }
  338.     return 0;
  339. }
  340.  
  341. /* Sort and uniq an array of string items. */
  342. /* In case of duplicates, remove all but the earliest. */
  343. #define psi1 ((const string_item *)p1)
  344. #define psi2 ((const string_item *)p2)
  345. int
  346. cmp_index(p1, p2) const void *p1; const void *p2;
  347. {    int cmp = psi1->index - psi2->index;
  348.     return (cmp < 0 ? -1 : cmp > 0 ? 1 : 0);
  349. }
  350. int
  351. cmp_str(p1, p2) const void *p1; const void *p2;
  352. {    int cmp = strcmp(psi1->str, psi2->str);
  353.     return (cmp != 0 ? cmp : cmp_index(p1, p2));
  354. }
  355. #undef psi1
  356. #undef psi2
  357. void
  358. sort_uniq(list) string_list *list;
  359. {    string_item *strlist = list->items;
  360.     int count = list->count;
  361.     const string_item *from;
  362.     string_item *to;
  363.     int i;
  364.     if ( count == 0 )
  365.         return;
  366.     qsort((char *)strlist, count, sizeof(string_item), cmp_str);
  367.     for ( from = to = strlist + 1, i = 1; i < count; from++, i++ )
  368.       if ( strcmp(from->str, to[-1].str) )
  369.         *to++ = *from;
  370.     count = to - strlist;
  371.     list->count = count;
  372.     qsort((char *)strlist, count, sizeof(string_item), cmp_index);
  373. }
  374.  
  375. /* Write a list of strings using a template. */
  376. void
  377. write_list(out, list, pstr) FILE *out; const string_list *list; const char *pstr;
  378. {    string_pattern pat;
  379.     pat.upper_case = false;
  380.     pat.drop_extn = false;
  381.     strcpy(pat.pattern, pstr);
  382.     write_list_pattern(out, list, &pat);
  383. }
  384. void
  385. write_list_pattern(out, list, pat) FILE *out; const string_list *list; const string_pattern *pat;
  386. {    int i;
  387.     char macname[40];
  388.     int plen = strlen(pat->pattern);
  389.     *macname = 0;
  390.     for ( i = 0; i < list->count; i++ )
  391.     {    const char *lstr = list->items[i].str;
  392.         int len = strlen(lstr);
  393.         char *str = malloc(len + 1);
  394.         int xlen = plen + len * 3;
  395.         char *xstr = malloc(xlen + 1);
  396.         char *alist;
  397.         strcpy(str, lstr);
  398.         if ( pat->drop_extn )
  399.         {    char *dot = str + len;
  400.             while ( dot > str && *dot != '.' ) dot--;
  401.             if ( dot > str ) *dot = 0, len = dot - str;
  402.         }
  403.         if ( pat->upper_case )
  404.         {    char *ptr = str;
  405.             for ( ; *ptr; ptr++ )
  406.               if ( islower(*ptr) ) *ptr = toupper(*ptr);
  407.         }
  408.         /* We repeat str for the benefit of patterns that */
  409.         /* need the argument substituted in more than one place. */
  410.         sprintf(xstr, pat->pattern, str, str, str);
  411.         /* Check to make sure the item is within the scope of */
  412.         /* an appropriate #ifdef, if necessary. */
  413.         alist = strchr(xstr, '(');
  414.         if ( alist != 0 && alist != xstr && alist[-1] == '_' )
  415.         {    *alist = 0;
  416.             if ( strcmp(xstr, macname) )
  417.             {    if (*macname )
  418.                     fputs("#endif\n", out);
  419.                 fprintf(out, "#ifdef %s\n", xstr);
  420.                 strcpy(macname, xstr);
  421.             }
  422.             *alist = '(';
  423.         }
  424.         else
  425.         {    if ( *macname )
  426.             {    fputs("#endif\n", out);
  427.                 *macname = 0;
  428.             }
  429.         }
  430.         fputs(xstr, out);
  431.         free(str);
  432.     }
  433.     if ( *macname )
  434.         fputs("#endif\n", out);
  435. }
  436.