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 
60 static const cxsize PAF_FIELD_OFFSET_VALUE = 20;
61 static 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 
70 static const cxsize PAF_RECORD_MAX = 256;
71 
72 
81 struct GiPafHdr {
82  cxchar *name;
83  cxchar *type;
84  cxchar *id;
85  cxchar *description;
86 };
87 
88 typedef struct GiPafHdr GiPafHdr;
89 
90 
91 struct GiPaf {
92  GiPafHdr *header;
93  cpl_propertylist *records;
94 };
95 
96 
97 inline 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 
204 inline 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 
338 inline 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 
362 inline 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 
395 inline 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 
512 GiPaf *
513 giraffe_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 
537 void
538 giraffe_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 
560 cxchar *
561 giraffe_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 
576 cxint
577 giraffe_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 
600 cxchar *
601 giraffe_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 
616 cxint
617 giraffe_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 
640 cxchar *
641 giraffe_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 
655 cxint
656 giraffe_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 
679 cxchar *
680 giraffe_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 
694 cxint
695 giraffe_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 
719 cpl_propertylist *
720 giraffe_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 
734 cxint
735 giraffe_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 
755 cxint
756 giraffe_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:580

This file is part of the GIRAFFE Pipeline Reference Manual 2.16.10.
Documentation copyright © 2002-2006 European Southern Observatory.
Generated on Thu Dec 15 2022 21:18:51 by doxygen 1.9.1 written by Dimitri van Heesch, © 1997-2004