/* ******************************************************************* * * * Copyright (c) L-DGO/MIT/JGOFS * * * * * * File : list.c * * * * Revision History : * * * * Date Developer * * ---- --------- * */ char id[] = "list version 1.3b 08 Sep 1999"; /* * Sep 09, 1999 v 1.3b Christine Hammond * * get widely used constants from default.h * * add conditional for DATUMSIZE, as value in default.h * * is typically defined as 80, was 120 here previously * * Aug 17, 1999 v 1.3a Warren Sass * * Bug fix: was attempting stty reset even if -n was set * * Change name of nflag to reflect what it asserts * * Aug 14, 1999 v 1.3 Warren Sass * * Misc bug fixes & minor improvements * * Bug fix: prettyprint failed if width > strlen(var) + 10 * * Bug fix: olen should be terminal width for "user viewing"; * * max buf else. When max buf raised, wrong olen changed * * Bug fix: -m would change a variable name that happened to be * * "nd" to -9999.0 * * Bug fix: "more" capability seemed broken on Bob's Solaris * * box. Improved there. Seemed to work on Chris' IRIX box * * before and after. Doesn't work on my VMS box either way * * Rename/resize appropriate constants to their default.h state * * Buffers ended up WAYY bigger. * * Add id string; print it during help * * prettyprint is now really a right justifier - name it that. * * Nobody used its return values - eliminate them * * Don't right justify if not enough room in buffer * * fillsize is no longer that; it's a fill/nofill flag. * * Make a flag variable and a width variable to distinguish * * Make static temp buffer - saves reallocation * * Declare jdb functions * * #include errno; stdlib * * Minimize use of #ifndef; remove #if's from runtime portion * * of code * * Add some error message text; remove redundant maxlevel test * * Reformat some comments relating to revision history * * Reformat some program text * * Unaddressed issues * * 1) Separator in data * * If a user of list chooses a separator character that * * appears as part of the data displayed, there may be a * * problem visually, and there will certainly be a problem * * if list's output is going on to another program. * * We could diagnose this condition in list and abort. * * We could couple the diagnosis to the -z flag if we assume * * -z "data consumers" are programs and not people. We could * * make the diagnostic itself switch-controllable. * * 2) Blanks in data * * Leading blank issues are probably moot, since iovalstr_ * * (at least the one in def), which feeds outer, which feeds * * us, removes leading blanks unconditionally. Theoretically * * however, we have an issue in this program * * The column alignment logic will treat the blanks as sig- * * nificant data, hence the output could look funny. However * * maybe it SHOULD look funny because somebody took the trou- * * ble to be sure blanks were data in that particular object * * 3) What should be affected by the -m flag? * * -m affects data that are exactly the 2 characters nd. * * It does not affect, say, nd's embedded in fields whose * * other characters are blanks, or nd's that have been quo- * * ted to invoke outer's NOQUOTELINK capability. * * Similar to blank discussion, question becomes whether * * it's up to list, a data displayer, to make data transform- * * ation decisions. For example, somebody might use n/d to * * represent no data. * * 4) PATH_INFO * * If there's a PATH_INFO in the environment when list * * runs, it will foul things up if the object listed is * * local. Effects include "object not found" errors and SEGV * * dumps * * This is an old issue w/ anything that uses the jdb * * routines. In general, "system" has issued "unsetenv * * PATH_INFO" commands. However, this has gradually caused * * down-the-line problems w/objects that themselves create * * other processes to get the data. * * We could "unsetenv" here. Most elegant soln is to use * * path info routines to modify PATH_INFO minimally (clear * * the "protocol" (.html, .flat) field, then reset it after * * jdb use (paranoid, but mindlessly safe). If we like this * * idea, then I think we could default list's input (eg, no * * object on command line) to "the object spec'd in * * PATH_INFO". The idea is to arrive at an OO server * * environment where the shells need to do minimal parsing of * * PATH_INFO. * * [begin v 1.3] * * * * Aug 11, 1999 v 1.2c Warren Sass * * Essentially the same as 1.3, except I introduced a bug. * * Given to Bob, who put it in his /bin directory. While test- * * ing bug fix, found another bug. Decided to do more code re- * * arrangement, and decided that a renumbering would be in order * * even though no major functionality was added * * [begin v 1.2c] * * * * June 1, 1999 v 1.2b Christine Hammond * * per WJS and CLC - see comment in code re print of msg * * [begin v 1.2b] * * * * Nov 9, 1998 v 1.2a Christine Hammond * * ver 1.2a resolves diffs between ver 1.2 and 1.1a * * developed independently from same code * * [begin v 1.2a] * * * * Aug 29, 1995 12.00 Christine Hammond * * ver 1.2 attribute for width determines width of field * * option '-m' converts missing value from 'nd' to -9999.0 * * [begin v 1.2] * * * * Oct. 8, 1996 v 1.1a Warren Sass * * Change number of char per flatfile output line before new line * * is inserted from 255 to 511 * * [begin v 1.1a] * * * * Sat Oct 17 1992 10.00 Glenn Flierl * * * ******************************************************************* */ #ifndef PC #define PC 0 #endif #ifndef VMS #define VMS 0 #endif #include #include #include #include #if ! PC #include #endif /* Function re-definitions */ #if HP || IBM #define jdbopen_ jdbopen #define jdbreada_ jdbreada #define jdbread_ jdbread #define jdbclose_ jdbclose #define jdbcomments_ jdbcomments #define jdblevel_ jdblevel #define jdbattributes_ jdbattributes #elif PC #define getchar getch #endif /* Sizes are defgb's; = default.h except for datumsize, up from 80 */ /* compile-time definition of OPTIONS will point to default.h */ #include OPTIONS #define NVALS 250 #ifdef DATUMSIZE < 120 #undef DATUMSIZE #define DATUMSIZE 120 #endif #if PC #define CR '\r' #else #define CR '\n' #endif #define SPACE ' ' #define MISSING_VAL_STRING "nd" #define MISSING_VAL_NUMERIC "-9999.0" #define DEFAULT_FIELD_WIDTH 7 #define SCREEN_COLS 80 #define SCREEN_ROWS 24 #define OUTLINEBUF 4096 #if SUN || ULTRIX char *setup_term_command = "/bin/stty cbreak"; char *reset_term_command = "/bin/stty -cbreak"; #elif IRIX || IBM || OSF || SOL || HP char *setup_term_command = "/bin/stty -icanon min 1 time 0"; char *reset_term_command = "/bin/stty icanon"; #elif VMS char *setup_term_command = "SET TERM/PASTHRU"; char *reset_term_command = "SET TERM/NOPASTHRU"; #else char *setup_term_command = ""; char *reset_term_command = ""; #endif /* Buffer sizing considerations. */ /* 1) Although the name and value buffers are logically different */ /* sizes, we use them to hold right-justified fields, and we */ /* right justify both to the same size. Accordingly the */ /* buffers need to be the same size (or the application needs */ /* to be recoded from "right justify all, output all" logic */ /* to "right justify 1, output 1" logic which would permit 1 */ /* buffer, reused for every right-justified field) */ /* 2) We append the attribute string to the name in the name */ /* buffer before right justifying, so the buffer needs to be */ /* big enough for that */ /* 3) There is no logical connection between the output field */ /* width to which we are right justifying, and the data field */ /* width. For example, somebody could request that data */ /* fields that never exceed 10 bytes in size should always be */ /* displayed in 20 character fields. We don't know the widths */ /* until we call jdbopen, but we must supply jdbopen with a */ /* buffer. We should provide a temporary buffer big enough */ /* to hold the jdbopen data, find the widths, then dynamically */ /* allocate buffers of the correct size and copy the temp */ /* buffer into that. We don't do this. Aside from eating my */ /* hat if the max requested width exceeds this buffer size, we */ /* fail safe by leaving that column left justified */ /* 4) Each buffer needs to be at least DEFAULT_FIELD_WIDTH in */ /* size. They are. */ /* 5) The value buffer needs to be big enough to hold */ /* MISSING_VAL_NUMERIC. It is */ #define MAXVALBUFSIZE DATUMSIZE + 1 /* + 2 in next line is for the []s we add to bracket the attrib list */ #define MAXNAMEBUFSIZE VARNAMESIZE + TOTATTRSIZE + 2 + 1 #if MAXVALBUFSIZE > MAXNAMEBUFSIZE #define BUFSIZE MAXVALBUFSIZE #else #define BUFSIZE MAXNAMEBUFSIZE #endif int valsize = BUFSIZE; int namebufsize = BUFSIZE; char namebuf[NVALS][BUFSIZE], vals[NVALS][BUFSIZE]; int levels[NVALS], widths[NVALS]; char outline[OUTLINEBUF]; int unit,maxlevel,firstpass,num,level; char one_char_buf; int outcount = 0; int moreflag = 1; int fflag = 0; int mflag = 0; int hflag = 1; int cflag = 1; int fillflag = 1; int olen = SCREEN_COLS - 1; char osep[] = ","; FILE *ofile; int jdbopen_(); int jdbreada_(); int jdbread_(); void jdbclose_(); int jdbcomments_(); int jdblevel_(); int jdbattributes_(); void rst_term(); /************************************************************************/ void writemln(outline) char *outline; { int len; len = strlen(outline); if (outline[len-1] == osep[0]) outline[len-1] = '\0'; fprintf(ofile,"%s\n",outline); if ( ! moreflag) return; /* 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"); jdbclose_(&unit); system("/bin/stty opost"); if (*reset_term_command != '\0') system (reset_term_command); exit(1); break; } return; } void outstr(s) char *s; { if ( strlen(outline)+strlen(s) > olen ) { writemln (outline); outline[0] = '\0'; } strcat(outline,s); strcat(outline,osep); return; } void outflush() { if (outline[0] != '\0') { writemln(outline); outline[0] = '\0'; } return; } void writevar(level) int level; { int i,j; static char tmp[OUTLINEBUF],msg[COMMENTLINE+1]; if (fflag) { if (firstpass) { if (cflag) while (jdbcomments_(&unit,msg)) { strcpy(tmp,"# "); strcat(tmp,msg); strcat(tmp," "); writemln(tmp); } if (hflag) { for (i=0 ;i= argc) { printf ("Usage: %s [-n] [-s] [-t] [-f] [-b] [-m] [-c] [-z] object [outfile]\n", argv[0]); printf("Options: \n -n nonstop\n -s space-separated\n"); printf(" -t tab-separated\n -f flat file output\n"); printf(" -b brief flat file (no header info)\n"); printf(" -m missing value converted to -9999.0\n"); printf(" -c no comments\n"); printf(" -z delete extra spaces\n"); printf("%s\n",id); exit(1); } ofile = stdout; while (argv[i][0] == '-') { switch (argv[i++][1]) { case 'f': fflag = 1; olen = OUTLINEBUF; break; case 'm': mflag=1; break; case 'n': moreflag=0; break; case 's': osep[0]=' '; break; case 't': osep[0]='\t'; break; case 'b': fflag = 1; hflag = 0; cflag = 0; olen = OUTLINEBUF; break; case 'c': cflag=0; break; case 'z': fillflag=0; break; } } strcpy(outline,argv[i]); if (++i < argc) { if ( (ofile = fopen(argv[i],"w")) == NULL ) { printf ("Could not open %s for write: %s\n%s\n", argv[i],strerror(errno),id); exit(1); } moreflag = 0; } unit = 1; num = -NVALS; maxlevel = jdbopen_(&unit,outline,namebuf,&namebufsize,&num); if (maxlevel < 0) { printf("jdbopen failure (Object %s not found?)\n%s\n",outline,id); exit(1); } /* do levels, attributes & cleanup names*/ for (i=0; i= 0 ) { for (i=0; i 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; i = *vn; p = strchr(ptr,'='); sscanf(p+1,"%d", &len); widths[i] = len; return; }