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.
14 * Copyright (c) 1995 Sun Microsystems, Inc.
16 * See the file "license.terms" for information on usage and redistribution
17 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08";
32 * Imported things that aren't defined in header files:
38 * Current line number, used for error messages.
41 static int lineNumber;
44 * The variable below is set to 1 if an error occurs anywhere
45 * while reading in the file.
51 * The variable below is set to 1 if output should be generated.
52 * If it's 0, it means we're doing a pre-pass to make sure that
53 * the file can be properly parsed.
56 static int writeOutput;
59 * Prototypes for procedures defined in this file:
62 static void DoMacro(char *line);
63 static void DoText(char *line);
64 static void QuoteText(char *string, int count);
67 *----------------------------------------------------------------------
71 * This procedure is the main program, which does all of the work
75 * None: exits with a 0 return status to indicate success, or
76 * 1 to indicate that there were problems in the translation.
79 * A Tcl script is output to standard output. Error messages may
80 * be output on standard error.
82 *----------------------------------------------------------------------
87 int argc; /* Number of command-line arguments. */
88 char **argv; /* Values of command-line arguments. */
91 #define MAX_LINE_SIZE 500
92 char line[MAX_LINE_SIZE];
96 * Find the file to read, and open it if it isn't stdin.
101 } else if (argc == 2) {
102 f = fopen(argv[1], "r");
104 fprintf(stderr, "Couldn't read \"%s\": %s\n", argv[1],
109 fprintf(stderr, "Usage: %s ?fileName?\n", argv[0]);
113 * Make two passes over the file. In the first pass, just check
114 * to make sure we can handle everything. If there are problems,
115 * generate output and stop. If everything is OK, make a second
116 * pass to actually generate output.
119 for (writeOutput = 0; writeOutput < 2; writeOutput++) {
122 while (fgets(line, MAX_LINE_SIZE, f) != NULL) {
123 for (p = line; *p != 0; p++) {
131 if ((line[0] == '\'') && (line[1] == '\\') && (line[2] == '\"')) {
133 * This line is a comment. Ignore it.
139 if ((line[0] == '.') || (line[0] == '\'')) {
141 * This line is a macro invocation.
147 * This line is text, possibly with formatting characters
157 fseek(f, 0, SEEK_SET);
163 *----------------------------------------------------------------------
167 * This procedure is called to handle a macro invocation.
168 * It parses the arguments to the macro and generates a
169 * Tcl command to handle the invocation.
175 * A Tcl command is written to stdout.
177 *----------------------------------------------------------------------
182 char *line; /* The line of text that contains the
183 * macro invocation. */
188 * If there is no macro name, then just skip the whole line.
191 if ((line[1] == 0) || (isspace(line[1]))) {
205 * Parse the arguments to the macro (including the name), in order.
215 * The argument is delimited by quotes.
218 for (end = p+1; *end != '"'; end++) {
221 "Unclosed quote in macro call on line %d.\n",
227 QuoteText(p+1, (end-(p+1)));
229 for (end = p+1; (*end != 0) && !isspace(*end); end++) {
230 /* Empty loop body. */
238 while (isspace(*p)) {
240 * Skip empty space before next argument.
255 *----------------------------------------------------------------------
259 * This procedure is called to handle a line of troff text.
260 * It parses the text, generating Tcl commands for text and
261 * for formatting stuff such as font changes.
267 * Tcl commands are written to stdout.
269 *----------------------------------------------------------------------
274 char *line; /* The line of text. */
279 * Divide the line up into pieces consisting of backslash sequences,
280 * tabs, and other text.
290 } else if (*p != '\\') {
295 for (end = p+1; (*end != '\\') && (*end != 0); end++) {
296 /* Empty loop body. */
308 * A backslash sequence. There are particular ones
309 * that we understand; output an error message for
310 * anything else and just ignore the backslash.
320 printf("font %c\n", p[1]);
323 } else if (*p == '-') {
328 } else if (*p == 'e') {
330 printf("text \\\\\n");
333 } else if (*p == '.') {
338 } else if (*p == '&') {
340 } else if (*p == '(') {
341 if ((p[1] == 0) || (p[2] == 0)) {
342 fprintf(stderr, "Bad \\( sequence on line %d.\n",
347 printf("char {\\(%c%c}\n", p[1], p[2]);
351 } else if (*p != 0) {
353 printf("char {\\%c}\n", *p);
365 *----------------------------------------------------------------------
369 * Copy the "string" argument to stdout, adding quote characters
370 * around any special Tcl characters so that they'll just be treated
377 * Text is written to stdout.
379 *----------------------------------------------------------------------
383 QuoteText(string, count)
384 char *string; /* The line of text. */
385 int count; /* Number of characters to write from string. */
393 for ( ; count > 0; string++, count--) {
394 if ((*string == '$') || (*string == '[') || (*string == '{')
395 || (*string == ' ') || (*string == ';') || (*string == '\\')
396 || (*string == '"') || (*string == '\t')) {
402 putc(*string, stdout);