home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / linuxdoc-sgml-1.1 / sgmls-1.1 / entgen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  9.7 KB  |  406 lines

  1. /* entgen.c -
  2.  
  3.    Implement entgen() which generates a list of filenames from a struct fpi.
  4.    
  5.    Written by James Clark (jjc@jclark.com).
  6. */
  7.  
  8. #include "config.h"
  9.  
  10. #ifdef HAVE_ACCESS
  11.  
  12. #ifdef HAVE_UNISTD_H
  13. #include <unistd.h>        /* For R_OK. */
  14. #endif /* HAVE_UNISTD_H */
  15.  
  16. #ifndef R_OK
  17. #define R_OK 4
  18. #endif /* not R_OK */
  19.  
  20. #endif /* HAVE_ACCESS */
  21.  
  22. #include "sgmlaux.h"
  23.  
  24. /* Environment variable that contains path. */
  25. #ifndef PATH_ENV_VAR
  26. #define PATH_ENV_VAR "SGML_PATH"
  27. #endif
  28. /* Default search path.  See field() for interpretation of %*. */
  29. #ifndef DEFAULT_PATH
  30. #define DEFAULT_PATH "/usr/local/lib/sgml/%O/%C/%T:%N.%X:%N.%D"
  31. #endif
  32.  
  33. #ifndef PATH_FILE_SEP
  34. #define PATH_FILE_SEP ':'
  35. #endif
  36.  
  37. #ifndef SYSID_FILE_SEP
  38. #define SYSID_FILE_SEP ':'
  39. #endif
  40.  
  41. /* This says: change space to underscore, slash to percent. */
  42.  
  43. #ifndef MIN_DAT_SUBS_FROM
  44. #define MIN_DAT_SUBS_FROM " /"
  45. #endif
  46. #ifndef MIN_DAT_SUBS_TO
  47. #define MIN_DAT_SUBS_TO "_%"
  48. #endif
  49.  
  50. static int field P((struct fpi *, int, char *));
  51. static int mindatcpy P((char *, char *, int, int));
  52. static int testopen P((char *));
  53. static UNIV sysidgen P((char *));
  54.  
  55. static char *path = 0;
  56.  
  57. /* Non-zero if searching should be performed when a system identifier
  58. is specified. */
  59. static int sysidsrch = 0;
  60.  
  61. #define EMPTY_VERSION "default"
  62.  
  63. static char *classes[] = {
  64.      "capacity",
  65.      "charset",
  66.      "notation",
  67.      "syntax",
  68.      "document",
  69.      "dtd",
  70.      "elements",
  71.      "entities",
  72.      "lpd",
  73.      "nonsgml",
  74.      "shortref",
  75.      "subdoc",
  76.      "text"
  77.      };
  78.  
  79. /* This is mainly for compatibility with arcsgml. */
  80.  
  81. static char *genext[] = {
  82.      "nsd",  /* Non-SGML data entity. */
  83.      "gml",  /* GML document or text entity. */
  84.      "spe",  /* System parameter entity. */
  85.      "dtd",  /* Document type definition. */
  86.      "lpd",  /* Link process definition. */
  87.      "pns",  /* Public non-SGML data entity. */
  88.      "pge",  /* Public general entity. */
  89.      "ppe",  /* Public parameter entity. */
  90.      "pdt",  /* Public document type definition. */
  91.      "plp",  /* Public link process definition. */
  92.      "vns",  /* Display version non-SGML data entity. */
  93.      "vge",  /* Display version general entity. */
  94.      "vpe",  /* Display version parameter entity. */
  95.      "vdt",  /* Display version document type definition.*/
  96.      "vlp",  /* Display version link process definition.*/
  97. };
  98.  
  99. static char *ext[] = {
  100.      "sgml",            /* SGML subdocument */
  101.      "data",            /* Data */
  102.      "text",            /* General text */
  103.      "parm",            /* Parameter entity */
  104.      "dtd",            /* Document type definition */
  105.      "lpd",            /* Link process definition */
  106. };
  107.  
  108. /* Like memcpy, but substitute, fold to lower case (if fold is
  109. non-zero) and null terminate.  This is used both for minimum data and
  110. for names. If p is NULL, do nothing. Return len. */
  111.  
  112. static int mindatcpy(p, q, len, fold)
  113. char *p, *q;
  114. int len;
  115. int fold;
  116. {
  117.      static char subsfrom[] = MIN_DAT_SUBS_FROM;
  118.      static char substo[] = MIN_DAT_SUBS_TO;
  119.      int n;
  120.  
  121.      if (!p)
  122.       return len;
  123.      for (n = len; --n >= 0; q++) {
  124.       char *r = strchr(subsfrom, *q);
  125.       if (!r) {
  126.            if (fold && ISASCII(*q) && isupper((UNCH)*q))
  127.             *p++ = tolower((UNCH)*q);
  128.            else
  129.             *p++ = *q;
  130.       }
  131.       else {
  132.            int i = r - subsfrom;
  133.            if (i < sizeof(substo) - 1)
  134.             *p++ = substo[i];
  135.       }
  136.      }
  137.      *p = '\0';
  138.      return len;
  139. }
  140.  
  141.  
  142. /* Return length of field.  Copy into buf if non-NULL. */
  143.  
  144. static int field(f, c, buf)
  145. struct fpi *f;
  146. int c;
  147. char *buf;
  148. {
  149.      int n;
  150.  
  151.      switch (c) {
  152.      case '%':
  153.       if (buf) {
  154.            buf[0] = '%';
  155.            buf[1] = '\0';
  156.       }
  157.       return 1;
  158.      case 'N':            /* the entity, document or dcn name */
  159.       return mindatcpy(buf, (char *)f->fpinm, ustrlen(f->fpinm),
  160.             (f->fpistore != 1 && f->fpistore != 2 && f->fpistore != 3
  161.              ? NAMECASE
  162.              : ENTCASE));
  163.      case 'D':            /* dcn name */
  164.       if (f->fpistore != 1) /* not a external data entity */
  165.            return -1;
  166.       if (f->fpinedcn == 0) /* it's a SUBDOC */
  167.            return -1;
  168.       return mindatcpy(buf, (char *)f->fpinedcn, ustrlen(f->fpinedcn),
  169.                           NAMECASE);
  170.      case 'X':
  171.       /* This is for compatibility with arcsgml */
  172.       if (f->fpistore < 1 || f->fpistore > 5)
  173.            return -1;
  174.       n = (f->fpipubis != 0)*(f->fpiversw > 0 ? 2 : 1)*5+f->fpistore - 1;
  175.       if (buf)
  176.            strcpy(buf, genext[n]);
  177.       return strlen(genext[n]);
  178.      case 'Y':            /* tYpe */
  179.       n = f->fpistore;
  180.       if (n < 1 || n > 5)
  181.            return -1;
  182.       if (n == 1 && f->fpinedcn == 0) /* it's a SUBDOC */
  183.            n = 0;
  184.       if (buf)
  185.            strcpy(buf, ext[n]);
  186.       return strlen(ext[n]);
  187.      case 'P':            /* public identifier */
  188.       if (!f->fpipubis)
  189.            return -1;
  190.       return mindatcpy(buf, (char *)f->fpipubis, ustrlen(f->fpipubis), 0);
  191.      case 'S':            /* system identifier */
  192.       if (!f->fpisysis)
  193.            return -1;
  194.       else {
  195.            UNCH *p;
  196.            n = 0;
  197.            for (p = f->fpisysis; *p; p++)
  198.             if (*p != RSCHAR) {
  199.              if (buf)
  200.                   buf[n] = *p == RECHAR ? '\n' : *p;
  201.              n++;
  202.             }
  203.            return n;
  204.       }
  205.      }
  206.      /* Other fields need a formal public identifier. */
  207.      /* return -1 if the formal public identifier was invalid or missing. */
  208.      if (f->fpiversw < 0 || !f->fpipubis)
  209.       return -1;
  210.      
  211.      switch (c) {
  212.      case 'A':            /* Is it available? */
  213.       return f->fpitt == '+' ? 0 : -1;
  214.      case 'I':            /* Is it ISO? */
  215.       return f->fpiot == '!' ? 0 : -1;
  216.      case 'R':            /* Is it registered? */
  217.       return f->fpiot == '+' ? 0 : -1;
  218.      case 'U':            /* Is it unregistered? */
  219.       return f->fpiot == '-' ? 0 : -1;
  220.      case 'L':            /* public text language */
  221.       if (f->fpic == FPICHARS)
  222.            return -1;
  223.       /* it's entered in all upper case letters */
  224.       return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 1);
  225.      case 'O':            /* owner identifier */
  226.       return mindatcpy(buf, (char *)f->fpipubis + f->fpio, f->fpiol, 0);
  227.      case 'C':            /* public text class */
  228.       n = f->fpic - 1;
  229.       if (n < 0 || n >= sizeof(classes)/sizeof(classes[0]))
  230.            return -1;
  231.       if (buf)
  232.            strcpy(buf, classes[n]);
  233.       return strlen(classes[n]);
  234.      case 'T':            /* text description */
  235.       return mindatcpy(buf, (char *)f->fpipubis + f->fpit, f->fpitl, 0);
  236.      case 'V':
  237.       if (f->fpic < FPICMINV)    /* class doesn't have version */
  238.            return -1;
  239.       if (f->fpiversw > 0)             /* no version */
  240.            return -1;
  241.       if (f->fpivl == 0) {        /* empty version: */
  242.                         /* use device-independent version*/
  243.            if (buf)
  244.             strcpy(buf, EMPTY_VERSION);
  245.            return strlen(EMPTY_VERSION);
  246.       }
  247.       return mindatcpy(buf, (char *)f->fpipubis + f->fpiv, f->fpivl, 0);
  248.      case 'E':                  /* public text designating (escape) sequence */
  249.       if (f->fpic != FPICHARS)
  250.            return -1;
  251.       return mindatcpy(buf, (char *)f->fpipubis + f->fpil, f->fpill, 0);
  252.      default:
  253.       break;
  254.      }
  255.      return -1;
  256. }
  257.  
  258. static int testopen(pathname)
  259. char *pathname;
  260. {
  261. #ifdef HAVE_ACCESS
  262.      return access(pathname, R_OK) >= 0;
  263. #else /* not HAVE_ACCESS */
  264.      FILE *fp;
  265.      fp = fopen(pathname, "r");
  266.      if (!fp)
  267.       return 0;
  268.      fclose(fp);
  269.      return 1;
  270. #endif /* not HAVE_ACCESS */
  271. }
  272.  
  273. /* Return a pointer to an dynamically-allocated buffer that contains
  274.    the names of the files containing this entity, with each filename
  275.    terminated by a '\0', and with the list of filenames terminated by
  276.    another '\0'. */
  277.  
  278. UNIV entgen(f)
  279. struct fpi *f;
  280. {
  281.      char *file;
  282.  
  283.      assert(f->fpistore != 6);    /* Musn't call entgen for a notation. */
  284.      if (!path) {
  285.       char *p;
  286.       char c;
  287.       path = getenv(PATH_ENV_VAR);
  288.       if (!path)
  289.            path = DEFAULT_PATH;
  290.       p = path;
  291.  
  292.       /* Only search for system identifiers if path uses %S. */
  293.       while ((c = *p++) != '\0')
  294.            if (c == '%') {
  295.             if (*p == 'S') {
  296.              sysidsrch = 1;
  297.              break;
  298.             }
  299.             if (*p != '\0' && *p != PATH_FILE_SEP)
  300.              p++;
  301.            }
  302.      }
  303.      if (f->fpisysis
  304.      && (!sysidsrch
  305.          || strchr((char *)f->fpisysis, SYSID_FILE_SEP)
  306.          || strcmp((char *)f->fpisysis, STDINNAME) == 0))
  307.       return sysidgen((char *)f->fpisysis);
  308.  
  309.      file = path;
  310.      
  311.      for (;;) {
  312.       char *p;
  313.       int len = 0;
  314.       char *fileend = strchr(file, PATH_FILE_SEP);
  315.       if (!fileend)
  316.            fileend = strchr(file, '\0');
  317.  
  318.       /* Check that all substitutions are non-null, and calculate
  319.          the resulting total length of the filename. */
  320.       for (p = file; p < fileend; p++)
  321.            if (*p == '%') {
  322.             int n;
  323.             /* Set len to -1 if a substitution is invalid. */
  324.             if (++p >= fileend) {
  325.              len = -1;
  326.              break;
  327.             }
  328.             n = field(f, *p, (char *)0);
  329.             if (n < 0) {
  330.              len = -1;
  331.              break;
  332.             }
  333.             len += n;
  334.            }
  335.            else
  336.             len++;
  337.       
  338.       if (len > 0) {
  339.            /* We've got a valid non-empty filename. */
  340.            char *s;
  341.            char *buf;
  342.  
  343.            s = buf = (char *)rmalloc(len + 2);
  344.            for (p = file; p < fileend; p++)
  345.             if (*p == '%')
  346.              s += field(f, *++p, s);
  347.             else
  348.              *s++ = *p;
  349.            *s++ = '\0';
  350.            if (testopen(buf)) {
  351.             /* Terminate the array of filenames. */
  352.             *s++ = '\0';
  353.             return buf;
  354.            }
  355.            free((UNIV)buf);
  356.       }
  357.       if (*fileend == '\0')
  358.            break;
  359.       file = ++fileend;
  360.      }
  361.      return 0;
  362. }
  363.  
  364. /* Handle a system identifier without searching. */
  365.  
  366. static
  367. UNIV sysidgen(s)
  368. char *s;
  369. {
  370.      char *buf, *p;
  371.      
  372.      buf = (char *)rmalloc(strlen(s) + 2);
  373.  
  374.      for (p = buf; *s; s++) {
  375.       if (*s == SYSID_FILE_SEP) {
  376.            if (p > buf && p[-1] != '\0')
  377.             *p++ = '\0';
  378.       }
  379.       else if (*s == RECHAR)
  380.            *p++ = '\n';
  381.       else if (*s != RSCHAR)
  382.            *p++ = *s;
  383.      }
  384.      /* Terminate this filename. */
  385.      if (p > buf && p[-1] != '\0')
  386.       *p++ = '\0';
  387.      if (p == buf) {
  388.       /* No filenames. */
  389.       frem((UNIV)buf);
  390.       return 0;
  391.      }
  392.      /* Terminate the list. */
  393.      *p++ = '\0';
  394.      return buf;
  395. }
  396.  
  397. /*
  398. Local Variables:
  399. c-indent-level: 5
  400. c-continued-statement-offset: 5
  401. c-brace-offset: -5
  402. c-argdecl-indent: 0
  403. c-label-offset: -5
  404. End:
  405. */
  406.