home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tcl8.0.5 / os2 / man2tcl.c < prev    next >
C/C++ Source or Header  |  1999-04-29  |  8KB  |  403 lines

  1. /* 
  2.  * man2tcl.c --
  3.  *
  4.  *    This file contains a program that turns a man page of the
  5.  *    form used for Tcl and Tk into a Tcl script that invokes
  6.  *    a Tcl command for each construct in the man page.  The
  7.  *    script can then be eval'ed to translate the manual entry
  8.  *    into some other format such as MIF or HTML.
  9.  *
  10.  * Usage:
  11.  *
  12.  *    man2tcl ?fileName?
  13.  *
  14.  * Copyright (c) 1995 Sun Microsystems, Inc.
  15.  *
  16.  * See the file "license.terms" for information on usage and redistribution
  17.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  18.  *
  19.  * RCS: @(#) $Id: man2tcl.c,v 1.3 1999/04/16 00:47:40 stanton Exp $
  20.  */
  21.  
  22. static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08";
  23.  
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27.  
  28. /*
  29.  * Imported things that aren't defined in header files:
  30.  */
  31.  
  32. extern int errno;
  33.  
  34. /*
  35.  * Current line number, used for error messages.
  36.  */
  37.  
  38. static int lineNumber;
  39.  
  40. /*
  41.  * The variable below is set to 1 if an error occurs anywhere
  42.  * while reading in the file.
  43.  */
  44.  
  45. static int status;
  46.  
  47. /*
  48.  * The variable below is set to 1 if output should be generated.
  49.  * If it's 0, it means we're doing a pre-pass to make sure that
  50.  * the file can be properly parsed.
  51.  */
  52.  
  53. static int writeOutput;
  54.  
  55. /*
  56.  * Prototypes for procedures defined in this file:
  57.  */
  58.  
  59. static void        DoMacro(char *line);
  60. static void        DoText(char *line);
  61. static void        QuoteText(char *string, int count);
  62.  
  63. /*
  64.  *----------------------------------------------------------------------
  65.  *
  66.  * main --
  67.  *
  68.  *    This procedure is the main program, which does all of the work
  69.  *    of the program.
  70.  *
  71.  * Results:
  72.  *    None: exits with a 0 return status to indicate success, or
  73.  *    1 to indicate that there were problems in the translation.
  74.  *
  75.  * Side effects:
  76.  *    A Tcl script is output to standard output.  Error messages may
  77.  *    be output on standard error.
  78.  *
  79.  *----------------------------------------------------------------------
  80.  */
  81.  
  82. int
  83. main(argc, argv)
  84.     int argc;            /* Number of command-line arguments. */
  85.     char **argv;        /* Values of command-line arguments. */
  86. {
  87.     FILE *f;
  88. #define MAX_LINE_SIZE 500
  89.     char line[MAX_LINE_SIZE];
  90.     char *p;
  91.  
  92.     /*
  93.      * Find the file to read, and open it if it isn't stdin.
  94.      */
  95.  
  96.     if (argc == 1) {
  97.     f = stdin;
  98.     } else if (argc == 2) {
  99.     f = fopen(argv[1], "r");
  100.     if (f == NULL) {
  101.         fprintf(stderr, "Couldn't read \"%s\": %s\n", argv[1],
  102.             strerror(errno));
  103.         exit(1);
  104.     }
  105.     } else {
  106.     fprintf(stderr, "Usage: %s ?fileName?\n", argv[0]);
  107.     }
  108.  
  109.     /*
  110.      * Make two passes over the file.  In the first pass, just check
  111.      * to make sure we can handle everything.  If there are problems,
  112.      * generate output and stop.  If everything is OK, make a second
  113.      * pass to actually generate output.
  114.      */
  115.  
  116.     for (writeOutput = 0; writeOutput < 2; writeOutput++) {
  117.     lineNumber = 0;
  118.     status = 0;
  119.     while (fgets(line, MAX_LINE_SIZE, f) != NULL) {
  120.         for (p = line; *p != 0; p++) {
  121.         if (*p == '\n') {
  122.             *p = 0;
  123.             break;
  124.         }
  125.         }
  126.         lineNumber++;
  127.     
  128.         if ((line[0] == '\'') && (line[1] == '\\') && (line[2] == '\"')) {
  129.         /* 
  130.          * This line is a comment.  Ignore it.
  131.          */
  132.     
  133.         continue;
  134.         }
  135.     
  136.         if ((line[0] == '.') || (line[0] == '\'')) {
  137.         /*
  138.          * This line is a macro invocation.
  139.          */
  140.     
  141.         DoMacro(line);
  142.         } else {
  143.         /*
  144.          * This line is text, possibly with formatting characters
  145.          * embedded in it.
  146.          */
  147.     
  148.         DoText(line);
  149.         }
  150.     }
  151.     if (status != 0) {
  152.         break;
  153.     }
  154.     fseek(f, 0, SEEK_SET);
  155.     }
  156.     exit(status);
  157. }
  158.  
  159. /*
  160.  *----------------------------------------------------------------------
  161.  *
  162.  * DoMacro --
  163.  *
  164.  *    This procedure is called to handle a macro invocation.
  165.  *    It parses the arguments to the macro and generates a
  166.  *    Tcl command to handle the invocation.
  167.  *
  168.  * Results:
  169.  *    None.
  170.  *
  171.  * Side effects:
  172.  *    A Tcl command is written to stdout.
  173.  *
  174.  *----------------------------------------------------------------------
  175.  */
  176.  
  177. static void
  178. DoMacro(line)
  179.     char *line;            /* The line of text that contains the
  180.                  * macro invocation. */
  181. {
  182.     char *p, *end;
  183.  
  184.     /*
  185.      * If there is no macro name, then just skip the whole line.
  186.      */
  187.  
  188.     if ((line[1] == 0) || (isspace(line[1]))) {
  189.     return;
  190.     }
  191.  
  192.     if (writeOutput) {
  193.     printf("macro");
  194.     }
  195.     if (*line != '.') {
  196.     if (writeOutput) {
  197.         printf("2");
  198.     }
  199.     }
  200.  
  201.     /*
  202.      * Parse the arguments to the macro (including the name), in order.
  203.      */
  204.  
  205.     p = line+1;
  206.     while (1) {
  207.     if (writeOutput) {
  208.         putc(' ', stdout);
  209.     }
  210.     if (*p == '"')  {
  211.         /*
  212.          * The argument is delimited by quotes.
  213.          */
  214.  
  215.         for (end = p+1; *end != '"'; end++) {
  216.         if (*end == 0) {
  217.             fprintf(stderr,
  218.             "Unclosed quote in macro call on line %d.\n",
  219.             lineNumber);
  220.             status = 1;
  221.             break;
  222.         }
  223.         }
  224.         QuoteText(p+1, (end-(p+1)));
  225.     } else {
  226.         for (end = p+1;  (*end != 0) && !isspace(*end); end++) {
  227.         /* Empty loop body. */
  228.         }
  229.         QuoteText(p, end-p);
  230.     }
  231.     if (*end == 0) {
  232.         break;
  233.     }
  234.     p = end+1;
  235.     while (isspace(*p)) {
  236.         /*
  237.          * Skip empty space before next argument.
  238.          */
  239.  
  240.         p++;
  241.     }
  242.     if (*p == 0) {
  243.         break;
  244.     }
  245.     }
  246.     if (writeOutput) {
  247.     putc('\n', stdout);
  248.     }
  249. }
  250.  
  251. /*
  252.  *----------------------------------------------------------------------
  253.  *
  254.  * DoText --
  255.  *
  256.  *    This procedure is called to handle a line of troff text.
  257.  *    It parses the text, generating Tcl commands for text and
  258.  *    for formatting stuff such as font changes.
  259.  *
  260.  * Results:
  261.  *    None.
  262.  *
  263.  * Side effects:
  264.  *    Tcl commands are written to stdout.
  265.  *
  266.  *----------------------------------------------------------------------
  267.  */
  268.  
  269. static void
  270. DoText(line)
  271.     char *line;            /* The line of text. */
  272. {
  273.     char *p, *end;
  274.  
  275.     /*
  276.      * Divide the line up into pieces consisting of backslash sequences,
  277.      * tabs, and other text.
  278.      */
  279.  
  280.     p = line;
  281.     while (*p != 0) {
  282.     if (*p == '\t') {
  283.         if (writeOutput) {
  284.         printf("tab\n");
  285.         }
  286.         p++;
  287.     } else if (*p != '\\') {
  288.         /*
  289.          * Ordinary text.
  290.          */
  291.  
  292.         for (end = p+1; (*end != '\\') && (*end != 0); end++) {
  293.         /* Empty loop body. */
  294.         }
  295.         if (writeOutput) {
  296.         printf("text ");
  297.         }
  298.         QuoteText(p, end-p);
  299.         if (writeOutput) {
  300.         putc('\n', stdout);
  301.         }
  302.         p = end;
  303.     } else {
  304.         /*
  305.          * A backslash sequence.  There are particular ones
  306.          * that we understand;  output an error message for
  307.          * anything else and just ignore the backslash.
  308.          */
  309.  
  310.         p++;
  311.         if (*p == 'f') {
  312.         /*
  313.          * Font change.
  314.          */
  315.  
  316.         if (writeOutput) {
  317.             printf("font %c\n", p[1]);
  318.         }
  319.         p += 2;
  320.         } else if (*p == '-') {
  321.         if (writeOutput) {
  322.             printf("dash\n");
  323.         }
  324.         p++;
  325.         } else if (*p == 'e') {
  326.         if (writeOutput) {
  327.             printf("text \\\\\n");
  328.         }
  329.         p++;
  330.         } else if (*p == '.') {
  331.         if (writeOutput) {
  332.             printf("text .\n");
  333.         }
  334.         p++;
  335.         } else if (*p == '&') {
  336.         p++;
  337.         } else if (*p == '(') {
  338.         if ((p[1] == 0) || (p[2] == 0)) {
  339.             fprintf(stderr, "Bad \\( sequence on line %d.\n",
  340.                 lineNumber);
  341.             status = 1;
  342.         } else {
  343.             if (writeOutput) {
  344.             printf("char {\\(%c%c}\n", p[1], p[2]);
  345.             }
  346.             p += 3;
  347.         }
  348.         } else if (*p != 0) {
  349.         if (writeOutput) {
  350.             printf("char {\\%c}\n", *p);
  351.         }
  352.         p++;
  353.         }
  354.     }
  355.     }
  356.     if (writeOutput) {
  357.     printf("newline\n");
  358.     }
  359. }
  360.  
  361. /*
  362.  *----------------------------------------------------------------------
  363.  *
  364.  * QuoteText --
  365.  *
  366.  *    Copy the "string" argument to stdout, adding quote characters
  367.  *    around any special Tcl characters so that they'll just be treated
  368.  *    as ordinary text.
  369.  *
  370.  * Results:
  371.  *    None.
  372.  *
  373.  * Side effects:
  374.  *    Text is written to stdout.
  375.  *
  376.  *----------------------------------------------------------------------
  377.  */
  378.  
  379. static void
  380. QuoteText(string, count)
  381.     char *string;        /* The line of text. */
  382.     int count;            /* Number of characters to write from string. */
  383. {
  384.     if (count == 0) {
  385.     if (writeOutput) {
  386.         printf("{}");
  387.     }
  388.     return;
  389.     }
  390.     for ( ; count > 0; string++, count--) {
  391.     if ((*string == '$') || (*string == '[') || (*string == '{')
  392.         || (*string == ' ') || (*string == ';') || (*string == '\\')
  393.         || (*string == '"') || (*string == '\t')) {
  394.         if (writeOutput) {
  395.         putc('\\', stdout);
  396.         }
  397.     }
  398.     if (writeOutput) {
  399.         putc(*string, stdout);
  400.     }
  401.     }
  402. }
  403.