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

This file is part of the GIRAFFE Pipeline Reference Manual 2.19.4.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Fri Feb 6 2026 11:30:08 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2004