diff options
Diffstat (limited to 'tcl8.6/tools/man2tcl.c')
-rw-r--r-- | tcl8.6/tools/man2tcl.c | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/tcl8.6/tools/man2tcl.c b/tcl8.6/tools/man2tcl.c new file mode 100644 index 0000000..8e59bea --- /dev/null +++ b/tcl8.6/tools/man2tcl.c @@ -0,0 +1,424 @@ +/* + * man2tcl.c -- + * + * This file contains a program that turns a man page of the form used + * for Tcl and Tk into a Tcl script that invokes a Tcl command for each + * construct in the man page. The script can then be eval'ed to translate + * the manual entry into some other format such as MIF or HTML. + * + * Usage: + * + * man2tcl ?fileName? + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08"; + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +/* + * Imported things that aren't defined in header files: + */ + +/* + * Some <errno.h> define errno to be something complex and thread-aware; in + * that case we definitely do not want to declare errno ourselves! + */ + +#ifndef errno +extern int errno; +#endif + +/* + * Current line number, used for error messages. + */ + +static int lineNumber; + +/* + * The variable below is set to 1 if an error occurs anywhere while reading in + * the file. + */ + +static int status; + +/* + * The variable below is set to 1 if output should be generated. If it's 0, it + * means we're doing a pre-pass to make sure that the file can be properly + * parsed. + */ + +static int writeOutput; + +#define PRINT(args) if (writeOutput) { printf args; } +#define PRINTC(chr) if (writeOutput) { putc((chr), stdout); } + +/* + * Prototypes for functions defined in this file: + */ + +static void DoMacro(char *line); +static void DoText(char *line); +static void QuoteText(char *string, int count); + +/* + *---------------------------------------------------------------------- + * + * main -- + * + * This function is the main program, which does all of the work of the + * program. + * + * Results: + * None: exits with a 0 return status to indicate success, or 1 to + * indicate that there were problems in the translation. + * + * Side effects: + * A Tcl script is output to standard output. Error messages may be + * output on standard error. + * + *---------------------------------------------------------------------- + */ + +int +main( + int argc, /* Number of command-line arguments. */ + char **argv) /* Values of command-line arguments. */ +{ + FILE *f; +#define MAX_LINE_SIZE 4000 + char line[MAX_LINE_SIZE]; + char *p; + + /* + * Find the file to read, and open it if it isn't stdin. + */ + + if (argc == 1) { + f = stdin; + } else if (argc == 2) { + f = fopen(argv[1], "r"); + if (f == NULL) { + fprintf(stderr, "Couldn't read \"%s\": %s\n", argv[1], + strerror(errno)); + exit(1); + } + } else { + fprintf(stderr, "Usage: %s ?fileName?\n", argv[0]); + } + + /* + * Make two passes over the file. In the first pass, just check to make + * sure we can handle everything. If there are problems, generate output + * and stop. If everything is OK, make a second pass to actually generate + * output. + */ + + for (writeOutput = 0; writeOutput < 2; writeOutput++) { + lineNumber = 0; + status = 0; + while (fgets(line, MAX_LINE_SIZE, f) != NULL) { + for (p = line; *p != 0; p++) { + if (*p == '\n') { + *p = 0; + break; + } + } + lineNumber++; + + if (((line[0] == '.') || (line[0] == '\'')) && (line[1] == '\\') && (line[2] == '\"')) { + /* + * This line is a comment. Ignore it. + */ + + continue; + } + + if (strlen(line) >= MAX_LINE_SIZE -1) { + fprintf(stderr, "Too long line. Max is %d chars.\n", + MAX_LINE_SIZE - 1); + exit(1); + } + + if ((line[0] == '.') || (line[0] == '\'')) { + /* + * This line is a macro invocation. + */ + + DoMacro(line); + } else { + /* + * This line is text, possibly with formatting characters + * embedded in it. + */ + + DoText(line); + } + } + if (status != 0) { + break; + } + fseek(f, 0, SEEK_SET); + } + exit(status); +} + +/* + *---------------------------------------------------------------------- + * + * DoMacro -- + * + * This function is called to handle a macro invocation. It parses the + * arguments to the macro and generates a Tcl command to handle the + * invocation. + * + * Results: + * None. + * + * Side effects: + * A Tcl command is written to stdout. + * + *---------------------------------------------------------------------- + */ + +static void +DoMacro( + char *line) /* The line of text that contains the macro + * invocation. */ +{ + char *p, *end; + int quote; + + /* + * If there is no macro name, then just skip the whole line. + */ + + if ((line[1] == 0) || (isspace(line[1]))) { + return; + } + + PRINT(("macro")); + if (*line != '.') { + PRINT(("2")); + } + + /* + * Parse the arguments to the macro (including the name), in order. + */ + + p = line+1; + while (1) { + PRINTC(' '); + if (*p == '"') { + /* + * The argument is delimited by quotes. + */ + + for (end = p+1; *end != '"'; end++) { + if (*end == 0) { + fprintf(stderr, + "Unclosed quote in macro call on line %d.\n", + lineNumber); + status = 1; + break; + } + } + QuoteText(p+1, (end-(p+1))); + } else { + quote = 0; + for (end = p+1; (*end != 0) && (quote || !isspace(*end)); end++) { + if (*end == '\'') { + quote = !quote; + } + } + QuoteText(p, end-p); + } + if (*end == 0) { + break; + } + p = end+1; + while (isspace(*p)) { + /* + * Skip empty space before next argument. + */ + + p++; + } + if (*p == 0) { + break; + } + } + PRINTC('\n'); +} + +/* + *---------------------------------------------------------------------- + * + * DoText -- + * + * This function is called to handle a line of troff text. It parses the + * text, generating Tcl commands for text and for formatting stuff such + * as font changes. + * + * Results: + * None. + * + * Side effects: + * Tcl commands are written to stdout. + * + *---------------------------------------------------------------------- + */ + +static void +DoText( + char *line) /* The line of text. */ +{ + char *p, *end; + + /* + * Divide the line up into pieces consisting of backslash sequences, tabs, + * and other text. + */ + + p = line; + while (*p != 0) { + if (*p == '\t') { + PRINT(("tab\n")); + p++; + } else if (*p != '\\') { + /* + * Ordinary text. + */ + + for (end = p+1; (*end != '\\') && (*end != 0); end++) { + /* Empty loop body. */ + } + PRINT(("text ")); + QuoteText(p, end-p); + PRINTC('\n'); + p = end; + } else { + /* + * A backslash sequence. There are particular ones that we + * understand; output an error message for anything else and just + * ignore the backslash. + */ + + p++; + if (*p == 'f') { + /* + * Font change. + */ + + PRINT(("font %c\n", p[1])); + p += 2; + } else if (*p == '-') { + PRINT(("dash\n")); + p++; + } else if (*p == 'e') { + PRINT(("text \\\\\n")); + p++; + } else if (*p == '.') { + PRINT(("text .\n")); + p++; + } else if (*p == '&') { + p++; + } else if (*p == '0') { + PRINT(("text { }\n")); + p++; + } else if (*p == '(') { + if ((p[1] == 0) || (p[2] == 0)) { + fprintf(stderr, "Bad \\( sequence on line %d.\n", + lineNumber); + status = 1; + } else { + PRINT(("char {\\(%c%c}\n", p[1], p[2])); + p += 3; + } + } else if (*p == 'N' && *(p+1) == '\'') { + int ch; + + p += 2; + sscanf(p,"%d",&ch); + PRINT(("text \\u%04x\n", ch)); + while(*p&&*p!='\'') p++; + p++; + } else if (*p != 0) { + PRINT(("char {\\%c}\n", *p)); + p++; + } + } + } + PRINT(("newline\n")); +} + +/* + *---------------------------------------------------------------------- + * + * QuoteText -- + * + * Copy the "string" argument to stdout, adding quote characters around + * any special Tcl characters so that they'll just be treated as ordinary + * text. + * + * Results: + * None. + * + * Side effects: + * Text is written to stdout. + * + *---------------------------------------------------------------------- + */ + +static void +QuoteText( + char *string, /* The line of text. */ + int count) /* Number of characters to write from + * string. */ +{ + if (count == 0) { + PRINT(("{}")); + return; + } + for ( ; count > 0; string++, count--) { + switch (*string) { + case '\\': + if (*(string+1) == 'N' && *(string+2) == '\'') { + int ch; + + string += 3; + count -= 3; + sscanf(string,"%d",&ch); + PRINT(("\\u%04x", ch)); + while(count>0&&*string!='\'') {string++;count--;} + continue; + } else if (*(string+1) == '0') { + PRINT(("\\ ")); + string++; + count--; + continue; + } + case '$': case '[': case '{': case ' ': case ';': + case '"': case '\t': + PRINTC('\\'); + default: + PRINTC(*string); + } + } +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |