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