f67e2651 |
1 | /* |
2 | * Read/write files in the oncoming Standard AMANDA format - "format 2000" |
3 | */ |
4 | #if 0 /******* TODO *********/ |
5 | /* skip event gets array as parameter */ |
6 | /* level 4 event types in mevt */ |
7 | /* end of file, tend */ |
8 | /******************************/ |
9 | #endif |
10 | |
11 | |
12 | char *amanda_rdmc_cvsid = |
13 | "$Header: /net/local/cvsroot/siegmund/rdmc/amanda.c,v 1.81 2004/02/19 17:10:08 wiebusch Exp $"; |
14 | |
15 | #include <stdlib.h> |
16 | #include <ctype.h> |
17 | |
18 | #include "rdmc.h" |
19 | #ifdef AMANDA_ASCII_F |
20 | |
21 | #include "rdmc_local.h" |
22 | |
23 | #include "amanda.h" |
24 | #include "f2k.h" |
25 | |
26 | /****************************************************************************/ |
27 | /* rdmc_nint(double a) */ |
28 | /* converts a to the nearest integer */ |
29 | /* but also takes care on the sign */ |
30 | /****************************************************************************/ |
31 | long rdmc_nint(double a) |
32 | { long i; |
33 | i = (a >= 0.) ? (long) (a + 0.5 ) : (long) (a - 0.5); |
34 | return i; |
35 | } |
36 | |
37 | /*******************************/ |
38 | /* Work around missing isnan() */ |
39 | /*******************************/ |
f60271ca |
40 | int isnan(double r) |
f67e2651 |
41 | { |
42 | return 0; |
43 | } |
44 | |
45 | /******************************************************/ |
46 | /*** Definitions of f2k blocks struture in memory ***/ |
47 | /******************************************************/ |
48 | |
49 | |
50 | /* check if line is in buffer or read a new one */ |
51 | /* returns 0 if OK */ |
52 | static int amanda_readline(mcfile *fp); |
53 | |
54 | /* dump a line back into the buffer if it is empty */ |
55 | /* returns 0 if OK */ |
56 | static int amanda_unreadline(mcfile *fp); |
57 | |
58 | /* read the next block according to a list of allowed lines into the buffer */ |
59 | /* returns 0 if OK */ |
60 | static int amanda_read_block(mcfile *fp ,const f2000_event_t *def); |
61 | |
62 | /* try to decode a given line according to line_def */ |
63 | /* store if OK */ |
64 | /* returns RDMC_IO_OK or RDMC_LINE_EMPTY or RDMC_EVENT_NOT_RECOGNIZED */ |
65 | static int amanda_lex_line(mcfile *fp, const f2000_line_t * const line_def[F2K_MAX_LINETYPES] ); |
66 | |
67 | /* compares each byte of key to the first no white exam until lngth of key*/ |
68 | /* -1 if line is empty, 0 on no and 1 on succes */ |
69 | static int tokencmp(const char *key, char *exam); |
70 | |
71 | /* same with no trailing chars */ |
72 | static int tokencmp_notrail(const char *key, char *exam); |
73 | |
74 | /* checks if the first non-white char in exam is in keys */ |
75 | /* if a line is only whitespace ot empty -1 is returned */ |
76 | /* 0: if the char is not found */ |
77 | /* 1: if the char is not found */ |
78 | static int tokenchr(const char *keys, char *exam); |
79 | /* same as above but chars are not alnum (ispunct()) */ |
80 | static int tokenchrpunct(const char *keys, char *exam); |
81 | |
82 | /***************************************************************************/ |
83 | /***************************************************************************/ |
84 | /*** ***/ |
85 | /*** Read functions follow ***/ |
86 | /*** ***/ |
87 | /***************************************************************************/ |
88 | |
89 | |
90 | /**************************************************************************** |
91 | * read the F2000 "V" line (the first one) and put it into fp |
92 | ****************************************************************************/ |
93 | /******* This is the only parswer routine, which is different !!! */ |
94 | /* it reads directly from fp, instead of the readline mode */ |
95 | int rdmc_amanda_V(const char *s, mcfile *fp) |
96 | { |
97 | int major = 0, minor = 0; |
98 | if(sscanf(s,"V 2000.%i.%i",&major, &minor) != 2) |
99 | return RDMC_LINE_NOT_PARSED; |
100 | if (rdmc_is_f2000_supported(major, minor) == 0) |
101 | return RDMC_UNKNOWN_FORMAT_VERSION; |
102 | fp->fmajor = major; |
103 | fp->fminor = minor; |
104 | return RDMC_IO_OK; |
105 | |
106 | } /* amanda_rdmc_V() */ |
107 | |
108 | int rdmc_rhd_amanda(mcfile *fp){ |
109 | const f2000_event_t *ev_def; |
110 | int ret; |
111 | |
112 | /* get the config def for the right format*/ |
113 | switch( 100*fp->fmajor + fp->fminor ){ |
114 | case 101: |
115 | case 102: |
116 | case 200401: |
117 | ev_def=&f2000_preamble_1x1; |
118 | break; |
119 | default: |
120 | return RDMC_UNKNOWN_FORMAT_VERSION; |
121 | } |
122 | |
123 | /* read the block acordng to the def */ |
124 | if ((ret = amanda_read_block(fp, ev_def)) != RDMC_IO_OK) |
125 | return ret; |
126 | |
127 | /* use the pointer from the event definition and scan*/ |
128 | return ev_def->reader(fp, NULL, NULL); |
129 | } |
130 | |
131 | |
132 | int rdmc_rarr_amanda(mcfile *fp, array *ar) |
133 | { |
134 | const f2000_event_t *ev_def; |
135 | int ret; |
136 | |
137 | /* get the config def for the right format*/ |
138 | switch( 100*fp->fmajor + fp->fminor ){ |
139 | case 101: |
140 | case 102: |
141 | case 200401: |
142 | ev_def=&f2000_mhead_1x1; |
143 | break; |
144 | default: |
145 | return RDMC_UNKNOWN_FORMAT_VERSION; |
146 | } |
147 | |
148 | /* read the block acordng to the def */ |
149 | if ((ret = amanda_read_block(fp, ev_def)) != RDMC_IO_OK) |
150 | return ret; |
151 | |
152 | /* use the pointer from the event definition and scan*/ |
153 | return ev_def->reader(fp, ar, NULL); |
154 | |
155 | } |
156 | |
157 | int rdmc_revt_amanda(mcfile *fp, mevt *ev, array *ar){ |
158 | const f2000_event_t **ev_def,*foot_def; |
159 | |
160 | int ret = RDMC_ILF; |
161 | int ret2 = RDMC_ILF; |
162 | |
163 | /* get the config def for the right format*/ |
164 | /* get the config def for the right format*/ |
165 | switch( 100*fp->fmajor + fp->fminor ){ |
166 | case 101: |
167 | ev_def = f2000_events_1x1; |
168 | foot_def = &f2000_mfoot_1x1 ; |
169 | break; |
170 | case 102: |
171 | ev_def =f2000_events_1x2; |
172 | foot_def = &f2000_mfoot_1x1 ; |
173 | break; |
174 | case 200401: |
175 | ev_def =f2000_events_2004x1; |
176 | foot_def = &f2000_mfoot_1x1 ; |
177 | break; |
178 | default: |
179 | return RDMC_UNKNOWN_FORMAT_VERSION; |
180 | } |
181 | |
182 | while( *ev_def !=NULL ){ |
183 | /* read the block acordng to the def */ |
184 | ret = amanda_read_block(fp, *ev_def); |
185 | if ( ret == RDMC_IO_OK) |
186 | break; |
187 | ++ev_def; |
188 | } |
189 | if ( ret == RDMC_IO_OK){ |
190 | rdmc_clear_mevt(ev); /* reset the event */ |
191 | /* use the pointer from the event definition and scan*/ |
192 | if (fp->info.f2000.nolex) |
193 | return RDMC_IO_OK; |
194 | else |
195 | return (*ev_def)->reader(fp, ar, ev); |
196 | }else{ /* test footer */ |
197 | if ( ret == RDMC_EVENT_NOT_RECOGNIZED) { |
198 | ret2 = amanda_read_block(fp, foot_def); |
199 | if (ret2 == RDMC_IO_OK) |
200 | return RDMC_EOF; |
201 | else |
202 | return ret2; |
203 | }else{ |
204 | return ret; |
205 | } |
206 | } |
207 | } |
208 | |
209 | int rdmc_skipevt_amanda(mcfile *fp) |
210 | { |
211 | int ret; |
212 | #if 0 |
213 | array ar; |
214 | #endif |
215 | mevt ev; |
216 | #if 0 /* this is the proper, presently slow version */ |
217 | rdmc_init_array(&ar); |
218 | rdmc_init_mevt(&ev); |
219 | fp->info.f2000.nolex=1; |
220 | ret = rdmc_revt_amanda(fp, &ev, &ar); |
221 | fp->info.f2000.nolex=0; |
222 | rdmc_clear_array(&ar); |
223 | rdmc_clear_mevt(&ev); |
224 | #else /* presently no array is needed -> dirty patch ! */ |
225 | rdmc_init_mevt(&ev); |
226 | fp->info.f2000.nolex=1; |
227 | ret = rdmc_revt_amanda(fp, &ev, NULL); |
228 | fp->info.f2000.nolex=0; |
229 | rdmc_clear_mevt(&ev); |
230 | #endif |
231 | return ret; |
232 | } |
233 | |
234 | |
235 | |
236 | /**************************************************************************** |
237 | * Reads a nonempty line |
238 | ****************************************************************************/ |
239 | static int amanda_readline(mcfile *fp){ |
240 | |
241 | char *s = fp->last_line; |
242 | do { |
243 | if (fp->info.f2000.unread != 0 ) { /* line in buffer */ |
244 | fp->info.f2000.unread = 0; |
245 | } else{ /* no line in buffer - read from file */ |
246 | if (fgets(s, RDMC_MAXLINE-1, fp->fp) == NULL)/*fgets includes the '\n'*/ |
247 | return EOF; |
248 | } |
249 | } while (*s == '\0'); /* look for a not-empty line */ |
250 | /* increment the counter line */ |
251 | fp->fpos++; |
252 | return RDMC_IO_OK; |
253 | |
254 | } /* amanda_readline() */ |
255 | |
256 | /**************************************************************************** |
257 | * "unread" an amanda F2000 format line |
258 | ****************************************************************************/ |
259 | |
260 | static int amanda_unreadline(mcfile *fp){ |
261 | if (fp->info.f2000.unread != 0) |
262 | return EOF; /* only one line allowed */ |
263 | else |
264 | fp->info.f2000.unread = 1; |
265 | fp->fpos--; |
266 | return RDMC_IO_OK; |
267 | } /* amanda_unreadline() */ |
268 | |
269 | |
270 | static int amanda_read_block(mcfile *fp ,const f2000_event_t *def){ |
271 | int r; |
272 | int ret=RDMC_ILF; |
273 | int do_reading; |
274 | rdmc_clear_f2k_buffer(fp->info.f2000.f2k_buffer); |
275 | fp->errline = 0; |
276 | |
277 | /* test if the block starts with the right line */ |
278 | do_reading=1; |
279 | do { |
280 | if (def->opener[0]){ /* yes there is one needed ! */ |
281 | if ( (r=amanda_readline(fp)) != RDMC_IO_OK) |
282 | ret=r; |
283 | else /* analyse if this line matches and store it then */ |
284 | ret = amanda_lex_line(fp, def->opener); |
285 | } else{ /* no opener needed -> OK */ |
286 | ret = RDMC_IO_OK; |
287 | break; |
288 | } |
289 | if( ret != RDMC_LINE_EMPTY ){ /* something happende */ |
290 | do_reading=0; |
291 | if ( ret == RDMC_EVENT_NOT_RECOGNIZED){ |
292 | amanda_unreadline(fp); /* we have read one line to much */ |
293 | return ret; |
294 | } |
295 | } |
296 | } while(do_reading); |
297 | |
298 | /* keep on reading body lines */ |
299 | do_reading=1; |
300 | do { |
301 | /* analyse if this line matches and store it then */ |
302 | if (def->inner[0]){ /* yes there are some ! */ |
303 | if ( (r=amanda_readline(fp)) != RDMC_IO_OK) |
304 | ret =r; |
305 | else |
306 | ret = amanda_lex_line(fp, def->inner); |
307 | } else{ |
308 | ret = RDMC_IO_OK; |
309 | do_reading=0; |
310 | break; |
311 | } |
312 | |
313 | if( ret != RDMC_LINE_EMPTY ){ /* something happend */ |
314 | if (ret == RDMC_IO_OK) /* line OK -> next one */ |
315 | continue; |
316 | else{ /* line is not parsed -> check if an end marker appeared */ |
317 | amanda_unreadline(fp); /* we have read one line to much */ |
318 | do_reading = 0; /* this is no error since the body may be empty */ |
319 | ret = RDMC_IO_OK; /* this is no error but maybe the next event */ |
320 | break; /* ok we end here */ |
321 | } |
322 | } |
323 | } while(do_reading); |
324 | |
325 | /* check the end marker */ |
326 | do_reading=1; |
327 | do { |
328 | /* analyse if this line matches and store it then */ |
329 | if (def->closer[0]){ /* yes there are some needed ! */ |
330 | if ( (r=amanda_readline(fp)) != RDMC_IO_OK) |
331 | ret=r; |
332 | else |
333 | ret = amanda_lex_line(fp, def->closer); |
334 | } else{ |
335 | ret = RDMC_IO_OK; |
336 | do_reading=0; |
337 | break; |
338 | } |
339 | |
340 | if( ret != RDMC_LINE_EMPTY ){ /* something happend */ |
341 | if (ret == RDMC_IO_OK){ /* line OK -> finish */ |
342 | do_reading=0; |
343 | break; |
344 | } |
345 | else{ /* line is not parsed */ |
346 | amanda_unreadline(fp); /* we have read one line to much */ |
347 | do_reading = 0; /* this is no error since the body may be empty */ |
348 | break; /* ok we end here */ |
349 | } |
350 | } |
351 | } while(do_reading); |
352 | |
353 | return ret; |
354 | } |
355 | |
356 | |
357 | static int amanda_lex_line(mcfile *fp, const f2000_line_t * const line_def[F2K_MAX_LINETYPES] ){ |
358 | int ptindex , cres = 0; |
359 | const f2000_line_t *opt; |
360 | |
361 | if ( !(line_def[0]) ) /* no match actually needed */ |
362 | return RDMC_EVENT_NOT_RECOGNIZED; |
363 | |
364 | for(ptindex=0 , cres=0, opt = line_def[0] |
365 | ; opt |
366 | ; opt = line_def[++ptindex] |
367 | ){ |
368 | |
369 | switch (opt->searchtype){ |
370 | case COMP_STRINGWISE: |
371 | cres = tokencmp(opt->tag,fp->last_line); |
372 | break; |
373 | case COMP_STRINGWISE_NOTRAIL: |
374 | cres = tokencmp_notrail(opt->tag,fp->last_line); |
375 | break; |
376 | case COMP_CHARWISE: |
377 | cres = tokenchr(opt->tag,fp->last_line); |
378 | break; |
379 | case COMP_CHARPUNCT: |
380 | cres = tokenchrpunct(opt->tag,fp->last_line); |
381 | break; |
382 | #if 0 |
383 | case COMP_DUMMY: /* no token is needed so stop parsing */ |
384 | /* trap to finish here */ |
385 | return RDMC_EVENT_NOT_RECOGNIZED; |
386 | break; |
387 | #endif |
388 | default: |
389 | return RDMC_LIBRARY_ERROR; |
390 | } /* switch */ |
391 | if (cres < 0){ /* empty line */ |
392 | return RDMC_LINE_EMPTY; |
393 | } else if(cres == 0){ /* no match found */ |
394 | /* needed but not found -> try the next */ |
395 | continue; |
396 | }else{ /* ok tag is found */ |
397 | rdmc_push_f2k_buffer(fp->info.f2000.f2k_buffer, fp->last_line,line_def[ptindex]); |
398 | return RDMC_IO_OK; |
399 | } /* check cres */ |
400 | } /*for */ |
401 | return RDMC_EVENT_NOT_RECOGNIZED; |
402 | } |
403 | |
404 | /* compares each byte of key to exam until th lngth of key */ |
405 | /* leading whitespaces are ignored */ |
406 | static int tokencmp(const char *key, char *exam){ |
407 | int r = -1; |
408 | const char *k = key; |
409 | const char *e = exam; |
410 | while(*e){ |
411 | if (isspace(*e)) |
412 | ++e; |
413 | else { /* this is the first non white */ |
414 | r=0; |
415 | while (*k){ /* now check key */ |
416 | if (!(*e)) /* if e ends before key */ |
417 | return r=0; |
418 | if( *e == *k ) /* stil agreement ? */ |
419 | r=1; |
420 | else |
421 | return r=0; /* break if not */ |
422 | ++e; /* next char */ |
423 | ++k; |
424 | } /* while k */ |
425 | return r; /* exit here likely with r==1 */ |
426 | } |
427 | } /* while e */ |
428 | |
429 | return r; |
430 | } |
431 | /* compares each byte of key to exam until the lngth of key */ |
432 | /* trailing chars are ignored */ |
433 | static int tokencmp_notrail(const char *key, char *exam){ |
434 | int r = -1; |
435 | const char *k = key; |
436 | const char *e = exam; |
437 | while(*e){ |
438 | if (isspace(*e)) |
439 | ++e; |
440 | else { /* this is the first non white */ |
441 | r=0; |
442 | while (*k){ /* now check key */ |
443 | if (!(*e)) /* if e ends before key */ |
444 | return r=0; |
445 | if( *e == *k ) /* stil agreement ? */ |
446 | r=1; |
447 | else |
448 | return r=0; /* break if not */ |
449 | ++e; /* next char */ |
450 | ++k; |
451 | } /* while k */ |
452 | return r; /* exit here likely with r==1 */ |
453 | } |
454 | } /* while e */ |
455 | return r; |
456 | } |
457 | |
458 | /* checks if the first non-white char in exam is in keys */ |
459 | /* if a line is only whitespace ot empty -1 is returned */ |
460 | /* 0: if the char is not found */ |
461 | /* 1: if the char is found */ |
462 | static int tokenchr(const char *keys, char *exam){ |
463 | int r = -1; |
464 | const char *k=keys; |
465 | const char *e=exam; |
466 | while(*e){ |
467 | if (isspace(*e)) |
468 | ++e; |
469 | else { /* this is the first non white */ |
470 | r=0; |
471 | while (*k){ /* now check key */ |
472 | if( *e == *k ) /* agreement ? */ |
473 | return r=1; |
474 | else |
475 | ++k; |
476 | } /* while k */ |
477 | return r=0; /* exit here likely with r==1 */ |
478 | } |
479 | } /* while e */ |
480 | return r; |
481 | } |
482 | |
483 | static int tokenchrpunct(const char *keys, char *exam){ |
484 | int r = -1; |
485 | const char *k=keys; |
486 | const char *e=exam; |
487 | while(*e){ |
488 | if (isspace(*e)) |
489 | ++e; |
490 | else if (!ispunct(*e)) |
491 | return r=0; |
492 | else { /* this is the first non white */ |
493 | r=0; |
494 | while (*k){ /* now check key */ |
495 | if( *e == *k ) /* agreement ? */ |
496 | return r=1; |
497 | else |
498 | ++k; |
499 | } /* while k */ |
500 | return r=0; /* exit here likely */ |
501 | } |
502 | } /* while e */ |
503 | return r; |
504 | } |
505 | |
506 | |
507 | /***************************************************************************/ |
508 | /*** ***/ |
509 | /*** Write functions follow ***/ |
510 | /*** ***/ |
511 | /***************************************************************************/ |
512 | /***************************************************************************/ |
513 | |
514 | |
515 | |
516 | |
517 | /***************************************************************************/ |
518 | /* write end of file (F2000 format) */ |
519 | int rdmc_wrend_amanda(const mcfile *fp) |
520 | { |
521 | const f2000_event_t *ev_def; |
522 | |
523 | /* get the config def for the right format*/ |
524 | switch( 100*fp->fmajor + fp->fminor ){ |
525 | case 101: |
526 | case 102: |
527 | case 200401: |
528 | ev_def=&f2000_mfoot_1x1; |
529 | break; |
530 | default: |
531 | return RDMC_UNKNOWN_FORMAT_VERSION; |
532 | } |
533 | |
534 | /* use the pointer from the event definition and scan*/ |
535 | return ev_def->writer(fp, NULL, NULL); |
536 | } /* wrend_amanda() */ |
537 | |
538 | /**************************************************************************** |
539 | * function warr_amanda() writes the array info to a amanda-like file |
540 | * This function writes out the head of a AMANDA ascii file |
541 | * opposite to reading the input file it writes not only |
542 | * the Geometry banks ('G', 'P') , but also the ('V' and 'M' flags) |
543 | * so the function whd_amanda does not exist |
544 | ****************************************************************************/ |
545 | |
546 | int rdmc_warr_amanda(const mcfile *fp,const array *geo) |
547 | { |
548 | const f2000_event_t *ev_def; |
549 | |
550 | /* get the config def for the right format*/ |
551 | switch( 100*fp->fmajor + fp->fminor ){ |
552 | default: |
553 | ev_def=&f2000_mhead_1x1; |
554 | break; |
555 | } |
556 | |
557 | /* use the pointer from the event definition and scan*/ |
558 | return ev_def->writer(fp, geo, NULL); |
559 | } |
560 | |
561 | /**************************************************************************** |
562 | * function wevt_amanda() writes an event to a amanda-like file |
563 | ****************************************************************************/ |
564 | |
565 | int rdmc_wevt_amanda(const mcfile *fp,const mevt *event, const array *ar) |
566 | { |
567 | const f2000_event_t *ev_def; |
568 | |
569 | /* get the config def for the right format*/ |
570 | switch( 100*fp->fmajor + fp->fminor ){ |
571 | case 101: |
572 | ev_def=f2000_events_1x1[0]; /* take first array element */ |
573 | break; |
574 | case 102: |
575 | ev_def=f2000_events_1x2[0]; /* take first array element */ |
576 | break; |
577 | case 200401: |
578 | ev_def=f2000_events_2004x1[0]; /* take first array element */ |
579 | break; |
580 | default: |
581 | return RDMC_UNKNOWN_FORMAT_VERSION; |
582 | } |
583 | |
584 | /* use the pointer from the event definition and scan*/ |
585 | return ev_def->writer(fp, ar, event); |
586 | |
587 | } |
588 | |
589 | #if 0 |
590 | /**************************************************************************** |
591 | * wrhist_amanda() writes history lines to an ASCII file |
592 | ****************************************************************************/ |
593 | |
594 | int rdmc_wrhist_amanda(const mcfile *fp, const char *s, const char *pre) |
595 | { |
596 | return rdmc_wrhist_f2k_1x1(fp, s, pre); |
597 | } |
598 | |
599 | /**************************************************************************** |
600 | * wrcomment_amanda() writes a comment line to an ASCII file |
601 | ****************************************************************************/ |
602 | |
603 | int rdmc_wrcomment_amanda(const mcfile *fp, const char *s) |
604 | { |
605 | return rdmc_wrcomment_f2k_1x1(fp, s); |
606 | } |
607 | #endif |
608 | |
609 | #endif /* AMANDA_ASCII_F */ |
610 | |
611 | /**************************************************************************** |
612 | ********************************** E O F *********************************** |
613 | ****************************************************************************/ |
614 | /* |
615 | This is just for EMACS: |
616 | Local Variables: |
617 | compile-command: "cd .. ; make -k rdmc" |
618 | End: |
619 | */ |
620 | |
621 | |
622 | |
623 | |
624 | |
625 | |
626 | |
627 | |
628 | |
629 | |
630 | |
631 | |