12 double atof PROTO((const char *));
15 /* own stuff already included */
17 #define N_MARKS 50 /* start size of the mark table */
18 #define N_SAMPLES 500 /* start size of the sample table */
24 int ch; /* last character read */
25 token thetok; /* last token */
26 int linenum; /* current line number */
27 int endfile; /* true at end of file */
29 static boolish gotjob = 0; /* "JOB" read */
30 static boolish gotdate = 0; /* "DATE" read */
31 static boolish gotvalueunit = 0; /* "VALUE_UNIT" read */
32 static boolish gotsampleunit = 0; /* "SAMPLE_UNIT" read */
33 static boolish insample = 0; /* true when in sample */
35 static floatish lastsample; /* the last sample time */
37 static void GetHpLine PROTO((FILE *)); /* forward */
38 static void GetHpTok PROTO((FILE *)); /* forward */
40 static struct entry *GetEntry PROTO((char *)); /* forward */
42 static void MakeIdentTable PROTO((void)); /* forward */
47 char *sampleunitstring;
48 char *valueunitstring;
50 floatish *samplemap; /* sample intervals */
51 floatish *markmap; /* sample marks */
54 * An extremely simple parser. The input is organised into lines of
57 * JOB s -- job identifier string
58 * DATE s -- date string
59 * SAMPLE_UNIT s -- sample unit eg "seconds"
60 * VALUE_UNIT s -- value unit eg "bytes"
61 * MARK i -- sample mark
62 * BEGIN_SAMPLE i -- start of ith sample
63 * identifier i -- there are i identifiers in this sample
64 * END_SAMPLE i -- end of ith sample
83 while (endfile == 0) {
88 Error("%s: JOB missing", hpfile);
92 Error("%s: DATE missing", hpfile);
96 Error("%s: VALUE_UNIT missing", hpfile);
100 Error("%s: SAMPLE_UNIT missing", hpfile);
104 Error("%s: contains no samples", hpfile);
115 * Read the next line from the input, check the syntax, and perform
116 * the appropriate action.
123 static intish nmarkmax = 0, nsamplemax = 0;
128 if (thetok != STRING_TOK) {
129 Error("%s, line %d: string must follow JOB", hpfile, linenum);
131 jobstring = thestring;
138 if (thetok != STRING_TOK) {
139 Error("%s, line %d: string must follow DATE", hpfile, linenum);
141 datestring = thestring;
146 case SAMPLE_UNIT_TOK:
148 if (thetok != STRING_TOK) {
149 Error("%s, line %d: string must follow SAMPLE_UNIT", hpfile,
152 sampleunitstring = thestring;
159 if (thetok != STRING_TOK) {
160 Error("%s, line %d: string must follow VALUE_UNIT", hpfile,
163 valueunitstring = thestring;
170 if (thetok != FLOAT_TOK) {
171 Error("%s, line %d, floating point number must follow MARK",
175 Error("%s, line %d, MARK occurs within sample", hpfile, linenum);
177 if (nmarks >= nmarkmax) {
180 markmap = (floatish*) xmalloc(nmarkmax * sizeof(floatish));
183 markmap = (floatish*) xrealloc(markmap, nmarkmax * sizeof(floatish));
186 markmap[ nmarks++ ] = thefloatish;
190 case BEGIN_SAMPLE_TOK:
193 if (thetok != FLOAT_TOK) {
194 Error("%s, line %d, floating point number must follow BEGIN_SAMPLE", hpfile, linenum);
196 if (thefloatish < lastsample) {
197 Error("%s, line %d, samples out of sequence", hpfile, linenum);
199 lastsample = thefloatish;
201 if (nsamples >= nsamplemax) {
203 nsamplemax = N_SAMPLES;
204 samplemap = (floatish*) xmalloc(nsamplemax * sizeof(floatish));
207 samplemap = (floatish*) xrealloc(samplemap,
208 nsamplemax * sizeof(floatish));
211 samplemap[ nsamples ] = thefloatish;
218 if (thetok != FLOAT_TOK) {
219 Error("%s, line %d: floating point number must follow END_SAMPLE",
228 if (thetok != INTEGER_TOK) {
229 Error("%s, line %d: integer must follow identifier", hpfile,
232 StoreSample(GetEntry(theident), nsamples, (floatish) theinteger);
241 Error("%s, line %d: %s unexpected", hpfile, linenum,
242 TokenToString(thetok));
253 case EOF_TOK: return "EOF";
254 case INTEGER_TOK: return "integer";
255 case FLOAT_TOK: return "floating point number";
256 case IDENTIFIER_TOK: return "identifier";
257 case STRING_TOK: return "string";
258 case BEGIN_SAMPLE_TOK: return "BEGIN_SAMPLE";
259 case END_SAMPLE_TOK: return "END_SAMPLE";
260 case JOB_TOK: return "JOB";
261 case DATE_TOK: return "DATE";
262 case SAMPLE_UNIT_TOK: return "SAMPLE_UNIT";
263 case VALUE_UNIT_TOK: return "VALUE_UNIT";
264 case MARK_TOK: return "MARK";
266 case X_RANGE_TOK: return "X_RANGE";
267 case Y_RANGE_TOK: return "Y_RANGE";
268 case ORDER_TOK: return "ORDER";
269 case SHADE_TOK: return "SHADE";
270 default: return "(strange token)";
275 * Read the next token from the input and assign its value
276 * to the global variable "thetok". In the case of numbers,
277 * the corresponding value is also assigned to "theinteger"
278 * or "thefloatish" as appropriate; in the case of identifiers
279 * it is assigned to "theident".
287 while (isspace(ch)) { /* skip whitespace */
288 if (ch == '\n') linenum++;
298 thetok = GetNumber(infp);
300 } else if (ch == '\"') {
304 } else if (IsIdChar(ch)) {
305 ASSERT(! (isdigit(ch))); /* ch can't be a digit here */
307 if (!isupper((int)theident[0])) {
308 thetok = IDENTIFIER_TOK;
309 } else if (strcmp(theident, "BEGIN_SAMPLE") == 0) {
310 thetok = BEGIN_SAMPLE_TOK;
311 } else if (strcmp(theident, "END_SAMPLE") == 0) {
312 thetok = END_SAMPLE_TOK;
313 } else if (strcmp(theident, "JOB") == 0) {
315 } else if (strcmp(theident, "DATE") == 0) {
317 } else if (strcmp(theident, "SAMPLE_UNIT") == 0) {
318 thetok = SAMPLE_UNIT_TOK;
319 } else if (strcmp(theident, "VALUE_UNIT") == 0) {
320 thetok = VALUE_UNIT_TOK;
321 } else if (strcmp(theident, "MARK") == 0) {
324 thetok = IDENTIFIER_TOK;
328 Error("%s, line %d: strange character (%c)", hpfile, linenum, ch);
334 * Read a sequence of digits and convert the result to an integer
335 * or floating point value (assigned to the "theinteger" or
339 static char numberstring[ NUMBER_LENGTH - 1 ];
348 ASSERT(isdigit(ch)); /* we must have a digit to start with */
352 for (i = 0; i < NUMBER_LENGTH && (isdigit(ch) || ch == '.'); i++) {
353 numberstring[ i ] = ch;
354 containsdot |= (ch == '.');
358 ASSERT(i < NUMBER_LENGTH); /* did not overflow */
360 numberstring[ i ] = '\0';
363 thefloatish = (floatish) atof(numberstring);
366 theinteger = atoi(numberstring);
372 * Read a sequence of identifier characters and assign the result
373 * to the string "theident".
383 for (i = 0; i < (sizeof idbuffer)-1 && IsIdChar(ch); i++) {
388 idbuffer[ i ] = '\0';
393 theident = copystring(idbuffer);
398 * Read a sequence of characters that make up a string and
399 * assign the result to "thestring".
408 size_t stringbuffersize;
412 stringbuffersize = 5000;
413 stringbuffer = xmalloc(stringbuffersize);
415 ch = getc(infp); /* skip the '\"' that begins the string */
420 Error("%s, line %d: EOF when expecting \"", hpfile, linenum, ch);
422 else if (i == stringbuffersize - 1) {
423 stringbuffersize = 2 * stringbuffersize;
424 stringbuffer = xrealloc(stringbuffer, stringbuffersize);
426 stringbuffer[ i++ ] = ch;
430 stringbuffer[i] = '\0';
431 thestring = copystring(stringbuffer);
435 ch = getc(infp); /* skip the '\"' that terminates the string */
442 return (!isspace(ch));
447 * The information associated with each identifier is stored
448 * in a linked list of chunks. The table below allows the list
449 * of chunks to be retrieved given an identifier name.
454 static struct entry* hashtable[ N_HASH ];
462 for (r = 0; *s; s++) {
472 * Get space for a new chunk. Initialise it, and return a pointer
482 ch = (struct chunk*) xmalloc( sizeof(struct chunk) );
484 d = (struct datapoint*) xmalloc (sizeof(struct datapoint) * N_CHUNK);
494 * Get space for a new entry. Initialise it, and return a pointer
504 e = (struct entry *) xmalloc(sizeof(struct entry));
505 e->chk = MakeChunk();
506 e->name = copystring(name);
511 * Get the entry associated with "name", creating a new entry if
515 static struct entry *
524 for (e = hashtable[ h ]; e; e = e->next) {
525 if (strcmp(e->name, name) == 0) {
535 e->next = hashtable[ h ];
543 * Store information from a sample.
547 StoreSample(en, bucket, value)
548 struct entry* en; intish bucket; floatish value;
552 for (chk = en->chk; chk->next != 0; chk = chk->next)
555 if (chk->nd < N_CHUNK) {
556 chk->d[ chk->nd ].bucket = bucket;
557 chk->d[ chk->nd ].value = value;
561 t = chk->next = MakeChunk();
562 t->d[ 0 ].bucket = bucket;
563 t->d[ 0 ].value = value;
569 struct entry** identtable;
572 * The hash table is useful while reading the input, but it
573 * becomes a liability thereafter. The code below converts
574 * it to a more easily processed table.
585 for (i = 0; i < N_HASH; i++) {
586 for (e = hashtable[ i ]; e; e = e->next) {
591 identtable = (struct entry**) xmalloc(nidents * sizeof(struct entry*));
594 for (i = 0; i < N_HASH; i++) {
595 for (e = hashtable[ i ]; e; e = e->next, j++) {