text: /*
  **++
  **  FACILITY:	MMK_COMPILE_RULES
  **
  **  ABSTRACT:	Code to generate the C code for the initialization structures
  **  	    	for compiled rules.
  **
  **  MODULE DESCRIPTION:
  **
  **  	Generates C structure definitions for symbols, rules, and
  **  suffixes for use as the default rules compiled into MMK.
  **
  **  AUTHOR: 	    M. Madison
  **
  **  Copyright (c) 2008, Matthew Madison.
  **  
  **  All rights reserved.
  **  
  **  Redistribution and use in source and binary forms, with or without
  **  modification, are permitted provided that the following conditions
  **  are met:
  **  
  **      * Redistributions of source code must retain the above
  **        copyright notice, this list of conditions and the following
  **        disclaimer.
  **      * Redistributions in binary form must reproduce the above
  **        copyright notice, this list of conditions and the following
  **        disclaimer in the documentation and/or other materials provided
  **        with the distribution.
  **      * Neither the name of the copyright owner nor the names of any
  **        other contributors may be used to endorse or promote products
  **        derived from this software without specific prior written
  **        permission.
  **  
  **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  **  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  **  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  **  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  **  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  **  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  **  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  **  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  **  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  **
  **  CREATION DATE:  30-APR-1993
  **
  **  MODIFICATION HISTORY:
  **
  **  	30-APR-1993 V1.0    Madison 	Initial coding.
  **  	04-JUN-1993 V1.1    Madison 	Add default rule support.
  **  	22-DEC-1996 V1.2    Madison 	Support for MMK V3.6.
  **  	27-DEC-1998 V1.2-1  Madison 	General cleanup.
  **	03-JUN-2009 V1.3    Sneddon	Added support for type in SYMBOL.
  **--
  */
  #pragma module GENSTRUC "V1.3"
  #include "mmk.h"
  #include "globals.h"
  #include <stdio.h>
  
  /*
  **  Forward declarations
  */
      void Generate_Structures(char *, char *);
      static void fix_string(char *, char *);
  
  /*
  **  External references
  */
      extern char *Version, *Copyright;
  
  #define PUT(str) {char *cp = (str); file_write(unit, cp, strlen(cp));}
  
  
  /*
  **++
  **  ROUTINE:	Generate_Structures
  **
  **  FUNCTIONAL DESCRIPTION:
  **
  **  	Generates C structure definitions for symbols, rules, and
  **  suffixes for use as the default rules compiled into MMK.
  **
  **  RETURNS:	cond_value, longword (unsigned), write only, by value
  **
  **  PROTOTYPE:
  **
  **  	Generate_Structures(char *in, char *out)
  **
  **  in:	    ASCIZ_string, read only, by reference
  **  out:    ASCIZ_string, read only, by reference
  **
  **  IMPLICIT INPUTS:	suffixes, rules, global_symbols.
  **
  **  IMPLICIT OUTPUTS:	None.
  **
  **  COMPLETION CODES:	None.
  **
  **  SIDE EFFECTS:   	None.
  **
  **--
  */
  void Generate_Structures(char *infile, char *outfile) {
  
      static $DESCRIPTOR(hdr1, "** generated by MMK_COMPILE_RULES !AD !%D");
      char tmp[256], tmp2[256], tmp3[256], tmp4[256], tmp5[256], *cp;
      struct dsc$descriptor dsc;
      struct SYMBOL *sym;
      struct RULE *rule, *xrule;
      struct CMD *cmd;
      struct SFX *sfx;
      FILEHANDLE unit;
      unsigned int status;
      int i, j, realcount, lastrealidx;
  
      INIT_DYNDESC(dsc);
  
      if (outfile[0] == '\0') {
      	cp = "MMK_DEFAULT_RULES.H";
      } else {
      	cp = outfile;
      }
  
      status = file_create(cp, &unit, "");
      if (!OK(status)) lib$stop(status);
  
      status = file_write(unit, "/*", 2);
      lib$sys_fao(&hdr1, 0, &dsc, strlen(Version), Version, 0);
      status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      strcpy(tmp, "** from file ");
      strcat(tmp, infile);
      status = file_write(unit, tmp, strlen(tmp));
      strcpy(tmp, "** ");
      strcat(tmp, Copyright);
      status = file_write(unit, tmp, strlen(tmp));
      status = file_write(unit, "*/", 2);
      status = file_write(unit, "", 0);
  
      PUT("static struct SFX sfx_init[] = {");
      for (sfx = suffixes.flink, i = 0; sfx != (struct SFX *) &suffixes;
      	    	sfx = sfx->flink, i++) {
      	static $DESCRIPTOR(fao, "    !AD{0,0,\"!AD\"}");
      	fix_string(sfx->value, tmp);
      	lib$sys_fao(&fao, 0, &dsc, (i > 0 ? 1 : 0), (i > 0 ? "," : ""),
      	    strlen(tmp), tmp);
      	status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      }
      PUT("};");
      sprintf(tmp, "#define SFX_INIT_COUNT  %d", i);
      PUT(tmp);
  
      PUT("static struct SYMBOL gsym_init[] = {");
      i = 0;
      for (j = 0; j < MMK_K_SYMTABLE_SIZE; j++) {
      	for (sym = global_symbols.symlist[j].head;
      	    	sym != (struct SYMBOL *) &global_symbols.symlist[j];
      	    	sym = sym->flink) {
      	    static $DESCRIPTOR(fao, "    !AD{0,0,!UL,\"!AD\",\"!AD\"}");
      	    fix_string(sym->name, tmp);
      	    fix_string(sym->value, tmp2);
      	    lib$sys_fao(&fao, 0, &dsc, (i > 0 ? 1 : 0), (i > 0 ? "," : ""),
      	    	MMK_K_SYM_DEFAULT, strlen(tmp), tmp, strlen(tmp2), tmp2);
      	    status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      	    i += 1;
      	}
      }
      PUT("};");
      sprintf(tmp, "#define GSYM_INIT_COUNT  %d", i);
      PUT(tmp);
  
      for (xrule = rules.flink, i = 0;
      	    	xrule != (struct RULE *) &rules;
      	    	xrule = xrule->flink) {
      	for (rule = xrule; rule != 0; rule = rule->next) {
      	    if (rule->cmdque.flink != &rule->cmdque) {
      	    	sprintf(tmp, "static struct CMD cmdq_init_%d[] = {", i);
      	    	PUT(tmp);
      	    	for (cmd = rule->cmdque.flink, j = 0; cmd != &rule->cmdque;
      	    	    	cmd = cmd->flink, j++) {
      	    	    static $DESCRIPTOR(fao, "    !AD{0,0,0X!XL,\"!AD\"}");
      	    	    fix_string(cmd->cmd, tmp);
      	    	    lib$sys_fao(&fao, 0, &dsc, (j > 0 ? 1 : 0), (j > 0 ? "," : ""),
      	    	    	cmd->flags, strlen(tmp), tmp);
      	    	    status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      	    	}
      	    	PUT("};");
      	    	rule->cmdque.flags = j;
      	    	rule->cmdque.cmd = (char *) i;
      	    	i += 1;
      	    }
      	}
      }
  
      if (default_rule != 0) {
      	if (default_rule->cmdque.flink != &default_rule->cmdque) {
      	    sprintf(tmp, "static struct CMD cmdq_init_%d[] = {", i);
      	    PUT(tmp);
      	    for (cmd = default_rule->cmdque.flink, j = 0; cmd != &default_rule->cmdque;
      	    	    cmd = cmd->flink, j++) {
      	    	static $DESCRIPTOR(fao, "    !AD{0,0,0X!XL,\"!AD\"}");
      	    	fix_string(cmd->cmd, tmp);
      	    	lib$sys_fao(&fao, 0, &dsc, (j > 0 ? 1 : 0), (j > 0 ? "," : ""),
      	    	    cmd->flags, strlen(tmp), tmp);
      	    	status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      	    }
      	    PUT("};");
      	    default_rule->cmdque.flags = j;
      	    default_rule->cmdque.cmd = (char *) i;
      	    i += 1;
      	}
      }
  
      PUT("static struct RULE rule_init[] = {");
      for (xrule = rules.flink, i = realcount = 0;
      	    	xrule != (struct RULE *) &rules;
      	    	xrule = xrule->flink, realcount++) {
      	static $DESCRIPTOR(fao, "    !AD{0,0,(struct RULE *) !UL,0,!UL,!UL,\"!AD\",\"!AD\",\"!AD\",\"!AD\",{!AD,0,!UL,0}}");
      	lastrealidx = i;
      	for (rule = xrule; rule != 0; rule = rule->next) {
      	    sprintf(tmp, "(void *)&cmdq_init_%d[0]", (int) rule->cmdque.cmd);
      	    fix_string(rule->src, tmp2);
      	    fix_string(rule->trg, tmp3);
      	    fix_string(rule->srcpfx, tmp4);
      	    fix_string(rule->trgpfx, tmp5);
      	    lib$sys_fao(&fao, 0, &dsc, (i > 0 ? 1 : 0), (i > 0 ? "," : ""),
      	    	(rule->next == 0 ? 0 : 1),
      	    	rule->srcpfxlen, rule->trgpfxlen,
     	    	strlen(tmp2), tmp2, strlen(tmp3), tmp3,
      	    	strlen(tmp4), tmp4, strlen(tmp5), tmp5,
      	    	(rule->cmdque.flink == &rule->cmdque ? 0 : strlen(tmp)),
      	    	(rule->cmdque.flink == &rule->cmdque ? "" : tmp),
      	    	(rule->cmdque.flink == &rule->cmdque ? 0 : rule->cmdque.flags));
      	    status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      	    i++;
      	}
      }
      PUT("};");
      sprintf(tmp, "#define RULE_INIT_COUNT  %d", i);
      PUT(tmp);
      sprintf(tmp, "#define RULE_INIT_COUNT_REAL  %d", realcount);
      PUT(tmp);
      sprintf(tmp, "#define RULE_REAL_LAST_IDX  %d", lastrealidx);
      PUT(tmp);
      if (default_rule != 0) {
      	static $DESCRIPTOR(fao, "    0,0,0,0,0,0,0,0,{!AD,0,!UL,0}}");
      	PUT("#define DEFAULT_RULE_EXISTS 1");
      	PUT("static struct RULE default_rule_init = {");
      	sprintf(tmp, "(void *)&cmdq_init_%d[0]", (int) default_rule->cmdque.cmd);
      	lib$sys_fao(&fao, 0, &dsc,
      	    (default_rule->cmdque.flink == &default_rule->cmdque ? 0 : strlen(tmp)),
      	    (default_rule->cmdque.flink == &default_rule->cmdque ? "" : tmp),
      	    (default_rule->cmdque.flink == &default_rule->cmdque ? 0 : default_rule->cmdque.flags));
      	status = file_write(unit, dsc.dsc$a_pointer, dsc.dsc$w_length);
      }
  
      file_close(unit);
  
      return;
  
  } /* Generate_Structures */
  
  /*
  **++
  **  ROUTINE:	fix_string
  **
  **  FUNCTIONAL DESCRIPTION:
  **
  **  	Fixes up special characters appearing in character strings by
  **  quoting them with a backslash.
  **
  **  RETURNS:	cond_value, longword (unsigned), write only, by value
  **
  **  PROTOTYPE:
  **
  **  	fix_string(char *in, char *out)
  **
  **  IMPLICIT INPUTS:	None.
  **
  **  IMPLICIT OUTPUTS:	None.
  **
  **  COMPLETION CODES:	None.
  **
  **  SIDE EFFECTS:   	None.
  **
  **--
  */
  static void fix_string(char *in, char *out) {
  
      register char *cp, *cp1;
  
      for (cp = in, cp1 = out; *cp; cp++) {
      	if (*cp == '\\' || *cp == '"') *cp1++ = '\\';
      	*cp1++ = *cp;
      }
      *cp1 = '\0';
  
      return;
  
  } /* fix_string */
  