home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / wxwin140 / utils / wxhelp / src / tex2any.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  10.9 KB  |  454 lines

  1. /*
  2.  * File:     tex2any.cc
  3.  * Purpose:  Conversion utility for LaTeX files
  4.  *
  5.  *                       wxWindows 1.40
  6.  * Copyright (c) 1993 Artificial Intelligence Applications Institute,
  7.  *                   The University of Edinburgh
  8.  *
  9.  *                     Author: Julian Smart
  10.  *                        Date: 18-4-93
  11.  *
  12.  * Permission to use, copy, modify, and distribute this software and its
  13.  * documentation for any purpose is hereby granted without fee, provided
  14.  * that the above copyright notice, author statement and this permission
  15.  * notice appear in all copies of this software and related documentation.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
  18.  * IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
  19.  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  20.  *
  21.  * IN NO EVENT SHALL THE ARTIFICIAL INTELLIGENCE APPLICATIONS INSTITUTE OR THE
  22.  * UNIVERSITY OF EDINBURGH BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR
  23.  * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM
  24.  * LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF
  25.  * DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH
  26.  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
  27.  */
  28.  
  29. #include <windows.h> // Included only for benefit of MSC7 precompiled headers
  30. #include "tex2any.h"
  31.  
  32. FILE *CurrentOutput1 = NULL;
  33. FILE *CurrentOutput2 = NULL;
  34. FILE *Input = NULL;
  35.  
  36. TexChunk *TopLevel = NULL;
  37. wxList MacroDefs(wxKEY_STRING);
  38. char *BigBuffer = NULL;  // For reading in large chunks of text
  39. TexMacroDef *SoloBlockDef = NULL;
  40.  
  41. void TexOutput(char *s)
  42. {
  43.   if (CurrentOutput1)
  44.     fprintf(CurrentOutput1, "%s", s);
  45.   if (CurrentOutput2)
  46.     fprintf(CurrentOutput2, "%s", s);
  47. }
  48.  
  49. TexMacroDef *MatchMacro(char *buffer, int *pos, char **env)
  50. {
  51.   int i = (*pos);
  52.   TexMacroDef *def = NULL;
  53.  
  54.   // First, try to find begin{thing}
  55.   if (strncmp(buffer+i, "begin{", 6) == 0)
  56.   {
  57.     i += 6;
  58.  
  59.     wxNode *node = MacroDefs.First();
  60.     while (node && !def)
  61.     {
  62.       if (strncmp(buffer+i, node->key.string, strlen(node->key.string)) == 0)
  63.       { def = (TexMacroDef *)node->Data();
  64.         i += strlen(node->key.string); }
  65.       else node = node->Next();
  66.     }
  67.     if (def)
  68.     {
  69.       *pos = i + 1;
  70.       *env = def->name;
  71.       return def;
  72.     }
  73.     else return NULL;
  74.   }
  75.  
  76.   // Failed, so try to find macro from definition list
  77.   wxNode *node = MacroDefs.First();
  78.   while (node && !def)
  79.   {
  80.     if (strncmp(buffer+i, node->key.string, strlen(node->key.string)) == 0)
  81.     { def = (TexMacroDef *)node->Data();
  82.       i += strlen(node->key.string); }
  83.     else node = node->Next();
  84.   }
  85.   if (def)
  86.   {
  87.     // We want to check whether this is a space-consuming macro
  88.     // (e.g. {\bf word})
  89.     if (def->consume_space && (buffer[i] == 32))
  90.       i ++;
  91.     *pos = i;
  92.     return def;
  93.   }
  94.   return NULL;
  95. }
  96.  
  97. Bool FindEndEnvironment(char *buffer, int *pos, char *env)
  98. {
  99.   int i = (*pos);
  100.  
  101.   // Try to find end{thing}
  102.   if ((strncmp(buffer+i, "end{", 4) == 0) &&
  103.       (strncmp(buffer+i+4, env, strlen(env)) == 0))
  104.   {
  105.     *pos = i + 5 + strlen(env);
  106.     return TRUE;
  107.   }
  108.   else return FALSE;
  109. }
  110.  
  111. Bool read_a_line(FILE *fd, char *buf)
  112. {
  113.   int ch = -2;
  114.   int i = 0;
  115.   buf[0] = 0;
  116.   while (ch != EOF && ch != '\n')
  117.   {
  118.     ch = getc(fd);
  119.     if (ch != EOF)
  120.     {
  121.       buf[i] = ch;
  122.       i ++;
  123.     }
  124.   }
  125.   buf[i] = 0;
  126.   return (ch == EOF);
  127. }
  128.  
  129. // environment is only non-NULL is we're looking for the end
  130. // of an environment, e.g. \end{itemize}
  131. int ParseArg(wxList& children, char *buffer, int pos, char *environment)
  132. {
  133.   Bool eof = FALSE;
  134.   BigBuffer[0] = 0;
  135.   int buf_ptr = 0;
  136.   int len;
  137.  
  138.   // Consume leading brace
  139.   if (buffer[pos] == '{')
  140.     pos ++;
  141.  
  142.   while (!eof)
  143.   {
  144.     len = strlen(buffer);
  145.     if (pos >= len)
  146.     {
  147.       eof = read_a_line(Input, buffer);
  148.       pos = 0;
  149.       len = strlen(buffer);
  150.       // Check for verbatim
  151.       if (strncmp(buffer, "\\begin{verbatim}", 16) == 0)
  152.       {
  153.         if (buf_ptr > 0)
  154.         {
  155.           TexChunk *chunk = new TexChunk(CHUNK_TYPE_STRING);
  156.           BigBuffer[buf_ptr] = 0;
  157.           buf_ptr = 0;
  158.           chunk->value = copystring(BigBuffer);
  159.           children.Append(chunk);
  160.         }
  161.         BigBuffer[0] = 0;
  162.         buf_ptr = 0;
  163.  
  164.         eof = read_a_line(Input, buffer);
  165.         while (!eof && (strncmp(buffer, "\\end{verbatim}", 14) != 0))
  166.     {
  167.           strcat(BigBuffer, buffer);
  168.           buf_ptr += strlen(buffer);
  169.           eof = read_a_line(Input, buffer);
  170.     }
  171.         eof = read_a_line(Input, buffer);
  172.         buf_ptr = 0;
  173.  
  174.         TexChunk *chunk = new TexChunk(CHUNK_TYPE_MACRO);
  175.         chunk->no_args = 1;
  176.         chunk->name = copystring("verbatim");
  177.         TexChunk *arg = new TexChunk(CHUNK_TYPE_ARG);
  178.         arg->argn = 1;
  179.         arg->name = copystring("verbatim");
  180.         TexChunk *str = new TexChunk(CHUNK_TYPE_STRING);
  181.         str->value = copystring(BigBuffer);
  182.  
  183.         children.Append(chunk);
  184.         chunk->children.Append(arg);
  185.         arg->children.Append(str);
  186.       }
  187.     }
  188.     char ch = buffer[pos];
  189.     switch (ch)
  190.     {
  191.       case '}':
  192.       {
  193.         if (buf_ptr > 0)
  194.         {
  195.           TexChunk *chunk = new TexChunk(CHUNK_TYPE_STRING);
  196.           BigBuffer[buf_ptr] = 0;
  197.           buf_ptr = 0;
  198.           chunk->value = copystring(BigBuffer);
  199.           children.Append(chunk);
  200.         }
  201.         return pos+1;
  202.         break;
  203.       }
  204.       /* We want to treat this kind of construct:
  205.  
  206.          \begin{itemize}
  207.           ...
  208.          \end{itemize}
  209.  
  210.          as if it were this:
  211.  
  212.          \itemize{...}
  213.  
  214.        */
  215.  
  216.       case '\\':
  217.       {
  218.         if (buf_ptr > 0)
  219.         {
  220.           TexChunk *chunk = new TexChunk(CHUNK_TYPE_STRING);
  221.           BigBuffer[buf_ptr] = 0;
  222.           buf_ptr = 0;
  223.           chunk->value = copystring(BigBuffer);
  224.           children.Append(chunk);
  225.         }
  226.         pos ++;
  227.  
  228.         if (environment && FindEndEnvironment(buffer, &pos, environment))
  229.           return pos;
  230.  
  231.         char *env = NULL;
  232.         TexMacroDef *def = MatchMacro(buffer, &pos, &env);
  233.         if (def)
  234.         {
  235.           TexChunk *chunk = new TexChunk(CHUNK_TYPE_MACRO);
  236.           chunk->no_args = def->no_args;
  237.           chunk->name = copystring(def->name);
  238.           children.Append(chunk);
  239.           pos = ParseMacroBody(chunk->name, chunk->children, chunk->no_args,
  240.                      buffer, pos, env);
  241.         }
  242. #ifdef wx_x
  243.         else cerr << "Warning: could not find macro: " << buffer + pos << "\n";
  244. #endif
  245.         break;
  246.       }
  247.       // Parse constructs like {\bf thing} as if they were
  248.       // \bf{thing}
  249.       case '{':
  250.       {
  251.         pos ++;
  252.         if (buffer[pos] == '\\')
  253.         {
  254.           if (buf_ptr > 0)
  255.           {
  256.             TexChunk *chunk = new TexChunk(CHUNK_TYPE_STRING);
  257.             BigBuffer[buf_ptr] = 0;
  258.             buf_ptr = 0;
  259.             chunk->value = copystring(BigBuffer);
  260.             children.Append(chunk);
  261.           }
  262.           pos ++;
  263.           char *env;
  264.           TexMacroDef *def = MatchMacro(buffer, &pos, &env);
  265.           if (def)
  266.           {
  267.             TexChunk *chunk = new TexChunk(CHUNK_TYPE_MACRO);
  268.             chunk->no_args = def->no_args;
  269.             chunk->name = copystring(def->name);
  270.             children.Append(chunk);
  271.             pos = ParseMacroBody(chunk->name, chunk->children, chunk->no_args,
  272.                        buffer, pos);
  273.           }
  274.         }
  275.         else
  276.     {
  277.          /*
  278.           * If all else fails, we assume that we have
  279.           * a pair of braces on their own, so return a `dummy' macro
  280.           * definition with just one argument to parse.
  281.           */
  282.           if (!SoloBlockDef)
  283.           {
  284.             SoloBlockDef = new TexMacroDef("solo block", 1, FALSE);
  285.           }
  286.           TexChunk *chunk = new TexChunk(CHUNK_TYPE_MACRO);
  287.           chunk->no_args = SoloBlockDef->no_args;
  288.           chunk->name = copystring(SoloBlockDef->name);
  289.           children.Append(chunk);
  290.           pos = ParseMacroBody(chunk->name, chunk->children, chunk->no_args,
  291.                        buffer, pos);
  292.     }
  293.         break;
  294.       }
  295.       default:
  296.       {
  297.         BigBuffer[buf_ptr] = ch;
  298.         BigBuffer[buf_ptr+1] = 0;
  299.         buf_ptr ++;
  300.         pos ++;
  301.         break;
  302.       }
  303.     }
  304.   }
  305.   return pos;
  306. }
  307.  
  308. int ParseMacroBody(char *macro_name, wxList& children,
  309.                    int no_args, char *buffer, int pos,
  310.                    char *environment)
  311. {
  312.   for (int i = 0; i < no_args; i++)
  313.   {
  314.     TexChunk *arg = new TexChunk(CHUNK_TYPE_ARG);
  315.  
  316.     children.Append(arg);
  317.     arg->name = copystring(macro_name);
  318.     arg->argn = i+1;
  319.     pos = ParseArg(arg->children, buffer, pos, environment);
  320.   }
  321.   return pos;
  322. }
  323.  
  324. Bool TexLoadFile(char *filename)
  325. {
  326.   static char line_buffer[500];
  327.   Input = fopen(filename, "r");
  328.   if (Input)
  329.   {
  330.     read_a_line(Input, line_buffer);
  331.     ParseMacroBody("toplevel", TopLevel->children, 1, line_buffer, 0);
  332.     fclose(Input);
  333.     return TRUE;
  334.   }
  335.   else return FALSE;
  336. }
  337.  
  338. TexMacroDef::TexMacroDef(char *the_name, int n, Bool ig, Bool consumeSpace)
  339. {
  340.   name = copystring(the_name);
  341.   no_args = n;
  342.   ignore = ig;
  343.   consume_space = consumeSpace;
  344. }
  345.  
  346. TexMacroDef::~TexMacroDef(void)
  347. {
  348.   if (name) delete name;
  349. }
  350.  
  351. TexChunk::TexChunk(int the_type)
  352. {
  353.   type = the_type;
  354.   no_args = 0;
  355.   argn = 0;
  356.   name = NULL;
  357.   value = NULL;
  358.   children.DeleteContents(TRUE);
  359. }
  360.  
  361. TexChunk::~TexChunk(void)
  362. {
  363.   if (name) delete name;
  364.   if (value) delete value;
  365. }
  366.  
  367. /*
  368.  * Traverses document calling functions to allow the client to
  369.  * write out the appropriate stuff
  370.  */
  371.  
  372.  
  373. void TraverseDocument1(TexChunk *chunk)
  374. {
  375.   switch (chunk->type)
  376.   {
  377.     case CHUNK_TYPE_MACRO:
  378.     {
  379.       wxNode *node = MacroDefs.Find(chunk->name);
  380.       if (node)
  381.       {
  382.         TexMacroDef *def = (TexMacroDef *)node->Data();
  383.         if (def->ignore)
  384.           return;
  385.       }
  386.  
  387.       OnMacro(chunk->name, chunk->no_args, TRUE);
  388.  
  389.       node = chunk->children.First();
  390.       while (node)
  391.       {
  392.         TexChunk *child_chunk = (TexChunk *)node->Data();
  393.         TraverseDocument1(child_chunk);
  394.         node = node->Next();
  395.       }
  396.  
  397.       OnMacro(chunk->name, chunk->no_args, FALSE);
  398.       break;
  399.     }
  400.     case CHUNK_TYPE_ARG:
  401.     {
  402.       OnArgument(chunk->name, chunk->argn, TRUE);
  403.  
  404.       wxNode *node = chunk->children.First();
  405.       while (node)
  406.       {
  407.         TexChunk *child_chunk = (TexChunk *)node->Data();
  408.         TraverseDocument1(child_chunk);
  409.         node = node->Next();
  410.       }
  411.  
  412.       OnArgument(chunk->name, chunk->argn, FALSE);
  413.       break;
  414.     }
  415.     case CHUNK_TYPE_STRING:
  416.     {
  417.       if (chunk->value)
  418.         TexOutput(chunk->value);
  419.       break;
  420.     }
  421.   }
  422. }
  423.  
  424. void TraverseDocument(void)
  425. {
  426.   TraverseDocument1(TopLevel);
  427. }
  428.  
  429. void SetCurrentOutput(FILE *fd)
  430. {
  431.   CurrentOutput1 = fd;
  432.   CurrentOutput2 = NULL;
  433. }
  434.  
  435. void SetCurrentOutputs(FILE *fd1, FILE *fd2)
  436. {
  437.   CurrentOutput1 = fd1;
  438.   CurrentOutput2 = fd2;
  439. }
  440.  
  441. void AddMacroDef(char *name, int n, Bool ignore, Bool consume_space)
  442. {
  443.   MacroDefs.Append(name, new TexMacroDef(name, n, ignore, consume_space));
  444. }
  445.  
  446. void TexInitialize(void)
  447. {
  448.   BigBuffer = new char[20000];
  449.   AddMacroDef("toplevel", 1);
  450.   TopLevel = new TexChunk(CHUNK_TYPE_MACRO);
  451.   TopLevel->name = copystring("toplevel");
  452.   TopLevel->no_args = 1;
  453. }
  454.