Ultrix-3.1/src/cmd/ctrace/main.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
static char Sccsid[] = "@(#)main.c 3.0 4/21/86";
/* (System V) main.c 1.3 */
/* ctrace - C program debugging tool
*
* main function - interprets arguments
*/
#include "global.h"
/* global options */
enum bool suppress = no; /* suppress redundant trace output (-s) */
enum bool pound_line = no; /* input preprocessed so suppress #line */
int tracemax = TRACE_DFLT; /* maximum traced variables per statement (-t number) */
/* local options */
static enum bool preprocessor = no; /* run the preprocessor (-P) */
static enum bool octal = no; /* print variable values in octal (-o) */
static enum bool hex = no; /* print variable values in hex (-x) */
static enum bool unsign = no; /* print variable values as unsigned (-u) */
static enum bool floating = no; /* print variable values as float (-e) */
static enum bool only = no; /* trace only these functions (-f) */
static enum bool basic = no; /* use basic functions only (-b) */
static int loopmax = LOOPMAX; /* maximum loop size for loop recognition (-l number) */
static char *print_fcn = "printf("; /* run-time print function (-p string) */
static char *codefile = NULL; /* run-time package file name (-r file) */
/* global data */
char *filename = ""; /* input file name */
enum bool trace; /* indicates if this function should be traced */
/* local data */
static int error_code = 0; /* exiting error code */
static int fcn_count = 0; /* number of functions (-f and -v) */
static char **fcn_names; /* function names (-f and -v) */
static char *pp_command; /* preprocessor command (-P) */
static enum bool fcn_traced = no; /* indicates if at least one function was traced */
main(argc, argv)
int argc;
char *argv[];
{
int i;
char option, *s;
char *strsave();
FILE *fopen(), *popen();
/* set the options */
if ((pp_command = strsave(PP_COMMAND)) == NULL) {
fprintf(stderr, "ctrace: out of memory\n");
exit(1);
}
while (--argc > 0 && (*++argv)[0] == '-') {
for (s = argv[0] + 1; *s != '\0'; s++)
switch (*s) {
case 'P': /* run the preprocessor */
preprocessor = yes;
break;
case 'D': /* options for preprocessor */
case 'I':
case 'U':
preprocessor = yes;
append(pp_command, argv[0]);
goto next_arg;
case 'o': /* variable output in octal */
octal = yes;
break;
case 'x': /* variable output in hex */
hex = yes;
break;
case 'u': /* variable output as unsigned */
unsign = yes;
break;
case 'e': /* print variable values as float */
floating = yes;
break;
case 'b': /* use basic functions only */
basic = yes;
break;
case 's': /* suppress redundant trace output */
suppress = yes;
break;
/* options with string arguments */
case 'p':
case 'r':
case 'T': /* obsolete option */
option = *s;
if (*++s == '\0' && --argc > 0) {
s = *++argv;
}
switch (option) {
case 'p': /* run-time print function */
print_fcn = s;
break;
case 'r': /* run-time code file name */
codefile = s;
break;
case 'T': /* define symbol as a type */
add_type(s);
break;
}
goto next_arg;
case 'f': /* trace only these functions */
only = yes;
case 'v': /* trace all but these functions */
fcn_names = argv + 1; /* not valid if no more args */
/* look for the file name or next option */
while (--argc > 0) {
s = *++argv; /* get next arg */
if (s[0] == '-' || s[strlen(s) - 2] == '.') {
--argv; /* back up one arg */
break;
}
/* shorten long function names */
if (strlen(s) > IDMAX)
s[IDMAX] = '\0';
++fcn_count;
}
++argc; /* back up one arg */
goto next_arg;
case 'l': /* options with a numeric argument */
case 't':
option = *s;
if (*++s == '\0' && --argc > 0)
s = *++argv;
/* convert the argument to an integer and check for a conversion error */
if (*s < '0' || *s > '9' || ((i = atoi(s)) == 0 && option == 't')) {
fprintf(stderr, "ctrace: -%c option: missing or invalid numeric value\n", option);
goto usage;
}
switch (option) {
case 'l': /* print all loop trace output */
loopmax = i;
break;
case 't': /* maximum traced variables per statement */
tracemax = i;
if (tracemax > TRACEMAX) /* force into range */
tracemax = TRACEMAX;
break;
}
goto next_arg;
default:
fprintf(stderr, "ctrace: illegal option: -%c\n", *s);
usage:
fprintf(stderr, "Usage: ctrace [-beosuxP] [C preprocessor options] [-f|v functions]\n");
fprintf(stderr, " [-p string] [-r file] [-l number] [-t number] [file]\n");
exit(1);
}
next_arg: ;
}
/* open the input file */
yyin = stdin; /* default to the standard input */
if (argc > 0) {
filename = *argv; /* save the file name for messages */
if ((yyin = fopen(filename, "r")) == NULL) {
fprintf(stderr, "ctrace: cannot open file %s\n", filename);
exit(1);
}
}
/* run the preprocessor if requested */
if (preprocessor) {
if (strcmp(filename, "") != 0) {
append(pp_command, filename);
}
if ((yyin = popen(pp_command, "r")) == NULL) {
fprintf(stderr, "ctrace: cannot run preprocessor (%s)\n", pp_command);
exit(1);
}
pound_line = yes; /* suppress #line insertion */
}
/* #define CTRACE so you can put this in your code:
* #ifdef CTRACE
* ctroff();
* #endif
*/
printf("#define CTRACE 1\n");
/* prepend signal.h (needed by the runtime package) so programs that
call signal but don't include signal.h won't get a "redeclaration
of signal" compiler error */
if (!basic) {
printf("#include <signal.h>\n");
}
/* prepend a #line statement with the original file name for
compiler errors in programs with no preprocessor statements */
printf("#line 1 \"%s\"\n", filename);
/* put the keywords into the symbol table */
init_symtab();
/* trace the executable statements */
yyparse();
/* output the run-time package of trace functions */
if (fcn_traced)
runtime();
/* final processing */
quit();
}
/* append an argument to the command */
append(s1, s2)
char *s1, *s2;
{
char *realloc(), *strcat();
/* increase the command string size */
if ((s1 = realloc(s1, (unsigned) (strlen(s1) + strlen(s2) + 4))) == NULL) {
fprintf(stderr, "ctrace: out of storage");
exit(1);
}
/* append the argument with single quotes around it to preserve any special chars */
strcat(s1, " '");
strcat(s1, s2);
strcat(s1, "'");
}
/* determine if this function should be traced */
tr_fcn(identifier)
char *identifier;
{
int i;
/* set default trace mode */
if (only)
trace = no;
else
trace = yes;
/* change the mode if this function is in the list */
for (i = 0; i < fcn_count; ++i)
if (strcmp(identifier, fcn_names[i]) == 0){
if (only)
trace = yes;
else
trace = no;
break;
}
/* indicate if any function was traced */
if (trace)
fcn_traced = yes;
}
/* output the run-time package of trace functions */
runtime()
{
register int c;
register FILE *code;
char pathname[100];
char *s;
char *getenv(), *strcat(), *strcpy();
/* force the output to a new line for the preprocessor statements */
putchar('\n');
/* if stdio.h has already been included and preprocessed then
just define stdout. _iob would be defined twice if stdio.h is
included again */
if (stdio_preprocessed)
printf("#undef\tstdout\n#define stdout\t\t(&_iob[1])\n");
/* if the output is not to be buffered then include stdio.h to get the stdout symbol */
else if (!basic)
printf("#include <stdio.h>\n");
/* see if setjmp.h has already been included and preprocessed.
jmp_buf would be defined twice if it is included again */
if (!setjmp_preprocessed && !basic)
printf("#include <setjmp.h>\n");
/* make preprocessor definitions to tailor the code */
printf("#define VM_CT_ %d\n", tracemax);
printf("#define PF_CT_ %s\n", print_fcn);
if (octal)
printf("#define O_CT_\n");
if (hex)
printf("#define X_CT_\n");
if (unsign)
printf("#define U_CT_\n");
if (floating)
printf("#define E_CT_\n");
if (basic)
printf("#define B_CT_\n");
if (loopmax != 0)
printf("#define LM_CT_ %d\n", loopmax);
/* construct the file name of the runtime trace package */
strcpy(pathname, RUNTIME);
if (codefile != NULL) {
strcpy(pathname, codefile);
}
/* open the file */
if ((code = fopen(pathname, "r")) == NULL) {
fprintf(stderr, "ctrace: cannot open runtime code file %s\n", pathname);
exit(1);
}
/* output the runtime trace package */
printf("#line 1 \"%s\"\n", pathname);
while ((c = getc(code)) != EOF) {
putchar(c);
}
}
/* error and warning message functions */
fatal(text)
char *text;
{
error(text);
error_code = 3;
quit();
}
error(text)
char *text;
{
msg_header();
fprintf(stderr, "%s\n", text);
error_code = 2;
}
warning(text)
char *text;
{
msg_header();
fprintf(stderr, "warning: %s\n", text);
}
static
msg_header()
{
fprintf(stderr, "ctrace: ");
if (strcmp(filename, "") != 0)
fprintf(stderr, "\"%s\", ", filename);
fprintf(stderr, "line %d: ", yylineno);
}
quit()
{
if (error_code > 1) {
fprintf(stderr, "See the ctrace manual page \"diagnostics\" section for help.\n");
}
exit(error_code);
}