MIDAS
Loading...
Searching...
No Matches
mhdump.cxx
Go to the documentation of this file.
1//
2// mhdump: midas history explorer
3//
4// Author: Konstantin Olchanski, 20-NOV-2007
5//
6// Compile:
7// g++ -o mhdump.o -c mhdump.cxx -O2 -g -Wall -Wuninitialized
8// g++ -o mhdump -g -O2 mhdump.o
9//
10// $Id$
11//
12
13#undef NDEBUG // midas required assert() to be always enabled
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <stdint.h>
18#include <string.h>
19#include <assert.h>
20#include <errno.h>
21
22#include <string>
23#include <map>
24#include <vector>
25#include <ctime>
26
28// Definitions extracted from midas.h //
30
31#define DWORD uint32_t
32
33#define NAME_LENGTH 32
35typedef struct {
36 DWORD record_type; /* RT_DATA or RT_DEF */
38 DWORD time;
39 DWORD def_offset; /* place of definition */
40 DWORD data_size; /* data following this header in bytes */
42
43typedef struct {
44 char name[NAME_LENGTH];
45 DWORD type;
46 DWORD n_data;
47} TAG;
48
50// Definitions extracted from midas.c //
52
53/********************************************************************/
54/* data type sizes */
55int tid_size[] = {
56 0, /* tid == 0 not defined */
57 1, /* TID_BYTE unsigned byte 0 255 */
58 1, /* TID_SBYTE signed byte -128 127 */
59 1, /* TID_CHAR single character 0 255 */
60 2, /* TID_WORD two bytes 0 65535 */
61 2, /* TID_SHORT signed word -32768 32767 */
62 4, /* TID_DWORD four bytes 0 2^32-1 */
63 4, /* TID_INT signed dword -2^31 2^31-1 */
64 4, /* TID_BOOL four bytes bool 0 1 */
65 4, /* TID_FLOAT 4 Byte float format */
66 8, /* TID_DOUBLE 8 Byte float format */
67 1, /* TID_BITFIELD 8 Bits Bitfield 00000000 11111111 */
68 0, /* TID_STRING zero terminated string */
69 0, /* TID_ARRAY variable length array of unkown type */
70 0, /* TID_STRUCT C structure */
71 0, /* TID_KEY key in online database */
72 0, /* TID_LINK link in online database */
73 8, /* TID_INT64 8 bytes int -2^63 2^63-1 */
74 8 /* TID_UINT64 8 bytes unsigned int 0 2^64-1 */
75};
76
77/* data type names */
78const char *tid_name[] = {
79 "NULL",
80 "BYTE",
81 "SBYTE",
82 "CHAR",
83 "UINT16",
84 "INT16",
85 "UINT32",
86 "INT32",
87 "BOOL",
88 "FLOAT",
89 "DOUBLE",
90 "BITFIELD",
91 "STRING",
92 "ARRAY",
93 "STRUCT",
94 "KEY",
95 "LINK",
96 "INT64",
97 "UINT64"
98};
99
101
102struct Tag
103{
105 std::string name;
106 int offset;
110};
111
112struct Event
113{
115 int size;
116 std::map<std::string,Tag*> tags;
117 std::vector<std::string> tagNames;
118 std::vector<int> tagIndexes;
119};
120
121std::map<int,Event*> gTags;
122
123bool doPrintTags = true;
124bool doPrintNames = true;
125bool doPrintData = true;
126bool doAll = false;
127
129{
130 bool doRead = true;
131
132 assert(f!=NULL);
133
134 while (1)
135 {
137
138 if (doRead)
139 {
140 int rd = fread(&rec, sizeof(rec), 1, f);
141 if (!rd)
142 break;
143 }
144
145 doRead = true;
146#if 0
147 printf("HIST_RECORD:\n");
148 printf(" Record type: 0x%x\n", rec.record_type);
149 printf(" Event ID: %d\n", rec.event_id);
150 printf(" Time: %d\n", rec.time);
151 printf(" Offset: 0x%x\n", rec.def_offset);
152 printf(" Size: 0x%x\n", rec.data_size);
153#endif
154
155 switch (rec.record_type)
156 {
157 default:
158 printf("Unexpected record type: 0x%08x, trying to recover by skipping bad data.\n", rec.record_type);
159 while (1)
160 {
161 int c = fgetc(f);
162 //printf("read 0x%02x\n", c);
163 if (c==EOF)
164 return 0;
165 if (c!=0x48)
166 continue;
167
168 c = fgetc(f);
169 if (c==EOF)
170 return 0;
171 if (c!=0x53)
172 continue;
173
174 c = fgetc(f);
175 if (c==EOF)
176 return 0;
177 if (c!=0x44)
178 continue;
179
180 printf("Maybe recovered - see what looks like valid history record header.\n");
181
182 ((char*)(&rec))[0] = 0x48;
183 ((char*)(&rec))[1] = 0x53;
184 ((char*)(&rec))[2] = 0x44;
185
186 int rd = fread(((char*)(&rec))+3, sizeof(rec)-3, 1, f);
187 if (!rd)
188 return 0;
189
190 doRead = false;
191 break;
192 }
193 break;
194
195 case 0x46445348: // RT_DEF:
196 {
197 char event_name[NAME_LENGTH];
198 int rd = fread(event_name, 1, NAME_LENGTH, f);
199 assert(rd == NAME_LENGTH);
200
201 int size = rec.data_size;
202 int ntags = size/sizeof(TAG);
203
204 if (doPrintTags)
205 printf("Event %d, \"%s\", size %d, %d tags.\n", rec.event_id, event_name, size, ntags);
206
207 assert(size > 0);
208 assert(size < 1*1024*1024);
209 assert(size == ntags*(int)sizeof(TAG));
210
211 TAG *tags = new TAG[ntags];
212 rd = fread(tags, 1, size, f);
213 assert(rd == size);
214
215 Event* e = gTags[rec.event_id];
216 if (!e)
217 {
218 gTags[rec.event_id] = new Event;
219 e = gTags[rec.event_id];
220 e->printAllTags = false;
221 if (doAll)
222 e->printAllTags = true;
223 }
224 else
225 {
226 if (e->printAllTags) {
227 e->tagNames.clear();
228 e->tagIndexes.clear();
229 }
230 }
231
232 e->size = 0;
233
234 int offset = 0;
235
236 for (int itag=0; itag<ntags; itag++)
237 {
238 int tsize = tid_size[tags[itag].type];
239
240 if (tsize == 0)
241 tsize = 1;
242
243 int size = tags[itag].n_data * tsize;
244
245 if (tags[itag].type == 12) { // TID_STRING
246 //if (size == 1)
247 //size = 32; // kludge old broken history files
248 fprintf(stderr, "Error: Event %d, \"%s\", has a tag \"%s\" of type TID_STRING, which is forbidden and cannot be decoded, all data after this tag will be gibberish\n", rec.event_id, event_name, tags[itag].name);
249 size = 0;
250 }
251
252 if (offset%tsize != 0)
254
255 assert(offset%tsize == 0);
256
257 Tag* t = new Tag;
258 t->event_id = rec.event_id;
259 t->name = tags[itag].name;
260 t->offset = offset;
261 t->arraySize = tags[itag].n_data;
262 t->typeSize = tid_size[tags[itag].type];
263 t->typeCode = tags[itag].type;
264
265 e->tags[t->name] = t;
266
267 if (e->printAllTags)
268 {
269 e->tagNames.push_back(t->name);
270 e->tagIndexes.push_back(-1);
271 }
272
273 if (doPrintTags)
274 printf(" Tag %d: \"%s\"[%d], type \"%s\" (%d), type size %d, offset %d+%d\n", itag, tags[itag].name, tags[itag].n_data, tid_name[tags[itag].type], tags[itag].type, tid_size[tags[itag].type], offset, size);
275
276 offset += size;
277 }
278
279 e->size = offset;
280
281 //if (doPrintTags)
282 //printf(" Event size %d\n", e->size);
283
284 delete[] tags;
285 break;
286 }
287
288 case 0x41445348: // RT_DATA:
289 {
290 int size = rec.data_size;
291
292 if (0)
293 printf("Data record, size %d.\n", size);
294
295 if (size <= 1 || size > 1*1024*1024)
296 {
297 fprintf(stderr, "Error: Invalid data record: event %d, size %d is invalid\n", rec.event_id, rec.data_size);
298 continue;
299 }
300
301 char *buf = new char[size];
302 int rd = fread(buf, 1, size, f);
303 assert(rd == size);
304
305 time_t t = (time_t)rec.time;
306
307 Event* e = gTags[rec.event_id];
308 if (e && doPrintData)
309 {
310 if (size != e->size)
311 {
312 fprintf(stderr, "Error: event %d, size mismatch should be %d, got %d bytes\n", rec.event_id, e->size, size);
313 }
314
315 //printf("event %d, time %s", rec.event_id, ctime(&t));
316
317 int n = e->tagNames.size();
318
319 if (n>0)
320 printf("%d %d ", rec.event_id, rec.time);
321
322 for (int i=0; i<n; i++)
323 {
324 Tag*t = e->tags[e->tagNames[i]];
325 int index = e->tagIndexes[i];
326
327 //printf(" dump %s[%d] (%p)\n", e->tagNames[i].c_str(), e->tagIndexes[i], t);
328
329 if (t)
330 {
331 int offset = t->offset;
332 void* ptr = (void*)(buf+offset);
333
334 if (doPrintNames)
335 {
336 if (index < 0)
337 printf(" %s=", t->name.c_str());
338 else
339 printf(" %s[%d]=", t->name.c_str(), index);
340 }
341
342 for (int j=0; j<t->arraySize; j++)
343 {
344 if (index >= 0)
345 j = index;
346
347 switch (t->typeCode)
348 {
349 default:
350 printf("unknownType%d ",t->typeCode);
351 break;
352 case 1: /* BYTE */
353 printf("%u ",((uint8_t*)ptr)[j]);
354 break;
355 case 2: /* SBYTE */
356 printf("%d ",((int8_t*)ptr)[j]);
357 break;
358 case 3: /* CHAR */
359 printf("\'%c\' ",((char*)ptr)[j]);
360 break;
361 case 4: /* WORD */
362 printf("%u ",((uint16_t*)ptr)[j]);
363 break;
364 case 5: /* SHORT */
365 printf("%d ",((int16_t*)ptr)[j]);
366 break;
367 case 6: /* DWORD */
368 printf("%u ",((uint32_t*)ptr)[j]);
369 break;
370 case 7: /* INT */
371 printf("%d ",((int32_t*)ptr)[j]);
372 break;
373 case 8: /* BOOL */
374 printf("%u ",((uint32_t*)ptr)[j]);
375 break;
376 case 9: /* FLOAT */
377 printf("%.8g ",((float*)ptr)[j]);
378 break;
379 case 10: /* DOUBLE */
380 printf("%.16g ",((double*)ptr)[j]);
381 break;
382 //case 12: /* STRING */
383 //printf("%s ",&((char*)ptr)[j]);
384 //break;
385 }
386
387 if (index >= 0)
388 break;
389 }
390 }
391 }
392
393 if (n>0)
394 printf(" %s", ctime(&t));
395 }
396
397 delete[] buf;
398 break;
399 }
400 }
401 }
402
403 return 0;
404}
405
406int readHst(const char* name)
407{
408 FILE* f = fopen(name,"r");
409 if (!f)
410 {
411 fprintf(stderr,"Error: Cannot open \'%s\', errno %d (%s)\n", name, errno, strerror(errno));
412 exit(1);
413 }
414
415 readHstFile(f);
416 fclose(f);
417 return 0;
418}
419
420std::string readString(FILE* f)
421{
422 char buf[1024];
423 memset(buf, 0, sizeof(buf));
424 const char* s = fgets(buf, sizeof(buf)-1, f);
425 if (!s)
426 return "";
427 // NUL-teminated by memset(0)
428 size_t len = strlen(buf);
429 if (len > 0) {
430 // remove trailing newline
431 if (buf[len-1] == '\n')
432 buf[len-1] = 0;
433 }
434 return buf;
435}
436
437std::string tagValue(const char* tag, const std::string& s)
438{
439 size_t len = strlen(tag);
440 if (strncmp(s.c_str(), tag, len) == 0) {
441 const char* sptr = s.c_str() + len;
442 while (sptr[0] == ' ')
443 sptr++;
444 return sptr;
445 }
446 return "";
447}
448
449int readMhfFileV2(const char* filename, FILE*f)
450{
451 std::string event_name = tagValue("event_name:", readString(f));
452 std::string time = tagValue("time:", readString(f));
453 printf("event name: [%s], time [%s]\n", event_name.c_str(), time.c_str());
454 std::string s;
455 while (1) {
456 s = readString(f);
457 if (strncmp(s.c_str(), "tag:", 4) != 0)
458 break;
459 printf("tag: %s\n", s.c_str());
460 }
461 std::string s_record_size = tagValue("record_size:", s);
462 std::string s_data_offset = tagValue("data_offset:", readString(f));
463 size_t record_size = atoi(s_record_size.c_str());
464 size_t data_offset = atoi(s_data_offset.c_str());
465 //record_size += 4; // 4 bytes of timestamp
466 printf("record size: %zu, data offset: %zu\n", record_size, data_offset);
467 int status = fseek(f, data_offset, SEEK_SET);
468 if (status != 0) {
469 fprintf(stderr, "%s: cannot seek to %zu, fseek() returned %d, errno %d (%s)\n", filename, data_offset, status, errno, strerror(errno));
470 return -1;
471 }
472 char buf[record_size];
473 int count = 0;
474 uint32_t last_time = atoi(time.c_str());
475 while (!feof(f)) {
476 size_t rd = fread(buf, 1, record_size, f);
477 //printf("read %zu\n", rd);
478 if (rd == 0) {
479 // EOF
480 break;
481 } else if (rd != record_size) {
482 // short read
483 fprintf(stderr, "%s: short read at the end of file, last data record is truncated from %zu to %zu bytes\n", filename, record_size, rd);
484 break;
485 }
486 const uint32_t t = *(uint32_t*)&buf[0];
487 printf("record %d, time %lu, incr %lu\n", count, (long unsigned int)t, (long unsigned int)(t-last_time));
488 count++;
489 if (t == last_time) {
490 printf("duplicate time %lu -> %lu\n", (long unsigned int)last_time, (long unsigned int)t);
491 } else if (t < last_time) {
492 printf("non-monotonic time %lu -> %lu\n", (long unsigned int)last_time, (long unsigned int)t);
493 }
494 last_time = t;
495 }
496 fprintf(stderr, "%s: read %d records\n", filename, count);
497 return 0;
498}
499
500int readMhfFile(const char* filename, FILE*f)
501{
502 std::string version = readString(f);
503 if (version == "version: 2.0") {
504 return readMhfFileV2(filename, f);
505 }
506
507 fprintf(stderr, "%s: unexpected file version: %s\n", filename, version.c_str());
508 return -1;
509}
510
511int readMhf(const char* name)
512{
513 FILE* f = fopen(name,"r");
514 if (!f) {
515 fprintf(stderr,"Error: Cannot open \'%s\', errno %d (%s)\n", name, errno, strerror(errno));
516 exit(1);
517 }
518
519 readMhfFile(name, f);
520 fclose(f);
521 return 0;
522}
523
524void help()
525{
526 fprintf(stderr,"Usage: mhdump [-h] [-L] [-n] [-t] [-E event_id] [-T tag_name] file1.hst file2.hst ...\n");
527 fprintf(stderr,"Usage: mhdump [-L] [-n] [-t] [-T tag_name] mhf_file1.dat mhf_file2.dat ...\n");
528 fprintf(stderr,"\n");
529 fprintf(stderr,"Switches:\n");
530 fprintf(stderr," -h --- print this help message\n");
531 fprintf(stderr," -L --- list tag definitions only\n");
532 fprintf(stderr," -t --- omit tag definitions\n");
533 fprintf(stderr," -n --- omit variable names\n");
534 fprintf(stderr,"\n");
535 fprintf(stderr,"Examples:\n");
536 fprintf(stderr," To list all existing tags: mhdump -L file1.hst file2.hst ...\n");
537 fprintf(stderr," To show data for all events, all tags: mhdump file1.hst file2.hst ...\n");
538 fprintf(stderr," To show all data for event 0: mhdump -E 0 file1.hst file2.hst ...\n");
539 fprintf(stderr," To show data for event 0, tag \"State\": mhdump -n -E 0 -T State file1.hst file2.hst ...\n");
540 fprintf(stderr," To show data for event 3, tag \"MCRT\", array index 5: mhdump -n -E 3 -T MCRT[5] file1.hst file2.hst ...\n");
541 exit(1);
542}
543
544int main(int argc,char*argv[])
545{
546 int event_id = -1;
547
548 if (argc <= 1)
549 help(); // DOES NOT RETURN
550
551 for (int iarg=1; iarg<argc; iarg++)
552 if (strcmp(argv[iarg], "-h")==0)
553 {
554 help(); // DOES NOT RETURN
555 }
556 else if (strcmp(argv[iarg], "-E")==0)
557 {
558 iarg++;
560 if (!gTags[event_id])
561 gTags[event_id] = new Event;
562 gTags[event_id]->printAllTags = true;
563 }
564 else if (strcmp(argv[iarg], "-T")==0)
565 {
566 iarg++;
567 char *s = strchr(argv[iarg],'[');
568 int index = -1;
569 if (s)
570 {
571 index = atoi(s+1);
572 *s = 0;
573 }
574
575 std::string name = argv[iarg];
576
577 Event* e = gTags[event_id];
578
579 if ((event_id<0) || !e)
580 {
581 fprintf(stderr,"Error: expected \"-E event_id\" before \"-T ...\"\n");
582 exit(1);
583 }
584
585 e->printAllTags = false;
586 e->tagNames.push_back(name);
587 e->tagIndexes.push_back(index);
588 }
589 else if (strcmp(argv[iarg], "-t")==0)
590 doPrintTags = false;
591 else if (strcmp(argv[iarg], "-L")==0)
592 {
593 doPrintTags = true;
594 doPrintData = false;
595 }
596 else if (strcmp(argv[iarg], "-A")==0)
597 doAll = true;
598 else if (strcmp(argv[iarg], "-n")==0)
599 doPrintNames = false;
600 else if (strncmp(argv[iarg], "mhf_", 4) == 0 || strstr(argv[iarg], "/mhf_")) {
601 // read mhf_xxx.dat files
602 if (gTags.size() == 0)
603 doAll = true;
604 readMhf(argv[iarg]);
605 } else {
606 // read xxx.hst files
607 if (gTags.size() == 0)
608 doAll = true;
609 readHst(argv[iarg]);
610 }
611
612 // make leak sanitizer happy, delete everything we allocated.
613 for (auto& ei: gTags) {
614 if (ei.second) {
615 for (auto& ti: ei.second->tags) {
616 if (ti.second) {
617 delete ti.second;
618 }
619 }
620 ei.second->tags.clear();
621 delete ei.second;
622 }
623 }
624 gTags.clear();
625
626 return 0;
627}
628
629/* emacs
630 * Local Variables:
631 * tab-width: 8
632 * c-basic-offset: 3
633 * indent-tabs-mode: nil
634 * End:
635 */
unsigned int DWORD
Definition mcstd.h:51
int main()
Definition hwtest.cxx:23
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
DWORD last_time
Definition mana.cxx:3070
INT type
Definition mana.cxx:269
double count
Definition mdump.cxx:33
INT i
Definition mdump.cxx:32
static int offset
Definition mgd.cxx:1500
int readMhf(const char *name)
Definition mhdump.cxx:511
bool doPrintNames
Definition mhdump.cxx:124
bool doPrintData
Definition mhdump.cxx:125
int readHstFile(FILE *f)
Definition mhdump.cxx:128
int readMhfFileV2(const char *filename, FILE *f)
Definition mhdump.cxx:449
int readMhfFile(const char *filename, FILE *f)
Definition mhdump.cxx:500
bool doPrintTags
Definition mhdump.cxx:123
const char * tid_name[]
Definition mhdump.cxx:78
int readHst(const char *name)
Definition mhdump.cxx:406
void help()
Definition mhdump.cxx:524
std::string readString(FILE *f)
Definition mhdump.cxx:420
int tid_size[]
Definition mhdump.cxx:55
std::map< int, Event * > gTags
Definition mhdump.cxx:121
std::string tagValue(const char *tag, const std::string &s)
Definition mhdump.cxx:437
bool doAll
Definition mhdump.cxx:126
#define NAME_LENGTH
Definition mhdump.cxx:33
#define event_id
#define name(x)
Definition midas_macro.h:24
#define ctime
Definition msystem.h:264
INT j
Definition odbhist.cxx:40
DWORD status
Definition odbhist.cxx:39
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
std::vector< std::string > tagNames
Definition mhdump.cxx:117
bool printAllTags
Definition mhdump.cxx:114
int size
Definition mhdump.cxx:115
std::vector< int > tagIndexes
Definition mhdump.cxx:118
std::map< std::string, Tag * > tags
Definition mhdump.cxx:116
Definition midas.h:1234
DWORD type
Definition midas.h:1236
int offset
int arraySize
Definition mhdump.cxx:107
int typeSize
Definition mhdump.cxx:108
std::string name
Definition mhdump.cxx:105
int event_id
Definition mhdump.cxx:104
int typeCode
Definition mhdump.cxx:109
char c
Definition system.cxx:1310
static double e(void)
Definition tinyexpr.c:136