]>
Commit | Line | Data |
---|---|---|
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 |