home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 13 / MA_Cover_13.bin / source / c / tidy26jul99 / config.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-08  |  15.2 KB  |  626 lines

  1. /*
  2.   config.c - read config file and manage config properties
  3.   
  4.   (c) 1998, 1999 (W3C) MIT, INRIA, Keio University
  5.   See tidy.c for the copyright notice.
  6. */
  7.  
  8. /*
  9.   config files associate a property name with a value.
  10.  
  11.   // comments can start at the beginning of a line
  12.   name: short values fit onto one line
  13.   name: a really long value that
  14.    continues on the next line
  15.  
  16.   property names are case insensitive and should be less than
  17.   60 characters in length and must start at the begining of
  18.   the line, as whitespace at the start of a line signifies a
  19.   line continuation.
  20. */
  21.  
  22. #include "platform.h"
  23. #include "html.h"
  24.  
  25. typedef union
  26. {
  27.     int *number;
  28.     Bool *logical;
  29.     char **string;
  30. } Location;
  31.  
  32. typedef void (ParseProperty)(Location location);
  33.  
  34. ParseProperty ParseInt;     /* parser for integer values */
  35. ParseProperty ParseBool;    /* parser for 'true' or 'false' or 'yes' or 'no' */
  36. ParseProperty ParseInvBool; /* parser for 'true' or 'false' or 'yes' or 'no' */
  37. ParseProperty ParseName;    /* a string excluding whitespace */
  38. ParseProperty ParseString;  /* a string including whitespace */
  39. ParseProperty ParseTagNames; /* a space separated list of tag names */
  40. ParseProperty ParseCharEncoding; /* RAW, ASCII, LATIN1, UTF8 or ISO2022 */
  41. ParseProperty ParseIndent;   /* specific to the indent option */
  42. ParseProperty ParseDocType;  /* omit | auto | strict | loose | <fpi> */
  43.  
  44. uint spaces =  2;           /* default indentation */
  45. uint wraplen = 68;          /* default wrap margin */
  46. int CharEncoding = ASCII;
  47. int tabsize = 4;
  48.  
  49. DocTypeMode doctype_mode = doctype_auto; /* see doctype property */
  50. char *slide_style = null;    /* style sheet for slides */
  51. char *doctype_str = null;   /* user specified doctype */
  52. char *errfile = null;       /* file name to write errors to */
  53. Bool writeback = no;        /* if true then output tidied markup */
  54.  
  55. Bool OnlyErrors = no;       /* if true normal output is suppressed */
  56. Bool ShowWarnings = yes;    /* however errors are always shown */
  57. Bool IndentContent = no;    /* indent content of appropriate tags */
  58. Bool SmartIndent = no;      /* does text/block level content effect indentation */
  59. Bool HideEndTags = no;      /* suppress optional end tags */
  60. Bool XmlTags = no;          /* treat input as XML */
  61. Bool XmlOut = no;           /* create output as XML */
  62. Bool xHTML = no;            /* output extensible HTML */
  63. Bool XmlPi = yes;           /* add <?xml?> for XML docs */
  64. Bool RawOut = no;           /* avoid mapping values > 127 to entities */
  65. Bool UpperCaseTags = no;    /* output tags in upper not lower case */
  66. Bool UpperCaseAttrs = no;   /* output attributes in upper not lower case */
  67. Bool MakeClean = no;        /* replace presentational clutter by style rules */
  68. Bool LogicalEmphasis = no;  /* replace i by em and b by strong */
  69. Bool DropFontTags = no;     /* discard presentation tags */
  70. Bool BreakBeforeBR = no;    /* o/p newline before <br> or not? */
  71. Bool BurstSlides = no;      /* create slides on each h2 element */
  72. Bool NumEntities = no;      /* use numeric entities */
  73. Bool QuoteMarks = no;       /* output " marks as " */
  74. Bool QuoteNbsp = yes;       /* output non-breaking space as entity */
  75. Bool QuoteAmpersand = yes;  /* output naked ampersand as & */
  76. Bool WrapScriptlets = no;   /* wrap within JavaScript string literals */
  77. Bool WrapAsp = yes;         /* wrap within ASP pseudo elements */
  78. Bool FixBackslash = yes;    /* fix URLs by replacing \ with / */
  79. Bool IndentAttributes = no; /* newline+indent before each attribute */
  80. Bool XmlPIs = no;           /* if set to yes PIs must end with ?> */
  81.  
  82. typedef struct _lex PLex;
  83.  
  84. static uint c;      /* current char in input stream */
  85. static FILE *fp;    /* file pointer for input stream */
  86.  
  87. /* not used to store anything */
  88. static char *inline_tags;
  89. static char *block_tags;
  90. static char *empty_tags;
  91.  
  92.  
  93. typedef struct _plist PList;
  94.  
  95. struct _plist
  96. {
  97.     char *name;                     /* property name */
  98.     Location location;              /* place to store value */
  99.     ParseProperty *parser;          /* parsing method */
  100.     PList *next;                    /* linear hash chaining */
  101. };
  102.  
  103. #define HASHSIZE 101
  104.  
  105. static PList *hashtable[HASHSIZE];   /* private hash table */
  106. static Bool initialized = no;
  107.  
  108. static struct Flag
  109. {
  110.     char *name;                     /* property name */
  111.     Location location;              /* place to store value */
  112.     ParseProperty *parser;          /* parsing method */
  113. } flags[] =
  114. {
  115.     "indent-spaces",   (int *)&spaces,           ParseInt,
  116.     "wrap",            (int *)&wraplen,          ParseInt,
  117.     "wrap-script-literals", (int *)&WrapScriptlets, ParseBool,
  118.     "wrap-asp",        (int *)&WrapAsp,          ParseBool,
  119.     "tab-size",        (int *)&tabsize,          ParseInt,
  120.     "markup",          (int *)&OnlyErrors,       ParseInvBool,
  121.     "indent",          (int *)&IndentContent,    ParseIndent,
  122.     "indent-attributes", (int *)&IndentAttributes, ParseBool,
  123.     "hide-endtags",    (int *)&HideEndTags,      ParseBool,
  124.     "input-xml",       (int *)&XmlTags,          ParseBool,
  125.     "output-xml",      (int *)&XmlOut,           ParseBool,
  126.     "output-xhtml",    (int *)&xHTML,            ParseBool,
  127.     "add-xml-pi",      (int *)&XmlPi,            ParseBool,
  128.     "assume-xml-procins",  (int *)&XmlPIs,       ParseBool,
  129.     "raw",             (int *)&RawOut,           ParseBool,
  130.     "uppercase-tags",  (int *)&UpperCaseTags,    ParseBool,
  131.     "uppercase-attributes", (int *)&UpperCaseAttrs, ParseBool,
  132.     "clean",           (int *)&MakeClean,        ParseBool,
  133.     "logical-emphasis", (int *)&LogicalEmphasis, ParseBool,
  134.     "drop-font-tags",  (int *)&DropFontTags,     ParseBool,
  135.     "split",           (int *)&BurstSlides,      ParseBool,
  136.     "break-before-br", (int *)&BreakBeforeBR,    ParseBool,
  137.     "numeric-entities", (int *)&NumEntities,     ParseBool,
  138.     "quote-marks",     (int *)&QuoteMarks,       ParseBool,
  139.     "quote-nbsp",      (int *)&QuoteNbsp,        ParseBool,
  140.     "quote-ampersand", (int *)&QuoteAmpersand,   ParseBool,
  141.     "write-back",      (int *)&writeback,        ParseBool,
  142.     "show-warnings",   (int *)&ShowWarnings,     ParseBool,
  143.     "error-file",      (int *)&errfile,          ParseName,
  144.     "slide-style",     (int *)&slide_style,      ParseName,
  145.     "new-inline-tags",     (int *)&inline_tags,  ParseTagNames,
  146.     "new-blocklevel-tags", (int *)&block_tags,   ParseTagNames,
  147.     "new-empty-tags",  (int *)&empty_tags,       ParseTagNames,
  148.     "char-encoding",   (int *)&CharEncoding,     ParseCharEncoding,
  149.     "doctype",         (int *)&doctype_str,      ParseDocType,
  150.     "fix-backslash",   (int *)&FixBackslash,     ParseBool,
  151.   /* this must be the final entry */
  152.     0,          0,             0
  153. };
  154.  
  155. static unsigned hash(char *s)
  156. {
  157.     unsigned hashval;
  158.  
  159.     for (hashval = 0; *s != '\0'; s++)
  160.         hashval = toupper(*s) + 31*hashval;
  161.  
  162.     return hashval % HASHSIZE;
  163. }
  164.  
  165. static PList *lookup(char *s)
  166. {
  167.     PList *np;
  168.  
  169.     for (np = hashtable[hash(s)]; np != null; np = np->next)
  170.         if (wstrcmp(s, np->name) == 0)
  171.             return np;
  172.     return null;
  173. }
  174.  
  175. static PList *install(char *name, Location location, ParseProperty *parser)
  176. {
  177.     PList *np;
  178.     unsigned hashval;
  179.  
  180.     if ((np = lookup(name)) == null)
  181.     {
  182.         np = (PList *)MemAlloc(sizeof(*np));
  183.  
  184.         if (np == null || (np->name = wstrdup(name)) == null)
  185.             return null;
  186.  
  187.         hashval = hash(name);
  188.         np->next = hashtable[hashval];
  189.         hashtable[hashval] = np;
  190.     }
  191.  
  192.     np->location = location;
  193.     np->parser = parser;
  194.     return np;
  195. }
  196.  
  197. void InitConfig(void)
  198. {
  199.     struct Flag *p;
  200.  
  201.     if (!initialized)
  202.     {
  203.         initialized = yes;
  204.     
  205.         for(p = flags; p->name != null; ++p)
  206.             install(p->name, p->location, p->parser);
  207.     }
  208. }
  209.  
  210. void FreeConfig(void)
  211. {
  212.     PList *prev, *next;
  213.     int i;
  214.  
  215.     for (i = 0; i < HASHSIZE; ++i)
  216.     {
  217.         prev = null;
  218.         next = hashtable[i];
  219.  
  220.         while(next)
  221.         {
  222.             prev = next->next;
  223.             MemFree(next->name);
  224.             MemFree(next);
  225.             next = prev;
  226.         }
  227.     }
  228.  
  229.     if (slide_style)
  230.         MemFree(slide_style);
  231.  
  232.     if (doctype_str)
  233.         MemFree(doctype_str);
  234.  
  235.     if (errfile)
  236.         MemFree(errfile);
  237. }
  238.  
  239. static int AdvanceChar()
  240. {
  241.     if (c != EOF)
  242.         c = (uint)getc(fp);
  243.     return c;
  244. }
  245.  
  246. static int SkipWhite()
  247. {
  248.     while (IsWhite((uint) c))
  249.         c = (uint)getc(fp);
  250.     return c;
  251. }
  252.  
  253. /*
  254.  skip over line continuations
  255.  to start of next property
  256. */
  257. static int NextProperty()
  258. {
  259.     do
  260.     {
  261.         /* skip to end of line */
  262.         while (c != '\n' && c != '\r' && c != EOF)
  263.             c = (uint)getc(fp);
  264.  
  265.         /* treat  \r\n   \r  or  \n as line ends */
  266.         if (c == '\r')
  267.             c = (uint)getc(fp);
  268.  
  269.         if (c == '\n')
  270.             c = (uint)getc(fp);
  271.     }
  272.     while (IsWhite(c));  /* line continuation? */
  273.  
  274.     return c;
  275. }
  276.  
  277. void ParseConfigFile(char *file)
  278. {
  279.     int i;
  280.     char name[64];
  281.     PList *entry;
  282.  
  283.     /* setup property name -> parser table*/
  284.  
  285.     InitConfig();
  286.  
  287.     /* open the file and parse its contents */
  288.  
  289.     if ((fp = fopen(file, "r")) == null)
  290.         fprintf(stderr, "Error: can't open config file: \"%s\"\n", file);
  291.     else
  292.     {
  293.         AdvanceChar();  /* first char */
  294.  
  295.         while (c != EOF)
  296.         {
  297.             /* // starts a comment */
  298.             while (c == '/')
  299.                 NextProperty();
  300.  
  301.             i = 0;
  302.  
  303.             while (c != ':' && c != EOF && i < 60)
  304.             {
  305.                 name[i++] = (char)c;
  306.                 AdvanceChar();
  307.             }
  308.  
  309.             name[i] = '\0';
  310.             entry = lookup(name);
  311.  
  312.             if (c == ':' && entry)
  313.             {
  314.                 AdvanceChar();
  315.                 entry->parser(entry->location);
  316.             }
  317.     
  318.             NextProperty();
  319.         }
  320.  
  321.         fclose(fp);
  322.     }
  323. }
  324.  
  325. /* ensure that config is self consistent */
  326. void AdjustConfig(void)
  327. {
  328.  /* avoid the need to set IndentContent when SmartIndent is set */
  329.  
  330.     if (SmartIndent)
  331.         IndentContent = yes;
  332.  
  333.  /* drop-font-tags requires clean option */
  334.     if (DropFontTags)
  335.         MakeClean = yes;
  336.  
  337. /* logical-emphasis automatically invokes clean option */
  338.     if (LogicalEmphasis)
  339.         MakeClean = yes;
  340.  
  341.  /* XHTML is written in lower case */
  342.     if (xHTML)
  343.     {
  344.         XmlOut = yes;
  345.         UpperCaseTags = no;
  346.         UpperCaseAttrs = no;
  347.     }
  348.  
  349.  /* if XML in, then XML out */
  350.     if (XmlTags)
  351.     {
  352.         XmlOut = yes;
  353.         XmlPIs = yes;
  354.     }
  355.  
  356.  /* XML requires end tags */
  357.     if (XmlOut)
  358.     {
  359.         QuoteAmpersand = yes;
  360.         HideEndTags = no;
  361.     }
  362. }
  363.  
  364. /* unsigned integers */
  365. void ParseInt(Location location)
  366. {
  367.     int number = 0;
  368.  
  369.     SkipWhite();
  370.  
  371.     while(IsDigit(c))
  372.     {
  373.         number = c - '0' + (10 * number);
  374.         AdvanceChar();
  375.     }
  376.  
  377.     *location.number = number;
  378. }
  379.  
  380. /* true/false or yes/no only looks at 1st char */
  381. void ParseBool(Location location)
  382. {
  383.     Bool flag = no;
  384.     SkipWhite();
  385.  
  386.     if (c == 't' || c == 'T' || c == 'y' || c == 'Y')
  387.         flag = yes;
  388.  
  389.     *location.logical = flag;
  390. }
  391.  
  392. void ParseInvBool(Location location)
  393. {
  394.     Bool flag = no;
  395.     SkipWhite();
  396.  
  397.     if (c == 't' || c == 'T' || c == 'y' || c == 'Y')
  398.         flag = yes;
  399.  
  400.     *location.logical = (Bool)(!flag);
  401. }
  402.  
  403. /* a string excluding whitespace */
  404. void ParseName(Location location)
  405. {
  406.     char buf[256];
  407.     int i = 0;
  408.  
  409.     SkipWhite();
  410.  
  411.     while (i < 254 && c != EOF && !IsWhite(c))
  412.     {
  413.         buf[i++] = c;
  414.         AdvanceChar();
  415.     }
  416.  
  417.     buf[i] = '\0';
  418.  
  419.     *location.string = wstrdup(buf);
  420. }
  421.  
  422. /* a space or comma separated list of tag names */
  423. void ParseTagNames(Location location)
  424. {
  425.     char buf[1024];
  426.     int i = 0;
  427.  
  428.     do
  429.     {
  430.         SkipWhite();
  431.  
  432.         if (c == ',')
  433.         {
  434.             AdvanceChar();
  435.             continue;
  436.         }
  437.  
  438.         while (i < 1022 && c != EOF && !IsWhite(c) && c != ',')
  439.         {
  440.             buf[i++] = ToUpper(c);
  441.             AdvanceChar();
  442.         }
  443.  
  444.         buf[i] = '\0';
  445.  
  446.         /* add tag to dictionary */
  447.  
  448.         if(location.string == &inline_tags)
  449.             DefineInlineTag(buf);
  450.         else if (location.string == &block_tags)
  451.             DefineBlockTag(buf);
  452.         else if (location.string == &empty_tags)
  453.             DefineEmptyTag(buf);
  454.  
  455.         i = 0;
  456.     }
  457.     while (c != EOF);
  458. }
  459.  
  460. /* a string including whitespace */
  461. /* munges whitespace sequences */
  462. void ParseString(Location location)
  463. {
  464.     char buf[8192];
  465.     int i = 0;
  466.     Bool waswhite = no;
  467.  
  468.     SkipWhite();
  469.  
  470.     while (i < 8190 && c != EOF)
  471.     {
  472.         /* treat  \r\n   \r  or  \n as line ends */
  473.         if (c == '\r')
  474.         {
  475.             AdvanceChar();
  476.  
  477.             if (c != '\n' && !IsWhite(c))
  478.                 break;
  479.         }
  480.  
  481.         if (c == '\n')
  482.         {
  483.             AdvanceChar();
  484.  
  485.             if (!IsWhite(c))
  486.                 break;
  487.         }
  488.  
  489.         if (IsWhite(c))
  490.         {
  491.             if (waswhite)
  492.             {
  493.                 AdvanceChar();
  494.                 continue;
  495.             }
  496.  
  497.             c = ' ';
  498.         }
  499.         else
  500.             waswhite = no;
  501.  
  502.         buf[i++] = c;
  503.         AdvanceChar();
  504.     }
  505.  
  506.     buf[i] = '\0';
  507.  
  508.     if (*location.string)
  509.         MemFree(*location.string);
  510.  
  511.     *location.string = wstrdup(buf);
  512. }
  513.  
  514. void ParseCharEncoding(Location location)
  515. {
  516.     char buf[64];
  517.     int i = 0;
  518.  
  519.     SkipWhite();
  520.  
  521.     while (i < 62 && c != EOF && !IsWhite(c))
  522.     {
  523.         buf[i++] = c;
  524.         AdvanceChar();
  525.     }
  526.  
  527.     buf[i] = '\0';
  528.  
  529.     if (wstrcasecmp(buf, "ascii") == 0)
  530.         *location.number = ASCII;
  531.     else if (wstrcasecmp(buf, "latin1") == 0)
  532.         *location.number = LATIN1;
  533.     else if (wstrcasecmp(buf, "raw") == 0)
  534.         *location.number = RAW;
  535.     else if (wstrcasecmp(buf, "utf8") == 0)
  536.         *location.number = UTF8;
  537.     else if (wstrcasecmp(buf, "iso2022") == 0)
  538.         *location.number = ISO2022;
  539. }
  540.  
  541. /* slight hack to avoid changes to pprint.c */
  542. void ParseIndent(Location location)
  543. {
  544.     char buf[64];
  545.     int i = 0;
  546.  
  547.     SkipWhite();
  548.  
  549.     while (i < 62 && c != EOF && !IsWhite(c))
  550.     {
  551.         buf[i++] = c;
  552.         AdvanceChar();
  553.     }
  554.  
  555.     buf[i] = '\0';
  556.  
  557.     if (wstrcasecmp(buf, "yes") == 0)
  558.     {
  559.         IndentContent = yes;
  560.         SmartIndent = no;
  561.     }
  562.     else if (wstrcasecmp(buf, "true") == 0)
  563.     {
  564.         IndentContent = yes;
  565.         SmartIndent = no;
  566.     }
  567.     else if (wstrcasecmp(buf, "no") == 0)
  568.     {
  569.         IndentContent = no;
  570.         SmartIndent = no;
  571.     }
  572.     else if (wstrcasecmp(buf, "false") == 0)
  573.     {
  574.         IndentContent = no;
  575.         SmartIndent = no;
  576.     }
  577.     else if (wstrcasecmp(buf, "auto") == 0)
  578.     {
  579.         IndentContent = yes;
  580.         SmartIndent = yes;
  581.     }
  582. }
  583.  
  584. /*
  585.    doctype: omit | auto | strict | loose | <fpi>
  586.  
  587.    where the fpi is a string similar to
  588.  
  589.       "-//ACME//DTD HTML 3.14159//EN"
  590. */
  591. void ParseDocType(Location location)
  592. {
  593.     char buf[64];
  594.     int i = 0;
  595.  
  596.     SkipWhite();
  597.  
  598.     /* "-//ACME//DTD HTML 3.14159//EN" or similar */
  599.  
  600.     if (c == '"')
  601.     {
  602.         ParseString(location);
  603.         doctype_mode = doctype_user;
  604.         return;
  605.     }
  606.  
  607.     /* read first word */
  608.     while (i < 62 && c != EOF && !IsWhite(c))
  609.     {
  610.         buf[i++] = c;
  611.         AdvanceChar();
  612.     }
  613.  
  614.     buf[i] = '\0';
  615.  
  616.     doctype_mode = doctype_auto;
  617.  
  618.     if (wstrcasecmp(buf, "omit") == 0)
  619.         doctype_mode = doctype_omit;
  620.     else if (wstrcasecmp(buf, "strict") == 0)
  621.         doctype_mode = doctype_strict;
  622.     else if (wstrcasecmp(buf, "loose") == 0 ||
  623.              wstrcasecmp(buf, "transitional") == 0)
  624.         doctype_mode = doctype_loose;
  625. }
  626.