/* ******************************************************************* * * * Copyright (c) L-DGO/MIT/JGOFS * * * * * * File : list.c * * * * Revision History : * * * * Date Developer * * ---- --------- * */ #define LIST_VERSION "list version 1.9 28 Apr 2017" /* * 22 Apr 17 wjs * * Have list output line counts * * Don't allow outfile to begin w/ a hyphen (happens if user * * puts switch after object spec) * * [begin v 1.9] * * 21 Apr 17 wjs * * Put jdb condition into exit-after-jdbopen-failure message * * [begin v 1.8d] * * 30 Nov 16 wjs * * Fix LIST_VERSION, which was dated 2916 * * 9 Aug 16 wjs * * Process INCLUDE_ATTRIBUTES_SWITCH stuff before processing com- * * mand line switches since the text that gets printed for bad * * switches depends on inc_attr_switch, etc * * [begin v 1.8c] * * 22 Jan 15 wjs * * Make list behave as documented regarding env var * * INCLUDE_ATTRIBUTES_SWITCH; ie, implement it * * [begin v 1.8b] * * 20 Feb 09 wjs * * Bug fix: off-by-1 length calculation in outstr * * Bug fix: code tried to trim "separators" off the pretty- * * print dividing lines which were char constants. Make * * them variables so code succeeds. * * [begin v 1.8a] * * 3 Aug 08 wjs * * -nohelp, -errprefix * * Fix some formatting of help printout * * Move old comments to list_revision.doc * * [Needs list.h v 1.5] * * [begin v 1.8] * * 25 Oct 07 wjs * * Special diagnostic for -a & -aw switches if they are * * diagnosed as being illegal * * [begin v 1.7b] * * 6 Oct 06 wjs * * Parametrize JDB_CONDITION_EOF * * [Needs core.h v 1.5] * * 2 Sep 06 wjs * * Bug fix: left help in for stuff that had been pulled out * * 19 Jul 06 wjs * * Bug fix: can't have run-time decision about whether to use * * subscripted st_ino (VMS). Must be compile time decision; * * else using variable as both subscripted & un. Suspect * * this problem introduced in 1.5; certainly in 1.6b... and * * it never showed until now. * * [begin v 1.7a] * * 14 Jul 06 wjs * * -a, -aw * * Changed buffer sizes to BUFSIZ per arguments in list.h * * Don't know what motivated the list.h stuff, but seems * * that we changed things there and never implemented them * * here! * * Use ADD/COPY_INTO_FIXED_LEN_BUFFER & add_to_buffer * * instead of strcat/cpy. (Even better, used buildstring * * to get rid of a bunch. Could probably get rid of the * * rest (as well as most of the -r buffer logic if we used * * lengthen_str! Next time...) * * Bug fix: we tested a char beyond end-of-string processing * * -r[st] switch * * [Needs utils.c (library) v 2.1] * * [Needs list.h v 1.4] * * [Needs core.h v 1.4c] * * [begin v 1.7] * * 6 Aug 05 WJS * * Get level_splits from library * * 3 Jun 05 WJS * * Fix typo in declaration of add_id_to_err * * [begin v 1.6d] * * 30 Aug 04 wjs * * jgfuncdefns.h * * 9 Jul 04 wjs * * Add return after error_ to avoid compiler diagnostic * * Apr 23, 2004 v 1.6c Warren Sass * * Bug fix: extra separator was appearing at end-of-line * * under some circumstances * * Bug fix: don't consider repsep at EOL to be a separator * * unless user has asked for -r switch of some flavor * * Apr 16, 2004 v 1.6c Warren Sass * * Don't want "version" in any function name since such * * names appear when grep'ping for "version" * * Mar 25, 2004 v 1.6c Warren Sass * * stat.h now #include'd in core.h, so remove from here * * Feb 27, 2004 v 1.6c Warren Sass * * Comment mod * * Rename local return_version to global list_return_version * * Feb 11, 2004 v 1.6c Warren Sass * * Fixes to remove compiler warnings * * [Needs utils.c v 1.8] * * [begin v 1.6c] * * Feb 4, 2004 v 1.6b Warren Sass * * Get list.h version defn into binary here instead of in * * list.h * * Jan 30, 2004 v 1.6b Warren Sass * * add_id_to_err (common routine to add username, time & * * program version to error messages) * * errn to defgb_utils. * * [Needs defgb_utils.c v 1.7] * * [begin v 1.6b] * * [move earlier comments to list_revision.doc * * Sat Oct 17 1992 10.00 Glenn Flierl * * * ******************************************************************* */ #include "list.h" #include "jdbfuncdefns.h" int valsize = BUFSIZE; int namebufsize = BUFSIZE; char namebuf[NVAR][BUFSIZE], vals[NVAR][BUFSIZE]; int widths[NVAR]; int *firstvaratlevel; char *outline; int unit = -1; int maxlevel,firstpass,num,level; char one_char_buf; /* NB: the lm method reads "plain" (no switches) list output */ /* That includes parsing the separator lines, etc, so that kind */ /* of formatting is fixed (unless we admit nobody uses lm) */ char between_level_separator_line[] = "======================= "; char varlist_delimiter_line[] = "........................ "; char last_lev_varlist_delimiter_line[] = "------------------------ "; /* linecount counts the fprintf calls in writemln */ /* Includes varline_linecount, commentline_linecount and pretty-printing */ /* varline_linecount counts the number of times outflush in writevar is called */ /* presumably 0 if -b; 1 if -f, etc; nlevel if "levelized" */ /* commentline_linecount counts the number of calls to jdbcomments */ /* estdataline_linecount = linecount - varline_linecount */ /* - commentline_linecount - guess_at_pretty-printing */ struct linecount { char *name; int count; Logical do_it; char *destination; char *destination_access; }; struct linecount linecount; struct linecount varline_linecount; struct linecount commentline_linecount; struct linecount estdataline_linecount; /* outcount is screen-related */ int outcount = 0; Logical moreflag = TRUE; Logical fflag = FLAG_UNDEFINED; Logical include_attributes,include_attributes_switch; Logical widths_are_normal_attributes = FALSE; Logical header_flag = TRUE; Logical mflag = FALSE; Logical outputcomments = TRUE; Logical outlinelengthlimitflag = TRUE; Logical rflag = FLAG_UNDEFINED; Logical fillflag = TRUE; Logical help_after_err = TRUE; Logical broken_pipe_is_err = TRUE; Logical err_echo = TRUE; Logical die_on_outerr = TRUE; Logical any_data_from_object = FALSE; Logical forceheader = FALSE; Logical print_help; char osep[2] = {DEFAULT_OSEP , '\0'}; char repsep[2] = {DEFAULT_OSEP , '\0'}; char *err_prefix = ""; char *new_missing_value = DEFAULT_SUBSTITUTE_MISSING_VALUE; char *object_name; int olen; FILE *ofile; char *ofilename; int ofile_status = 0; char *ofile_access = "w"; struct stat ofileinfo; FILE *errfile; char *errfilename = NULL; char *errfile_access = "w"; struct stat efileinfo; Logical add_id_to_err(); /* from utils.c */ void errn(); /* from utils.c */ int *level_splits(); /* from utils.c */ char *buildstring(); /* from utils.c */ char *add_to_buffer(); /* from utils.c */ Logical get_logical_value(); /* from utils.c */ char *getenv(); int putenv(); void reset(); void reset_and_out(); void output_counts(); /* Should NOT be typed for "executable exit status". This is what */ /* we'd LIKE the status to be. Unfortunately, we need to cram it */ /* it into 8 bits most of the time... */ int desired_exit_status; /************************************************************************/ char *list_return_vers() /* Routine exists mostly to force .h file version string into this */ /* module, but we could call it if we want. Note string must not be */ /* global or we'll have conflicts if another routine similarly */ /* includes the version string */ { static char version[] = LIST_VERSION"/"FULL_LISTH_VERSION"/"FULL_JDBFUNCDEFNSH_VERSION; return version; } void error_(s,t) char *s,*t; { Logical print_to_ofile; char *ss = "", *tt = "", *ss_eol = "", *tt_eol= ""; /* exit_status should be typed for "executable exit status". */ /* Failing that, I'm too lazy to fool w/unsigned char and the */ /* various castings I'd have to do. Besides, the exit function */ /* WANTS int and truncates, etc, itself */ int exit_status; /* Take care of null strings and strings w/o newlines. This work */ /* should be redundant, but easier to do it than make sure... */ /* This code also makes it easy to modify into a message format */ /* of "s:t" if one prefers. (Note, however, that if called from */ /* err, s is whole error message and t is time/program ID info) */ if (s != NULL) { ss = s; if (ss[strlen(ss)-1] != '\n') ss_eol = "\n"; } if (t != NULL) { tt = t; if (tt[strlen(tt)-1] != '\n') tt_eol = "\n"; } /* errfile will be NULL if attempt to open it failed... */ if (errfile != NULL) fprintf (errfile,"%s%s%s%s%s",err_prefix,ss,ss_eol,tt,tt_eol); /* Also write message to ofile if different from efile (unless */ /* user asked us not to). Most of the code deals with abnormal */ /* circumstances. If either but not both are abnormal, then they */ /* differ. If both are abnormal, hey, try it - what do we have to */ /* lose? We're beyond trying to diagnose the situation! */ if ( err_echo && (ofile != NULL) ) { /* Any reason to print means we can stop testing. We don't just */ /* OR the various things because we don't want to redo things we */ /* know in advance are NG (eg, fstat if file descriptor NULL) */ print_to_ofile = (errfile == NULL); /* Different since ofile !=NULL */ /* fstat returns 0 on success. Failure means files are */ /* different; means we want to print */ if (! print_to_ofile) print_to_ofile = (fstat(fileno(errfile),&efileinfo) != 0); if (! print_to_ofile) { if (fstat(fileno(ofile),&ofileinfo) == 0) { /* The real test. Files same if major/minor device & inode */ /* are the same - print if not true */ print_to_ofile = #if VMS ! ( (efileinfo.st_ino[0] == ofileinfo.st_ino[0]) && (efileinfo.st_ino[1] == ofileinfo.st_ino[1]) && (efileinfo.st_ino[2] == ofileinfo.st_ino[2]) && (efileinfo.st_dev == ofileinfo.st_dev) ); #else ! ( (efileinfo.st_ino == ofileinfo.st_ino) && (efileinfo.st_dev == ofileinfo.st_dev) ); #endif } else { /* Who knows? Give the write a shot... */ print_to_ofile = TRUE; } } if (print_to_ofile) fprintf (ofile,"%s%s%s%s%s", err_prefix,ss,ss_eol,tt,tt_eol); } /* Assume negative exit statuses come from jdb and "start" from */ /* -999. Make -999 = 255; -998 = 254; etc. After that mod, if */ /* the thing doesn't fit into 8 bits, we drop the most signifi- */ /* cant bits. VMS is more liberal, but we still don't have the */ /* full 32 bits for a code & not worth trying to duplicate this */ /* work for the 21 (or whatever) bits we have. How many VMS */ /* users of this are there, anyway? */ exit_status = (desired_exit_status < 0) ? 255 - (999 + desired_exit_status) : desired_exit_status; exit(exit_status); } void err(s,t) char *s,*t; { char *new_s,*new_t; add_id_to_err(&new_s,&new_t,s,t,LIST_VERSION); error_(new_s,new_t); return; /* Not that it should ever get here... */ } void printhelp(stat) int stat; /* Should be typed for "executable exit status" */ { if ( ! print_help) exit(stat); printf ("Usage: list [-n] [-s|-t] [-z] [-c] [-l] [-f|-b|-r|-rs|-rt]\n"); printf (" "); if (include_attributes_switch) printf ("[-a] "); printf ("[-aw] [-h] [?] [-v]\n"); printf (" [-nohelp] [-errprefix [string]]\n"); printf (" [-linecount count_destination_file[+]] [-X_linecount count_destination_file[+]]\n"); printf (" [-noerrecho] [-nopipeerr] [-finishinp]\n"); printf (" [-errout errfile[+]] [-m [new_missing]]\n"); printf (" [-forceheader]\n"); printf (" object [outfile[+]]\n"); printf("Options: \n"); printf(" -n nonstop\n"); printf(" -s space-separated -t tab-separated\n"); printf(" -z delete extra spaces\n"); printf(" -c no comments\n"); printf(" -l no limit on output line length\n"); printf(" -f flat file output -b brief flat file (no header info)\n"); printf(" -r reps-on-one-line output\n"); printf(" -rs -r w/reps space-separated -rt -r w/reps tab-separated\n"); if (include_attributes_switch) printf(" -a print attribute list after variable name\n"); printf(" -aw print width attribute if other attributes are being printed\n"); printf(" -h prints this message\n"); printf(" ? prints this message\n"); printf(" -v prints version information\n"); printf(" -m missing value converted to new_missing (default: %s) \n", DEFAULT_SUBSTITUTE_MISSING_VALUE); printf("\n"); printf ("-nohelp do not print help after list syntax errors\n"); printf ("-errprefix prefix list error messages w/string (default: %s)\n", DEFAULT_ERR_PREFIX); printf ("-X_linecount output various counts to count_destination_file\n"); printf (" X can be varline, commentline, or estdataline\n"); printf (" commentline_linecount counts the number of comment lines\n"); printf (" varline_linecount counts the number of lines with varlist information\n"); printf (" linecount counts \"all\" lines\n"); printf (" estdataline_linecount is linecount - varline_linecount - commentline_linecount\n"); printf (" - \"pretty-print\" lines. It is an estimate of the number of data lines\n"); printf (" With regard to file overwrite/append, lines are printed in the order above\n"); printf ("-noerrecho do not echo err messages to outfile if errfile is different\n"); printf ("-nopipeerr do not produce err message if output ends w/ \"broken pipe\"\n"); printf ("-finishinp read input until end-of-data even if output errors\n"); printf ("-errout send err messages to errfile instead of /dev/stdout after \ command line parsing\n"); printf ("-forceheader produce variable list even if there is no data from object\n"); printf (" (unless listing is in -b format)\n"); printf ("\noutfile may not begin with a -\n"); printf("\n%s\n",LIST_VERSION); exit(stat); } void badswitch(problem,badswitch) char *problem,*badswitch; { char *s; /* problem is a string but we only look at first char. Please? Tnx */ switch (*problem) { case 'I': s = "Illegal"; break; case 'C': s = "Conflicting/duplicate"; break; default: s = "Problem"; break; } printf ("%s%s switch %s\n",err_prefix,s,badswitch); /* Special diagnostic for -a */ if ( (*(++badswitch) == 'a') && (*(++badswitch) == '\0') ) printf ("%s(Check compilation options with which list was built)\n", err_prefix); printhelp(ERROR_EXIT); return; } void get_args(argc,argv) int argc; char *argv[]; { int i,len; char *s; int nprescan; struct linecount *struct_ptr; #define NPRESCANSWITCHES 2 /* Prescan for switches related to the formatting of diagnostics, */ /* so that if we detect errs here, we do what user wants w/regard */ /* the output. Haven't tried to do anything if these switches */ /* themselves are specified badly, multiple times, etc. Present */ /* thought is that there's nothing to be done */ nprescan = 0; for (i = 1; i < argc; i++) { if (strcmp("-nohelp",argv[i]) == 0) { help_after_err = FALSE; nprescan++; } else if (strcmp("-errprefix",argv[i]) == 0) { err_prefix = DEFAULT_ERR_PREFIX; /* See -m code (from which this came) for discussion of */ /* problems w/ */ /* -switch [value] */ /* syntax in general, as well as the next 2 if statements */ if (argv[i+1] == NULL) break; if (argv[i+2] == NULL) break; if (*argv[i+1] != '-') err_prefix = argv[++i]; nprescan++; } if (nprescan == NPRESCANSWITCHES) break; } print_help = help_after_err; /* Handle args. Switches must come before obj spec & opt outfile */ /* Note that we cannot recognize the following error at parse time */ /* list -errout object outfile */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; struct_ptr = NULL; if (strcmp(argv[i],"-linecount") == 0) { struct_ptr = &linecount; } else if (strcmp(argv[i],"-varline_linecount") == 0) { struct_ptr = &varline_linecount; } else if (strcmp(argv[i],"-commentline_linecount") == 0) { struct_ptr = &commentline_linecount; } else if (strcmp(argv[i],"-estdataline_linecount") == 0) { struct_ptr = &estdataline_linecount; } if (struct_ptr != NULL) { if (++i >= argc) { printf("%sMissing linecount destination after %s switch\n",err_prefix,argv[i-1]); printhelp(ERROR_EXIT); } len = strlen(argv[i]); if (len == 0) { printf ("%scount_destination for %s empty",err_prefix,struct_ptr->name); printhelp (ERROR_EXIT); } struct_ptr->destination = argv[i]; if (struct_ptr->destination[len-1] == '+') { if (len == 1) { printf ("%scount_destination for %s cannot be just a \'+\'\n",err_prefix,struct_ptr->name); printhelp(ERROR_EXIT); } struct_ptr->destination_access = "a"; struct_ptr->destination[len-1] = '\0'; } else { struct_ptr->destination_access = "w"; } struct_ptr->do_it = TRUE; continue; } switch (argv[i][1]) { case 'a': if (argv[i][2] == '\0') { if (include_attributes_switch) include_attributes = TRUE; else badswitch("Illegal",argv[i]); } else { if (argv[i][3] != '\0') badswitch("Illegal",argv[i]); if (argv[i][2] == 'w') widths_are_normal_attributes = TRUE; else badswitch("Illegal",argv[i]); } break; case 'b': if ( ! ((fflag == FLAG_UNDEFINED) && (rflag == FLAG_UNDEFINED)) ) badswitch("Conflict",argv[i]); fflag = TRUE; header_flag = FALSE; outputcomments = FALSE; break; case 'c': outputcomments = FALSE; break; case 'e': if (strcmp("-errout",argv[i]) == 0) { if (++i >= argc) { printf("%sMissing errfile after -errout switch\n",err_prefix); printhelp(ERROR_EXIT); } errfilename = argv[i]; len = strlen(errfilename); if (errfilename[len-1] == '+') { if (len == 1) { printf ("%serrfile cannot be just a \'+\'\n",err_prefix); printhelp(ERROR_EXIT); } errfile_access = "a"; errfilename[len-1] = '\0'; } } else if (strcmp("-errprefix",argv[i]) == 0) { /* Processing of the first occurrence of this switch */ /* took place up top ... and will control formatting of */ /* the following error message. Hope 1st one was right */ if (*err_prefix != '\0') { if (argv[i+1] == NULL) { if (err_prefix != DEFAULT_ERR_PREFIX) badswitch("Duplicate",argv[i]); break; } if (argv[i+2] == NULL) { if (err_prefix != DEFAULT_ERR_PREFIX) badswitch("Duplicate",argv[i]); break; } if (*argv[i+1] != '-') { if (strcmp(err_prefix,argv[i+1]) != 0 ) badswitch("Duplicate",argv[i]); i++; break; } } } else { badswitch("Illegal",argv[i]); } break; case 'f': if (argv[i][2] == '\0') { if ( ! ((fflag == FLAG_UNDEFINED) && (rflag == FLAG_UNDEFINED)) ) badswitch("Conflict",argv[i]); fflag = TRUE; } else if (strcmp("-forceheader",argv[i]) == 0) { forceheader = TRUE; } else if (strcmp("-finishinp",argv[i]) == 0) { die_on_outerr = FALSE; } else { badswitch("Illegal",argv[i]); } break; case 'h': print_help = TRUE; printhelp(OK_EXIT); case 'l': outlinelengthlimitflag = FALSE; break; case 'm': /* Cannot distinguish between "-m repl_string object" and */ /* "-m object output_spec" */ mflag = TRUE; /* If next arg not there, we're missing an object specifier, */ /* but let some other code pick that up */ if (argv[i+1] == NULL) break; /* If next arg is last arg, it's probably the object speci- */ /* fier. If not, we'll have error anyway, so let's pretend */ /* it is. Since next arg isn't value for -m, then, leave */ if (argv[i+2] == NULL) break; if (*argv[i+1] != '-') new_missing_value = argv[++i]; else { /* Try to accept a string that's a negative number */ /* Note this fails if there are blanks after the number. */ /* To accept blanks there would mean a forward search to */ /* see if there was anything after the blank, etc. */ strtod(argv[i+1],&s); if (*s == '\0') new_missing_value = argv[++i]; } break; case 'n': if (argv[i][2] == '\0') moreflag = FALSE; else if (strcmp("-nopipeerr",argv[i]) == 0) broken_pipe_is_err = FALSE; else if (strcmp("-noerrecho",argv[i]) == 0) err_echo = FALSE; /* Handled nohelp already. Next line accepts it for syntax */ /* purposes */ else if (strcmp("-nohelp",argv[i]) == 0) ; else badswitch("Illegal",argv[i]); break; case 'r': /* Handle -r[st] switch before -r so that "Illegal" */ /* message appears instead of "Conflict" in case of -rZ */ if (argv[i][2] != '\0') { if (argv[i][3] != '\0') badswitch("Illegal",argv[i]); switch (argv[i][2]) { case 's': repsep[0] = ' '; break; case 't': repsep[0] = '\t'; break; default: badswitch("Illegal",argv[i]); } } if ( ! ((fflag == FLAG_UNDEFINED) && (rflag == FLAG_UNDEFINED)) ) badswitch("Conflict",argv[i]); rflag = TRUE; header_flag = FALSE; break; case 's': if (osep[0] != DEFAULT_OSEP) badswitch("Conflict",argv[i]); osep[0] = ' '; break; case 't': if (osep[0] != DEFAULT_OSEP) badswitch("Conflict",argv[i]); osep[0] = '\t'; break; case 'v': printf("%s\n",LIST_VERSION); exit(OK_EXIT); case 'z': fillflag = FALSE; break; default: badswitch("Illegal",argv[i]); break; } } if (fflag == FLAG_UNDEFINED) fflag = DEFAULT_FFLAG; if (rflag == FLAG_UNDEFINED) rflag = DEFAULT_RFLAG; olen = (fflag || rflag || ! outlinelengthlimitflag) ? DEFAULT_MAXOLEN : SCREEN_COLS - 1; if (i >= argc) { printf ("%sNeed an object specifier argument\n",err_prefix); printhelp(ERROR_EXIT); } object_name = argv[i]; if (++i < argc) { if (*(argv[i]) == '-') { printf ("%sSwitches must precede object specifier argument\n",err_prefix); printhelp(ERROR_EXIT); } ofilename = argv[i]; len = strlen(ofilename); if (ofilename[len-1] == '+') { if (len == 1) { printf ("%soutfile cannot be just a \'+\'\n",err_prefix); printhelp(ERROR_EXIT); } ofile_access = "a"; ofilename[len-1] = '\0'; } } if (++i < argc) { printf ("%sToo many arguments\n",err_prefix); printhelp(ERROR_EXIT); } return; } void writemln(outline) char *outline; { int len,lensep; len = strlen(outline); /* Remove separators at end of line. Presumably if both repsep */ /* and osep are present, repsep came first */ /* seps should be 1 char long, but let's protect ourselves... */ lensep = strlen(osep); if ( strcmp(outline+len-lensep,osep) == 0 ) outline[len-lensep] = '\0'; /* Only remove repsep if it's a separator! */ if (rflag) { lensep = strlen(repsep); if ( strcmp(outline+len-lensep,repsep) == 0 ) outline[len-lensep] = '\0'; } if (fprintf(ofile,"%s\n",outline) < 0) { ofile_status = errno; return; } linecount.count++; if (moreflag) { /* Do "more" emulation */ if ( ++outcount < SCREEN_ROWS - 1) return; printf("--More--"); switch (getchar()) { case SPACE: printf("\n"); outcount = 0; break; case CR: if (PC) printf("\n"); /* Arrange things so that we interrupt after next line of */ /* output. Use -2 instead of -1 to account for the --More-- */ /* we put out */ outcount = SCREEN_ROWS - 2; break; default: printf("\n"); reset(); exit(ERROR_EXIT); } } return; } void outstr(s,sep) char *s,*sep; { int newlen; /* sep should be 1 char long, but let's protect ourselves... */ /* Too bad that while subtly thinking the above, forgot about */ /* trailing \0! ... hence the +1 */ newlen = strlen(outline)+strlen(s)+strlen(sep)+1; if ( newlen > olen ) { if (outlinelengthlimitflag) { writemln (outline); outline[0] = '\0'; } else { /* Get more memory. */ /* No particular reason to use DEFAULT_MAXOLEN as increment */ /* No particular reason to increment in a loop rather than */ /* do the division to find out how many increments we need */ while ((newlen > olen) && (olen <= OLEN_SANITY_LIMIT)) olen += DEFAULT_MAXOLEN; if (olen > OLEN_SANITY_LIMIT) { desired_exit_status = ERROR_EXIT; errn ("Output line size too big. Limit = ",OLEN_SANITY_LIMIT); } outline = (char *)realloc(outline,olen); if (outline == NULL) { olen = newlen; outline = (char *)realloc(outline,olen); } if (outline == NULL) { desired_exit_status = ERROR_EXIT; errn ( "Cannot increase size of output line buffer. Desired size = ",olen); } } } add_to_buffer(outline,olen,s,"adding datum to output buffer"); add_to_buffer(outline,olen,sep,"adding separator to output buffer"); return; } void outflush() { if (outline[0] != '\0') { writemln(outline); outline[0] = '\0'; } return; } void writevar(level) int level; { int i,j; char *ptr; /* +1 for newline, +2 for initial '# ', +1 for trailing blank */ static char msg[COMMENTLINE+4] = {'#',' '}; if (fflag || rflag) { if (firstpass) { if (outputcomments && any_data_from_object) while (jdbcomments_(&unit,msg+2)) { ADD_INTO_FIXED_LEN_BUFFER (msg," ","adding blank to comment buffer (-f/-r)"); writemln(msg); commentline_linecount.count++; } if (header_flag) { for (i=0 ;i%s<--. Must be JGOFS-system logical value (1,0,T,F,etc)", include_attributes_switch_env_var,s); printf("\n%s\n",LIST_VERSION); exit(ERROR_EXIT); } /* Default attrib inclusion behavior is that switch is not */ /* acceptable; ="old way"; = include attribs */ /* Note that the _switch variables only address the issue of */ /* whether the -a switch should be accepted, and do NOT address */ /* whether the switch was specified. */ include_attributes = ! include_attributes_switch; /* No args or single arg '?' get help and exit */ if (argc <= 1) { print_help = TRUE; printhelp(ERROR_EXIT); } if ((argc == 2) && (argv[1][0] == '?') && (argv[1][1] == '\0')) { print_help = TRUE; printhelp(OK_EXIT); } get_args(argc,argv); /* Done w/args. Use standard error reporting from here on, hence */ /* foolery after opening the first file... */ /* Historically, error info was written to stdout, so this */ /* default cannot be changed w/o risk of breaking existing code */ if (errfilename == NULL) errfilename = STDOUT_NAME; /* Don't open standard devices. 2 reasons: first, not sure what */ /* this does if shell has already opened; and second, some systems */ /* don't HAVE a /dev/stdout, etc */ if (strcmp(errfilename,STDOUT_NAME) == 0) errfile = stdout; else if (strcmp(errfilename,STDERR_NAME) == 0) errfile = stderr; else errfile = fopen(errfilename,errfile_access); /* Cannot report error completely yet, so save status (will only */ /* use it if errfile is NULL, so can save bogus errnos) */ i = errno; if (ofilename == NULL) ofilename = STDOUT_NAME; /* See above comments about not opening standard files */ if (strcmp(ofilename,STDOUT_NAME) == 0) ofile = stdout; else if (strcmp(ofilename,STDERR_NAME) == 0) ofile = stderr; else ofile = fopen(ofilename,ofile_access); if (ofile == NULL) { /* Do following even if we have no error file on which to put */ /* the message. Doing so will allow uniform communication of */ /* error code into the exit status (be nice - don't ask so what) */ s = buildstring("Could not open ",ofilename," for write: ", "ofilename open error msg buffer"); /* Don't try to write error message to ofile */ err_echo = FALSE; desired_exit_status = errno; err (s,strerror(errno)); } /* Original list turned off moreflag if user spec'd outfile. */ /* Since we explicitly allow outfile=/dev/stdout=terminal device */ /* we can't do that. Note that a 0 return might mean "could not */ /* perform the test" (due to an I/O problem presumably). Don't */ /* see a problem w/turning off flag in that situation */ if (isatty(fileno(ofile)) == 0) moreflag = FALSE; if (errfile == NULL) { s = buildstring("Could not open ",errfilename," for write: ", "errfilename open error msg buffer"); desired_exit_status = i; err (s,strerror(i)); } /* Copy object spec into temp buffer. Don't know why we need a */ /* copy - maybe jdbopen alters object spec? Main use of outline */ /* is as line output buffer - size for its first use while we're */ /* at it... */ len_buf = strlen(object_name) + 1; if (len_buf < DEFAULT_MAXOLEN) len_buf = DEFAULT_MAXOLEN; outline = (char *)malloc(len_buf); if (outline == NULL) { desired_exit_status = ERROR_EXIT; errn ("Could not allocate buffer outline. Desired size = ",len_buf); } strcpy(outline,object_name); linecount.count = varline_linecount.count = 0; commentline_linecount.count = estdataline_linecount.count = 0; unit = 1; num = -NVAR; maxlevel = jdbopen_(&unit,outline,namebuf,&namebufsize,&num); if (maxlevel < 0) { desired_exit_status = maxlevel; if (desired_exit_status == JDB_CONDITION_DCTSEARCHFAILURE) { strcpy (tmp,"object not found"); } else if (desired_exit_status == JDB_CONDITION_ERROR) { strcpy (tmp,"catch-all error"); } else { sprintf (tmp,"jdb_condition %d-look in core.h for defn",desired_exit_status); } s = buildstring("jdbopen failure (",tmp,") Object: ","jdb failure err msg"); err(s,object_name); } /* do levels */ /* maxlevel+1 because we want # levels, not max */ firstvaratlevel = level_splits(unit,maxlevel,num); if (firstvaratlevel == NULL) { desired_exit_status = ERROR_EXIT; errn ("Could not get memory for levels buffer. Desired # integers = ", maxlevel+2); } /* do attributes & cleanup names */ for (i=0; i= 0 ) { any_data_from_object = TRUE; for (i=firstvaratlevel[level]; i= 0) jdbclose_(&unit); if ( moreflag && (*reset_term_command != '\0') ) system (reset_term_command); return; } void reset_and_out(signal) int signal; { reset(); exit(ERROR_EXIT); } void rightjust(s,fillwidth,maxwidth) char *s; int fillwidth,maxwidth; /* Right justify the string in s to a width of fillwidth, pre-filling */ /* with blanks. Do nothing if s already wider than fillwidth or */ /* if fillwidth > maxwidth (? might use maxwidth instead...) */ /* Not clear what should be done if user says "fill" but no width */ /* spec'd. Duplicate 1.2b behavior of filling to width 7 if */ /* 1) fillsize > 0 but 2) widths[vn]= 0 (fillsize & widths[vn] were */ /* variables in 1.2b source) */ { int i,chars_to_fill; /* Who knows what < 0 would mean? Too lazy to issue error msg */ if (fillwidth <= 0) fillwidth = DEFAULT_FIELD_WIDTH; if (fillwidth > maxwidth) return; chars_to_fill = fillwidth - strlen(s); if (chars_to_fill <= 0) return; /* Right justify. Go backwards to deal w/overlap problem */ for (i = fillwidth-1; i >= chars_to_fill; i--) s[i] = s[i-chars_to_fill]; /* Blank fill at the front */ for (i = 0; i < chars_to_fill; i++) s[i] = ' '; s[fillwidth] = '\0'; return; } void in_getwidth(vn, ptr) /* read the width from the string 'ptr' (an attribute that has been tested prior to coming here for containing the string 'width=') and write it to the widths array element '*vn' */ int *vn; char *ptr; { char *p; int i,len,ierr; i = *vn; p = strchr(ptr,'='); switch (ierr = sscanf(p+1,"%d", &len)) { case EOF: errn("No width after \"width=\" for variable ",i); case 0: err("Illegal width after \"width=\". Bad string=",ptr); case 1: break; default: errn("Unexpected return value from sscanf in in_getwidth. Value=",ierr); } widths[i] = len; return; } void output_count(count) struct linecount *count; { FILE *file; Logical close_it; /* Next is arbitrary. 40 2 lines down is > max len of an int formatted into ASCII */ #define MAX_DEST_LEN 1024 char count_buf[MAX_DEST_LEN+40]; int status; if (count->do_it) { status = sprintf (count_buf,"%s=%d\n",count->name,count->count); /* Harbison & Steele is source for what constitutes an error here. */ /* EOF is negative, so we have redundancy ... but see Harbison & Steele */ if ((status == EOF) || (status < 0)) errn ("sprintf failure encoding count. status=",status); close_it = FALSE; /* See above comments about not opening standard files */ if (strcmp(count->destination,STDOUT_NAME) == 0) { file = stdout; } else if (strcmp(count->destination,STDERR_NAME) == 0) { file = stderr; } else { file = fopen(count->destination,count->destination_access); if (file == NULL) { errn( buildstring("Could not open ",count->destination, " for write/append. errno=","count_open_err_msg"), errno ); } close_it = TRUE; } status = fprintf(file,"%s",count_buf); if ((status == EOF) || (status < 0)) errn ("fprintf failure writing count. status=",status); if (close_it) if (fclose(file) == EOF) errn ("fclose failure after writing count. errno=",errno); } return; } void output_counts() { output_count (&commentline_linecount); output_count (&varline_linecount); output_count (&linecount); estdataline_linecount.count += linecount.count - commentline_linecount.count - varline_linecount.count; output_count (&estdataline_linecount); return; }