Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/tools/man2tcl.c @ 35

Last change on this file since 35 was 25, checked in by landauf, 18 years ago

added tcl to libs

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