GIRAFFE Pipeline Reference Manual

gipaf.c
1/*
2 * This file is part of the GIRAFFE Pipeline
3 * Copyright (C) 2002-2019 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <pwd.h>
27#if defined HAVE_SYS_TYPES_H
28# include <sys/types.h>
29#endif
30
31#include <cxmemory.h>
32#include <cxstring.h>
33#include <cxstrutils.h>
34
35#include <cpl_propertylist.h>
36
37#include "giutils.h"
38#include "gipaf.h"
39
40
41#define PAF_HDR_START "PAF.HDR.START"
42#define PAF_TYPE "PAF.TYPE"
43#define PAF_ID "PAF.ID"
44#define PAF_NAME "PAF.NAME"
45#define PAF_DESC "PAF.DESC"
46#define PAF_CRTE_NAME "PAF.CRTE.NAME"
47#define PAF_CRTE_TIME "PAF.CRTE.DAYTIM"
48#define PAF_LCHG_NAME "PAF.LCHG.NAME"
49#define PAF_LCHG_TIME "PAF.LCHG.DAYTIM"
50#define PAF_CHCK_NAME "PAF.CHCK.NAME"
51#define PAF_CHCK_TIME "PAF.CHCK.DAYTIM"
52#define PAF_CHCK_CHECKSUM "PAF.CHCK.CHECKSUM"
53#define PAF_HDR_END "PAF.HDR.END"
54
55
56/*
57 * Value and comment field start position
58 */
59
60static const cxsize PAF_FIELD_OFFSET_VALUE = 20;
61static const cxsize PAF_FIELD_OFFSET_COMMENT = 45;
62
63
64/*
65 * Maximum length of a parameter file record, i.e. maximum number of
66 * characters per line of a parameter file on disk. This does not include
67 * a trailing 0.
68 */
69
70static const cxsize PAF_RECORD_MAX = 256;
71
72
81struct GiPafHdr {
82 cxchar *name;
83 cxchar *type;
84 cxchar *id;
85 cxchar *description;
86};
87
88typedef struct GiPafHdr GiPafHdr;
89
90
91struct GiPaf {
92 GiPafHdr *header;
93 cpl_propertylist *records;
94};
95
96
97inline static cxint
98_giraffe_paf_format_line(cx_string *line, const cxchar *name,
99 const cxchar *value, const cxchar *comment,
100 cxbool append)
101{
102
103 cxchar buffer[PAF_RECORD_MAX + 2];
104
105 cxsize sz = 0;
106 cxsize cpos = 0;
107
108
109 cx_assert(line != NULL);
110
111 if (name == NULL) {
112 return -1;
113 }
114
115
116 /*
117 * Verify that the record name fits into the buffer. The extra
118 * character is for the semicolon which has to be present.
119 */
120
121 sz = strlen(name);
122
123 if (sz + 1 > PAF_RECORD_MAX) {
124 return 1;
125 }
126
127 memset(buffer, ' ', PAF_RECORD_MAX + 1);
128 memcpy(buffer, name, sz);
129
130 cpos = sz;
131
132 if (value != NULL) {
133
134 if (cpos < PAF_FIELD_OFFSET_VALUE) {
135 cpos = PAF_FIELD_OFFSET_VALUE;
136 }
137 else {
138 ++cpos;
139 }
140
141 sz = strlen(value);
142
143
144 /*
145 * Verify that writing the value string does not overflow
146 * the buffer.
147 */
148
149 if (sz > PAF_RECORD_MAX - cpos + 1) {
150 return 2;
151 }
152
153 memcpy(&buffer[cpos], value, sz);
154 cpos += sz;
155
156 }
157
158 buffer[cpos++] = ';';
159
160
161 /*
162 * Comments are only printed if there is room in the buffer for
163 * at least 3 characters, so that not only the hash and the
164 * following blank appear in the output because of the finite
165 * record size.
166 */
167
168 if (comment != NULL && comment[0] != '\0' &&
169 (PAF_RECORD_MAX - cpos + 1) > 2) {
170
171 if (cpos < PAF_FIELD_OFFSET_COMMENT) {
172 cpos = PAF_FIELD_OFFSET_COMMENT;
173 }
174 else {
175 ++cpos;
176 }
177
178 memcpy(&buffer[cpos], "# ", 2);
179 cpos += 2;
180
181 sz = strlen(comment);
182 sz = sz < PAF_RECORD_MAX - cpos + 1 ? sz : PAF_RECORD_MAX - cpos + 1;
183
184 memcpy(&buffer[cpos], comment, sz);
185 cpos += sz;
186 }
187
188 buffer[cpos] = '\n';
189 buffer[++cpos] = '\0';
190
191
192 if (append == TRUE) {
193 cx_string_append(line, buffer);
194 }
195 else {
196 cx_string_set(line, buffer);
197 }
198
199 return 0;
200
201}
202
203
204inline static cxint
205_giraffe_paf_convert_property(cx_string *line, cpl_property *property,
206 cxbool append)
207{
208
209 cxint status = 0;
210
211 const cxchar *name;
212 const cxchar *comment;
213
214 cx_string *value = NULL;
215
216
217 cx_assert(line != NULL);
218
219 if (property == NULL) {
220 return -1;
221 }
222
223 value = cx_string_new();
224
225 switch (cpl_property_get_type(property)) {
226 case CPL_TYPE_CHAR:
227 {
228 cxchar c = cpl_property_get_char(property);
229
230 cx_string_sprintf(value, "%c", c);
231 }
232 break;
233
234 case CPL_TYPE_BOOL:
235 {
236 cxint b = cpl_property_get_bool(property);
237
238 if (b != 0) {
239 cx_string_set(value, "T");
240 }
241 else {
242 cx_string_set(value, "F");
243 }
244 }
245 break;
246
247 case CPL_TYPE_INT:
248 {
249 cxint i = cpl_property_get_int(property);
250
251 cx_string_sprintf(value, "%d", i);
252 }
253 break;
254
255 case CPL_TYPE_LONG:
256 {
257 cxlong l = cpl_property_get_long(property);
258
259 cx_string_sprintf(value, "%ld", l);
260 }
261 break;
262
263 case CPL_TYPE_FLOAT:
264 {
265 cxfloat f = cpl_property_get_float(property);
266
267 cx_string_sprintf(value, "%.15G", f);
268
269 if (!strchr(cx_string_get(value), '.')) {
270
271 if (strchr(cx_string_get(value), 'E')) {
272 cx_string_sprintf(value, "%.1E", f);
273 }
274 else {
275 cx_string_append(value, ".");
276 }
277 }
278 }
279 break;
280
281 case CPL_TYPE_DOUBLE:
282 {
283 cxdouble d = cpl_property_get_double(property);
284
285 cx_string_sprintf(value, "%.15G", d);
286
287 if (!strchr(cx_string_get(value), '.')) {
288
289 if (strchr(cx_string_get(value), 'E')) {
290 cx_string_sprintf(value, "%.1E", d);
291 }
292 else {
293 cx_string_append(value, ".");
294 }
295 }
296 }
297 break;
298
299 case CPL_TYPE_STRING:
300 {
301 const cxchar *s = cpl_property_get_string(property);
302
303 cx_string_sprintf(value, "\"%s\"", s);
304 }
305 break;
306
307 default:
308
309 /*
310 * Unsupported property type. This point should never be
311 * reached!
312 */
313
314 cx_string_delete(value);
315
316 return 1;
317 break;
318 }
319
320 name = cpl_property_get_name(property);
321 comment = cpl_property_get_comment(property);
322
323 status = _giraffe_paf_format_line(line, name, cx_string_get(value),
324 comment, append);
325
326 if (status != 0) {
327 cx_string_delete(value);
328 return 2;
329 }
330
331 cx_string_delete(value);
332
333 return 0;
334
335}
336
337
338inline static GiPafHdr *
339_giraffe_pafhdr_create(const cxchar *name, const cxchar *type,
340 const cxchar *id, const cxchar *description)
341{
342
343 GiPafHdr *self = cx_calloc(1, sizeof *self);
344
345
346 self->name = cx_strdup(name);
347 self->type = cx_strdup(type);
348
349 if (id != NULL) {
350 self->id = cx_strdup(id);
351 }
352
353 if (description != NULL) {
354 self->description = cx_strdup(description);
355 }
356
357 return self;
358
359}
360
361
362inline static void
363_giraffe_pafhdr_destroy(GiPafHdr *self)
364{
365
366 if (self != NULL) {
367 if (self->name != NULL) {
368 cx_free(self->name);
369 self->name = NULL;
370 }
371
372 if (self->type != NULL) {
373 cx_free(self->type);
374 self->type = NULL;
375 }
376
377 if (self->id != NULL) {
378 cx_free(self->id);
379 self->id = NULL;
380 }
381
382 if (self->description != NULL) {
383 cx_free(self->description);
384 self->description = NULL;
385 }
386
387 cx_free(self);
388 }
389
390 return;
391
392}
393
394
395inline static cxint
396_giraffe_pafhdr_write(GiPafHdr *self, FILE *stream)
397{
398
399 if (stream == NULL) {
400 return -1;
401 }
402
403 if (self != NULL) {
404
405 cxchar *user;
406 cxchar *timestamp;
407
408 cx_string *header = cx_string_new();
409
410
411#if defined HAVE_GETUID && defined HAVE_GETPWUID
412
413 struct passwd *pw;
414
415 pw = getpwuid(getuid());
416
417 if (pw == NULL) {
418 cx_string_delete(header);
419 return 1;
420 }
421
422 user = pw->pw_name;
423
424#else
425 user = getenv("USER");
426 user = user == NULL ? getenv("LOGNAME") : user;
427
428 if (user == NULL) {
429 cx_string_delete(header);
430 return 1;
431 }
432
433#endif
434
435 timestamp = giraffe_localtime_iso8601();
436
437 if (timestamp == NULL) {
438 cx_string_delete(header);
439 return 2;
440 }
441
442
443 /*
444 * Write formatted header records to a string buffer
445 */
446
447 _giraffe_paf_format_line(header, PAF_HDR_START, NULL, NULL, TRUE);
448 _giraffe_paf_format_line(header, PAF_TYPE, self->type, "Type of "
449 "parameter file", TRUE);
450
451 if (self->id != NULL) {
452 _giraffe_paf_format_line(header, PAF_ID, self->id, NULL, TRUE);
453 }
454 else {
455 _giraffe_paf_format_line(header, PAF_ID, "", NULL, TRUE);
456 }
457
458 _giraffe_paf_format_line(header, PAF_NAME, self->name, "Name of "
459 "PAF", TRUE);
460
461 if (self->description != NULL) {
462 _giraffe_paf_format_line(header, PAF_DESC, self->description,
463 "Short description of PAF", TRUE);
464 }
465 else {
466 _giraffe_paf_format_line(header, PAF_DESC, "", "Short "
467 "description of PAF", TRUE);
468 }
469
470 _giraffe_paf_format_line(header, PAF_CRTE_NAME, user, "Name of "
471 "creator", TRUE);
472 _giraffe_paf_format_line(header, PAF_CRTE_TIME, timestamp,
473 "Civil time for creation", TRUE);
474
475 _giraffe_paf_format_line(header, PAF_LCHG_NAME, "", "Author of "
476 "par. file", TRUE);
477 _giraffe_paf_format_line(header, PAF_LCHG_TIME, "", "Timestamp for "
478 "last change", TRUE);
479
480 _giraffe_paf_format_line(header, PAF_CHCK_NAME, "", "Name of appl. "
481 "checking", TRUE);
482 _giraffe_paf_format_line(header, PAF_CHCK_TIME, "", "Time for "
483 "checking", TRUE);
484 _giraffe_paf_format_line(header, PAF_CHCK_CHECKSUM, "", "Checksum "
485 "for the PAF", TRUE);
486
487 _giraffe_paf_format_line(header, PAF_HDR_END, NULL, NULL, TRUE);
488
489
490 /*
491 * Write string buffer contents to the output stream
492 */
493
494 fprintf(stream, "%s", cx_string_get(header));
495
496 if (ferror(stream) != 0) {
497 cx_free(timestamp);
498 cx_string_delete(header);
499
500 return 3;
501 }
502
503 cx_free(timestamp);
504 cx_string_delete(header);
505 }
506
507 return 0;
508
509}
510
511
512GiPaf *
513giraffe_paf_new(const cxchar *name, const cxchar *type, const cxchar *id,
514 const cxchar *description)
515{
516
517 GiPaf *self = NULL;
518
519
520 if (name == NULL || type == NULL) {
521 return NULL;
522 }
523
524 self = cx_malloc(sizeof *self);
525
526 self->header = _giraffe_pafhdr_create(name, type, id, description);
527 self->records = cpl_propertylist_new();
528
529 cx_assert(self->header != NULL);
530 cx_assert(self->records != NULL);
531
532 return self;
533
534}
535
536
537void
538giraffe_paf_delete(GiPaf *self)
539{
540
541 if (self != NULL) {
542 if (self->records != NULL) {
543 cpl_propertylist_delete(self->records);
544 self->records = NULL;
545 }
546
547 if (self->header != NULL) {
548 _giraffe_pafhdr_destroy(self->header);
549 self->header = NULL;
550 }
551
552 cx_free(self);
553 }
554
555 return;
556
557}
558
559
560cxchar *
561giraffe_paf_get_name(const GiPaf *self)
562{
563
564 if (self == NULL) {
565 return NULL;
566 }
567
568 cx_assert(self->header != NULL);
569 cx_assert(self->header->name != NULL);
570
571 return self->header->name;
572
573}
574
575
576cxint
577giraffe_paf_set_name(GiPaf *self, const cxchar *name)
578{
579
580 cx_assert(self != NULL);
581
582 if (name == NULL) {
583 return -1;
584 }
585
586 if (self->header->name != NULL) {
587 self->header->name = cx_realloc(self->header->name,
588 (strlen(name) + 1) * sizeof(cxchar));
589 strcpy(self->header->name, name);
590 }
591 else {
592 self->header->name = cx_strdup(name);
593 }
594
595 return 0;
596
597}
598
599
600cxchar *
601giraffe_paf_get_type(const GiPaf *self)
602{
603
604 if (self == NULL) {
605 return NULL;
606 }
607
608 cx_assert(self->header != NULL);
609 cx_assert(self->header->type != NULL);
610
611 return self->header->type;
612
613}
614
615
616cxint
617giraffe_paf_set_type(GiPaf *self, const cxchar *type)
618{
619
620 cx_assert(self != NULL);
621
622 if (type == NULL) {
623 return -1;
624 }
625
626 if (self->header->type != NULL) {
627 self->header->type = cx_realloc(self->header->type,
628 (strlen(type) + 1) * sizeof(cxchar));
629 strcpy(self->header->type, type);
630 }
631 else {
632 self->header->type = cx_strdup(type);
633 }
634
635 return 0;
636
637}
638
639
640cxchar *
641giraffe_paf_get_id(const GiPaf *self)
642{
643
644 if (self == NULL) {
645 return NULL;
646 }
647
648 cx_assert(self->header != NULL);
649
650 return self->header->id;
651
652}
653
654
655cxint
656giraffe_paf_set_id(GiPaf *self, const cxchar *id)
657{
658
659 cx_assert(self != NULL);
660
661 if (id == NULL) {
662 return -1;
663 }
664
665 if (self->header->id != NULL) {
666 self->header->id = cx_realloc(self->header->id,
667 (strlen(id) + 1) * sizeof(cxchar));
668 strcpy(self->header->id, id);
669 }
670 else {
671 self->header->id = cx_strdup(id);
672 }
673
674 return 0;
675
676}
677
678
679cxchar *
680giraffe_paf_get_description(const GiPaf *self)
681{
682
683 if (self == NULL) {
684 return NULL;
685 }
686
687 cx_assert(self->header != NULL);
688
689 return self->header->description;
690
691}
692
693
694cxint
695giraffe_paf_set_description(GiPaf *self, const cxchar *description)
696{
697
698 cx_assert(self != NULL);
699
700 if (description == NULL) {
701 return -1;
702 }
703
704 if (self->header->description != NULL) {
705 self->header->description = cx_realloc(self->header->description,
706 (strlen(description) + 1) *
707 sizeof(cxchar));
708 strcpy(self->header->description, description);
709 }
710 else {
711 self->header->description = cx_strdup(description);
712 }
713
714 return 0;
715
716}
717
718
719cpl_propertylist *
720giraffe_paf_get_properties(const GiPaf *self)
721{
722
723 if (self == NULL) {
724 return NULL;
725 }
726
727 cx_assert(self->records != NULL);
728
729 return self->records;
730
731}
732
733
734cxint
735giraffe_paf_set_properties(GiPaf *self, const cpl_propertylist *properties)
736{
737
738 cx_assert(self != NULL);
739
740 if (properties == NULL) {
741 return -1;
742 }
743
744 if (self->records != NULL) {
745 cpl_propertylist_delete(self->records);
746 }
747
748 self->records = cpl_propertylist_duplicate(properties);
749
750 return 0;
751
752}
753
754
755cxint
756giraffe_paf_write(const GiPaf *self)
757{
758
759 cxint status = 0;
760
761 FILE *stream = NULL;
762
763
764 if (self == NULL) {
765 return -1;
766 }
767
768 cx_assert(self->header != NULL);
769
770 stream = fopen(giraffe_paf_get_name(self), "wb");
771
772 if (stream == NULL) {
773 return 1;
774 }
775
776
777 /*
778 * Write PAF header
779 */
780
781 status = _giraffe_pafhdr_write(self->header, stream);
782
783 if (status != 0) {
784 fclose(stream);
785 return 2;
786 }
787
788 fflush(stream);
789
790
791 /*
792 * Write PAF records
793 */
794
795 if (self->records != NULL && !cpl_propertylist_is_empty(self->records)) {
796
797 cxchar buffer[PAF_RECORD_MAX];
798
799 register cxlong i;
800
801 cx_string *line = NULL;
802
803
804 buffer[0] = '#';
805 memset(&buffer[1], '-', 78);
806 buffer[79] = '\0';
807 fprintf(stream, "%s\n", buffer);
808
809 if (ferror(stream) != 0) {
810 fclose(stream);
811 return 3;
812 }
813
814 line = cx_string_new();
815
816 for (i = 0; i < cpl_propertylist_get_size(self->records); i++) {
817
818 cpl_property *p = cpl_propertylist_get(self->records, i);
819
820
821 status = _giraffe_paf_convert_property(line, p, FALSE);
822
823 if (status != 0) {
824 cx_string_delete(line);
825 fclose(stream);
826
827 return 4;
828 }
829
830 fprintf(stream, "%s", cx_string_get(line));
831
832 if (ferror(stream) != 0) {
833 cx_string_delete(line);
834 fclose(stream);
835
836 return 5;
837 }
838 }
839
840 cx_string_delete(line);
841 fflush(stream);
842
843 }
844
845 fclose(stream);
846
847 return 0;
848
849}
cxchar * giraffe_localtime_iso8601(void)
Get the current date and time in ISO 8601 format.
Definition: giutils.c:582

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.14.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Wed Jan 15 2025 22:16:53 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004