27 #if defined HAVE_SYS_TYPES_H
28 # include <sys/types.h>
33 #include <cxstrutils.h>
35 #include <cpl_propertylist.h>
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"
60 static const cxsize PAF_FIELD_OFFSET_VALUE = 20;
61 static const cxsize PAF_FIELD_OFFSET_COMMENT = 45;
70 static const cxsize PAF_RECORD_MAX = 256;
88 typedef struct GiPafHdr GiPafHdr;
93 cpl_propertylist *records;
98 _giraffe_paf_format_line(cx_string *line,
const cxchar *name,
99 const cxchar *value,
const cxchar *comment,
103 cxchar buffer[PAF_RECORD_MAX + 2];
109 cx_assert(line != NULL);
123 if (sz + 1 > PAF_RECORD_MAX) {
127 memset(buffer,
' ', PAF_RECORD_MAX + 1);
128 memcpy(buffer, name, sz);
134 if (cpos < PAF_FIELD_OFFSET_VALUE) {
135 cpos = PAF_FIELD_OFFSET_VALUE;
149 if (sz > PAF_RECORD_MAX - cpos + 1) {
153 memcpy(&buffer[cpos], value, sz);
158 buffer[cpos++] =
';';
168 if (comment != NULL && comment[0] !=
'\0' &&
169 (PAF_RECORD_MAX - cpos + 1) > 2) {
171 if (cpos < PAF_FIELD_OFFSET_COMMENT) {
172 cpos = PAF_FIELD_OFFSET_COMMENT;
178 memcpy(&buffer[cpos],
"# ", 2);
181 sz = strlen(comment);
182 sz = sz < PAF_RECORD_MAX - cpos + 1 ? sz : PAF_RECORD_MAX - cpos + 1;
184 memcpy(&buffer[cpos], comment, sz);
189 buffer[++cpos] =
'\0';
192 if (append == TRUE) {
193 cx_string_append(line, buffer);
196 cx_string_set(line, buffer);
205 _giraffe_paf_convert_property(cx_string *line, cpl_property *property,
212 const cxchar *comment;
214 cx_string *value = NULL;
217 cx_assert(line != NULL);
219 if (property == NULL) {
223 value = cx_string_new();
225 switch (cpl_property_get_type(property)) {
228 cxchar c = cpl_property_get_char(property);
230 cx_string_sprintf(value,
"%c", c);
236 cxint b = cpl_property_get_bool(property);
239 cx_string_set(value,
"T");
242 cx_string_set(value,
"F");
249 cxint i = cpl_property_get_int(property);
251 cx_string_sprintf(value,
"%d", i);
257 cxlong l = cpl_property_get_long(property);
259 cx_string_sprintf(value,
"%ld", l);
265 cxfloat f = cpl_property_get_float(property);
267 cx_string_sprintf(value,
"%.15G", f);
269 if (!strchr(cx_string_get(value),
'.')) {
271 if (strchr(cx_string_get(value),
'E')) {
272 cx_string_sprintf(value,
"%.1E", f);
275 cx_string_append(value,
".");
281 case CPL_TYPE_DOUBLE:
283 cxdouble d = cpl_property_get_double(property);
285 cx_string_sprintf(value,
"%.15G", d);
287 if (!strchr(cx_string_get(value),
'.')) {
289 if (strchr(cx_string_get(value),
'E')) {
290 cx_string_sprintf(value,
"%.1E", d);
293 cx_string_append(value,
".");
299 case CPL_TYPE_STRING:
301 const cxchar *s = cpl_property_get_string(property);
303 cx_string_sprintf(value,
"\"%s\"", s);
314 cx_string_delete(value);
320 name = cpl_property_get_name(property);
321 comment = cpl_property_get_comment(property);
323 status = _giraffe_paf_format_line(line, name, cx_string_get(value),
327 cx_string_delete(value);
331 cx_string_delete(value);
338 inline static GiPafHdr *
339 _giraffe_pafhdr_create(
const cxchar *name,
const cxchar *type,
340 const cxchar *
id,
const cxchar *description)
343 GiPafHdr *
self = cx_calloc(1,
sizeof *
self);
346 self->name = cx_strdup(name);
347 self->type = cx_strdup(type);
350 self->id = cx_strdup(
id);
353 if (description != NULL) {
354 self->description = cx_strdup(description);
363 _giraffe_pafhdr_destroy(GiPafHdr *
self)
367 if (self->name != NULL) {
372 if (self->type != NULL) {
377 if (self->id != NULL) {
382 if (self->description != NULL) {
383 cx_free(self->description);
384 self->description = NULL;
396 _giraffe_pafhdr_write(GiPafHdr *
self, FILE *stream)
399 if (stream == NULL) {
408 cx_string *header = cx_string_new();
411 #if defined HAVE_GETUID && defined HAVE_GETPWUID
415 pw = getpwuid(getuid());
418 cx_string_delete(header);
425 user = getenv(
"USER");
426 user = user == NULL ? getenv(
"LOGNAME") : user;
429 cx_string_delete(header);
437 if (timestamp == NULL) {
438 cx_string_delete(header);
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);
451 if (self->id != NULL) {
452 _giraffe_paf_format_line(header, PAF_ID, self->id, NULL, TRUE);
455 _giraffe_paf_format_line(header, PAF_ID,
"", NULL, TRUE);
458 _giraffe_paf_format_line(header, PAF_NAME, self->name,
"Name of "
461 if (self->description != NULL) {
462 _giraffe_paf_format_line(header, PAF_DESC, self->description,
463 "Short description of PAF", TRUE);
466 _giraffe_paf_format_line(header, PAF_DESC,
"",
"Short "
467 "description of PAF", TRUE);
470 _giraffe_paf_format_line(header, PAF_CRTE_NAME, user,
"Name of "
472 _giraffe_paf_format_line(header, PAF_CRTE_TIME, timestamp,
473 "Civil time for creation", TRUE);
475 _giraffe_paf_format_line(header, PAF_LCHG_NAME,
"",
"Author of "
477 _giraffe_paf_format_line(header, PAF_LCHG_TIME,
"",
"Timestamp for "
478 "last change", TRUE);
480 _giraffe_paf_format_line(header, PAF_CHCK_NAME,
"",
"Name of appl. "
482 _giraffe_paf_format_line(header, PAF_CHCK_TIME,
"",
"Time for "
484 _giraffe_paf_format_line(header, PAF_CHCK_CHECKSUM,
"",
"Checksum "
485 "for the PAF", TRUE);
487 _giraffe_paf_format_line(header, PAF_HDR_END, NULL, NULL, TRUE);
494 fprintf(stream,
"%s", cx_string_get(header));
496 if (ferror(stream) != 0) {
498 cx_string_delete(header);
504 cx_string_delete(header);
513 giraffe_paf_new(
const cxchar *name,
const cxchar *type,
const cxchar *
id,
514 const cxchar *description)
520 if (name == NULL || type == NULL) {
524 self = cx_malloc(
sizeof *
self);
526 self->header = _giraffe_pafhdr_create(name, type,
id, description);
527 self->records = cpl_propertylist_new();
529 cx_assert(self->header != NULL);
530 cx_assert(self->records != NULL);
538 giraffe_paf_delete(GiPaf *
self)
542 if (self->records != NULL) {
543 cpl_propertylist_delete(self->records);
544 self->records = NULL;
547 if (self->header != NULL) {
548 _giraffe_pafhdr_destroy(self->header);
561 giraffe_paf_get_name(
const GiPaf *
self)
568 cx_assert(self->header != NULL);
569 cx_assert(self->header->name != NULL);
571 return self->header->name;
577 giraffe_paf_set_name(GiPaf *
self,
const cxchar *name)
580 cx_assert(
self != NULL);
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);
592 self->header->name = cx_strdup(name);
601 giraffe_paf_get_type(
const GiPaf *
self)
608 cx_assert(self->header != NULL);
609 cx_assert(self->header->type != NULL);
611 return self->header->type;
617 giraffe_paf_set_type(GiPaf *
self,
const cxchar *type)
620 cx_assert(
self != NULL);
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);
632 self->header->type = cx_strdup(type);
641 giraffe_paf_get_id(
const GiPaf *
self)
648 cx_assert(self->header != NULL);
650 return self->header->id;
656 giraffe_paf_set_id(GiPaf *
self,
const cxchar *
id)
659 cx_assert(
self != NULL);
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);
671 self->header->id = cx_strdup(
id);
680 giraffe_paf_get_description(
const GiPaf *
self)
687 cx_assert(self->header != NULL);
689 return self->header->description;
695 giraffe_paf_set_description(GiPaf *
self,
const cxchar *description)
698 cx_assert(
self != NULL);
700 if (description == NULL) {
704 if (self->header->description != NULL) {
705 self->header->description = cx_realloc(self->header->description,
706 (strlen(description) + 1) *
708 strcpy(self->header->description, description);
711 self->header->description = cx_strdup(description);
720 giraffe_paf_get_properties(
const GiPaf *
self)
727 cx_assert(self->records != NULL);
729 return self->records;
735 giraffe_paf_set_properties(GiPaf *
self,
const cpl_propertylist *properties)
738 cx_assert(
self != NULL);
740 if (properties == NULL) {
744 if (self->records != NULL) {
745 cpl_propertylist_delete(self->records);
748 self->records = cpl_propertylist_duplicate(properties);
756 giraffe_paf_write(
const GiPaf *
self)
768 cx_assert(self->header != NULL);
770 stream = fopen(giraffe_paf_get_name(
self),
"wb");
772 if (stream == NULL) {
781 status = _giraffe_pafhdr_write(self->header, stream);
795 if (self->records != NULL && !cpl_propertylist_is_empty(self->records)) {
797 cxchar buffer[PAF_RECORD_MAX];
801 cx_string *line = NULL;
805 memset(&buffer[1],
'-', 78);
807 fprintf(stream,
"%s\n", buffer);
809 if (ferror(stream) != 0) {
814 line = cx_string_new();
816 for (i = 0; i < cpl_propertylist_get_size(self->records); i++) {
818 cpl_property *p = cpl_propertylist_get(self->records, i);
821 status = _giraffe_paf_convert_property(line, p, FALSE);
824 cx_string_delete(line);
830 fprintf(stream,
"%s", cx_string_get(line));
832 if (ferror(stream) != 0) {
833 cx_string_delete(line);
840 cx_string_delete(line);
cxchar * giraffe_localtime_iso8601(void)
Get the current date and time in ISO 8601 format.