Formatting fixes to GhcMonad
[ghc-hetmet.git] / utils / hp2ps / HpFile.c
1 #include "Main.h"
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include "Defines.h"
7 #include "Error.h"
8 #include "HpFile.h"
9 #include "Utilities.h"
10
11 #ifndef atof
12 double atof PROTO((const char *));
13 #endif
14
15 /* own stuff already included */
16
17 #define N_MARKS 50              /* start size of the mark table */
18 #define N_SAMPLES 500           /* start size of the sample table */
19
20 char *theident;
21 char *thestring;
22 int theinteger;
23 floatish thefloatish;
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  */
28
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  */
34
35 static floatish lastsample;                     /* the last sample time */
36
37 static void GetHpLine PROTO((FILE *));          /* forward */
38 static void GetHpTok  PROTO((FILE *));          /* forward */
39
40 static struct entry *GetEntry PROTO((char *));  /* forward */
41
42 static void MakeIdentTable PROTO((void));       /* forward */
43
44 char *jobstring;
45 char *datestring;
46
47 char *sampleunitstring;
48 char *valueunitstring;
49
50 floatish *samplemap;            /* sample intervals     */
51 floatish *markmap;              /* sample marks         */
52
53 /*
54  *      An extremely simple parser. The input is organised into lines of 
55  *      the form
56  *
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 
65  *
66  */
67
68 void
69 GetHpFile(infp)
70   FILE *infp;
71 {
72     nsamples = 0;
73     nmarks   = 0;
74     nidents  = 0;
75
76     ch = ' ';
77     endfile = 0;
78     linenum = 1;
79     lastsample = 0.0;
80
81     GetHpTok(infp);
82
83     while (endfile == 0) {
84         GetHpLine(infp);
85     }
86
87     if (!gotjob) {
88         Error("%s: JOB missing", hpfile);
89     }
90
91     if (!gotdate) {
92         Error("%s: DATE missing", hpfile);
93     }
94
95     if (!gotvalueunit) {
96         Error("%s: VALUE_UNIT missing", hpfile);
97     }
98
99     if (!gotsampleunit) {
100         Error("%s: SAMPLE_UNIT missing", hpfile);
101     }
102
103     if (nsamples == 0) {
104         Error("%s: contains no samples", hpfile);
105     }
106
107
108     MakeIdentTable();
109
110     fclose(hpfp);
111 }
112
113
114 /*
115  *      Read the next line from the input, check the syntax, and perform
116  *      the appropriate action.
117  */
118
119 static void
120 GetHpLine(infp)
121   FILE* infp;
122 {
123     static intish nmarkmax = 0, nsamplemax = 0;
124
125     switch (thetok) {
126     case JOB_TOK:
127         GetHpTok(infp);
128         if (thetok != STRING_TOK) {
129             Error("%s, line %d: string must follow JOB", hpfile, linenum);
130         }
131         jobstring = thestring;
132         gotjob = 1;
133         GetHpTok(infp);
134         break;
135
136     case DATE_TOK:
137         GetHpTok(infp);
138         if (thetok != STRING_TOK) {
139             Error("%s, line %d: string must follow DATE", hpfile, linenum);
140         }
141         datestring = thestring;
142         gotdate = 1;
143         GetHpTok(infp);
144         break;
145
146     case SAMPLE_UNIT_TOK:
147         GetHpTok(infp);
148         if (thetok != STRING_TOK) {
149             Error("%s, line %d: string must follow SAMPLE_UNIT", hpfile, 
150                   linenum);
151         }
152         sampleunitstring = thestring;
153         gotsampleunit = 1;
154         GetHpTok(infp);
155         break;
156
157     case VALUE_UNIT_TOK:
158         GetHpTok(infp);
159         if (thetok != STRING_TOK) {
160             Error("%s, line %d: string must follow VALUE_UNIT", hpfile, 
161                   linenum);
162         }
163         valueunitstring = thestring;
164         gotvalueunit = 1;
165         GetHpTok(infp);
166         break;
167
168     case MARK_TOK:
169         GetHpTok(infp);
170         if (thetok != FLOAT_TOK) {
171             Error("%s, line %d, floating point number must follow MARK",
172                   hpfile, linenum);
173         }
174         if (insample) {
175             Error("%s, line %d, MARK occurs within sample", hpfile, linenum);
176         }
177         if (nmarks >= nmarkmax) {
178             if (!markmap) {
179                 nmarkmax = N_MARKS;
180                 markmap = (floatish*) xmalloc(nmarkmax * sizeof(floatish));
181             } else {
182                 nmarkmax *= 2;
183                 markmap = (floatish*) xrealloc(markmap, nmarkmax * sizeof(floatish));
184             }
185         }
186         markmap[ nmarks++ ] = thefloatish; 
187         GetHpTok(infp);
188         break;
189
190     case BEGIN_SAMPLE_TOK: 
191         insample = 1;
192         GetHpTok(infp); 
193         if (thetok != FLOAT_TOK) {
194             Error("%s, line %d, floating point number must follow BEGIN_SAMPLE",                  hpfile, linenum);
195         }
196         if (thefloatish < lastsample) {
197             Error("%s, line %d, samples out of sequence", hpfile, linenum);
198         } else {
199             lastsample = thefloatish;
200         }
201         if (nsamples >= nsamplemax) {
202             if (!samplemap) {
203                 nsamplemax = N_SAMPLES;
204                 samplemap = (floatish*) xmalloc(nsamplemax * sizeof(floatish));
205             } else {
206                 nsamplemax *= 2;
207                 samplemap = (floatish*) xrealloc(samplemap, 
208                                               nsamplemax * sizeof(floatish));
209             }
210         }
211         samplemap[ nsamples ] = thefloatish;
212         GetHpTok(infp);
213         break;
214
215     case END_SAMPLE_TOK: 
216         insample = 0;
217         GetHpTok(infp); 
218         if (thetok != FLOAT_TOK) {
219             Error("%s, line %d: floating point number must follow END_SAMPLE", 
220                   hpfile, linenum);
221         }
222         nsamples++;
223         GetHpTok(infp);
224         break;
225
226     case IDENTIFIER_TOK:
227         GetHpTok(infp);
228         if (thetok != INTEGER_TOK) {
229             Error("%s, line %d: integer must follow identifier", hpfile, 
230                   linenum);
231         }
232         StoreSample(GetEntry(theident), nsamples, (floatish) theinteger);
233         GetHpTok(infp); 
234         break;
235
236     case EOF_TOK:
237         endfile = 1;
238         break;
239
240     default:
241         Error("%s, line %d: %s unexpected", hpfile, linenum,
242               TokenToString(thetok));
243         break;
244     }
245 }
246
247
248 char *
249 TokenToString(t)
250   token t;
251 {
252    switch (t) {
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";
265
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)";
271     }
272 }
273
274 /*
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".
280  */
281
282 static void
283 GetHpTok(infp)
284   FILE* infp;
285 {
286
287     while (isspace(ch)) {               /* skip whitespace */
288         if (ch == '\n') linenum++;
289         ch = getc(infp);
290     } 
291
292     if (ch == EOF) {
293         thetok = EOF_TOK;
294         return;
295     }
296
297     if (isdigit(ch)) {
298         thetok = GetNumber(infp);
299         return;
300     } else if (ch == '\"') {
301         GetString(infp);
302         thetok = STRING_TOK;
303         return;
304     } else if (IsIdChar(ch)) {
305         ASSERT(! (isdigit(ch)));        /* ch can't be a digit here */
306         GetIdent(infp);
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) {
314             thetok = JOB_TOK;
315         } else if (strcmp(theident, "DATE") == 0) {
316             thetok = DATE_TOK;
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) {
322             thetok = MARK_TOK;
323         } else {
324             thetok = IDENTIFIER_TOK;
325         }
326         return;
327     } else {
328         Error("%s, line %d: strange character (%c)", hpfile, linenum, ch);
329     }
330 }
331
332
333 /*
334  *      Read a sequence of digits and convert the result to an integer
335  *      or floating point value (assigned to the "theinteger" or 
336  *      "thefloatish").
337  */
338
339 static char numberstring[ NUMBER_LENGTH - 1 ];
340
341 token
342 GetNumber(infp)
343   FILE* infp;
344 {
345     int i;
346     int containsdot;
347  
348     ASSERT(isdigit(ch)); /* we must have a digit to start with */
349
350     containsdot = 0;
351
352     for (i = 0; i < NUMBER_LENGTH && (isdigit(ch) || ch == '.'); i++) {
353         numberstring[ i ] = ch;
354         containsdot |= (ch == '.'); 
355         ch = getc(infp);
356     }   
357  
358     ASSERT(i < NUMBER_LENGTH); /* did not overflow */
359
360     numberstring[ i ] = '\0';
361  
362     if (containsdot) {
363         thefloatish = (floatish) atof(numberstring);
364         return FLOAT_TOK;
365     } else {
366         theinteger = atoi(numberstring);
367         return INTEGER_TOK;
368     }
369 }
370
371 /*
372  *      Read a sequence of identifier characters and assign the result 
373  *      to the string "theident".
374  */
375
376 void
377 GetIdent(infp)
378   FILE *infp;
379 {
380     unsigned int i;
381     char idbuffer[5000];
382
383     for (i = 0; i < (sizeof idbuffer)-1 && IsIdChar(ch); i++) {
384         idbuffer[ i ] = ch;
385         ch = getc(infp);
386     }
387     
388     idbuffer[ i ] = '\0';
389
390     if (theident)
391         free(theident);
392
393     theident = copystring(idbuffer);
394 }
395
396
397 /*
398  *      Read a sequence of characters that make up a string and 
399  *      assign the result to "thestring".
400  */
401
402 void
403 GetString(infp)
404   FILE *infp;
405 {
406     unsigned int i;
407     char *stringbuffer;
408     size_t stringbuffersize;
409
410     ASSERT(ch == '\"');
411
412     stringbuffersize = 5000;
413     stringbuffer = xmalloc(stringbuffersize);
414
415     ch = getc(infp);    /* skip the '\"' that begins the string */
416
417     i = 0;
418     while (ch != '\"') {
419         if (ch == EOF) {
420                 Error("%s, line %d: EOF when expecting \"", hpfile, linenum, ch);
421         }
422         else if (i == stringbuffersize - 1) {
423             stringbuffersize = 2 * stringbuffersize;
424             stringbuffer = xrealloc(stringbuffer, stringbuffersize);
425         }
426         stringbuffer[ i++ ] = ch;
427         ch = getc(infp);
428     }
429
430     stringbuffer[i] = '\0'; 
431     thestring = copystring(stringbuffer);
432
433     ASSERT(ch == '\"');
434
435     ch = getc(infp);      /* skip the '\"' that terminates the string */
436 }
437
438 boolish
439 IsIdChar(ch)
440   int ch;
441 {
442     return (!isspace(ch));
443 }
444
445
446 /*
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.
450  */
451
452 #define N_HASH          513 
453
454 static struct entry* hashtable[ N_HASH ];
455
456 static intish
457 Hash(s)
458   char *s;
459 {
460     int r;
461  
462     for (r = 0; *s; s++) {
463         r = r + r + r + *s;
464     }
465
466     if (r < 0) r = -r;
467
468     return r % N_HASH;
469 }
470
471 /*
472  *      Get space for a new chunk. Initialise it, and return a pointer 
473  *      to the new chunk.
474  */
475  
476 static struct chunk*
477 MakeChunk()
478 {
479     struct chunk* ch;
480     struct datapoint* d;
481
482     ch = (struct chunk*) xmalloc( sizeof(struct chunk) );
483  
484     d = (struct datapoint*) xmalloc (sizeof(struct datapoint) * N_CHUNK);
485
486     ch->nd = 0; 
487     ch->d = d;
488     ch->next = 0;
489     return ch;
490 }
491
492
493 /*
494  *      Get space for a new entry. Initialise it, and return a pointer 
495  *      to the new entry.
496  */
497  
498 struct entry *
499 MakeEntry(name)
500   char *name;
501 {
502     struct entry* e;
503
504     e = (struct entry *) xmalloc(sizeof(struct entry));
505     e->chk = MakeChunk();
506     e->name = copystring(name); 
507     return e;
508 }
509
510 /*
511  *      Get the entry associated with "name", creating a new entry if 
512  *      necessary.
513  */
514
515 static struct entry *
516 GetEntry(name)
517   char* name;
518 {
519     intish h;
520     struct entry* e;
521  
522     h = Hash(name);
523  
524     for (e = hashtable[ h ]; e; e = e->next) {
525         if (strcmp(e->name, name) == 0) {
526             break;
527         }
528     }
529  
530     if (e) {
531         return (e); 
532     } else {
533         nidents++;
534         e = MakeEntry(name);
535         e->next = hashtable[ h ];
536         hashtable[ h ] = e;
537         return (e);
538     }
539 }
540
541
542 /*
543  *      Store information from a sample. 
544  */
545  
546 void
547 StoreSample(en, bucket, value)
548   struct entry* en; intish bucket; floatish value;
549 {
550     struct chunk* chk; 
551
552     for (chk = en->chk; chk->next != 0; chk = chk->next)
553         ; 
554
555     if (chk->nd < N_CHUNK) {
556         chk->d[ chk->nd ].bucket = bucket;
557         chk->d[ chk->nd ].value  = value;
558         chk->nd += 1;
559     } else {
560         struct chunk* t;
561         t = chk->next = MakeChunk(); 
562         t->d[ 0 ].bucket = bucket;
563         t->d[ 0 ].value  = value;
564         t->nd += 1;
565     }
566 }
567
568
569 struct entry** identtable;
570
571 /*
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.
575  */
576
577 static void
578 MakeIdentTable()
579 {
580     intish i;
581     intish j;
582     struct entry* e;
583
584     nidents = 0;
585     for (i = 0; i < N_HASH; i++) {
586         for (e = hashtable[ i ]; e; e = e->next) {
587             nidents++;
588         }
589     }
590
591     identtable = (struct entry**) xmalloc(nidents * sizeof(struct entry*));
592     j = 0;
593
594     for (i = 0; i < N_HASH; i++) {
595         for (e = hashtable[ i ]; e; e = e->next, j++) {
596             identtable[ j ] = e; 
597         }
598     }
599 }