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