00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <pwd.h>
00035 #if defined HAVE_SYS_TYPES_H
00036 # include <sys/types.h>
00037 #endif
00038
00039 #include <cxmemory.h>
00040 #include <cxstring.h>
00041 #include <cxstrutils.h>
00042
00043 #include <cpl_propertylist.h>
00044
00045 #include "giutils.h"
00046 #include "gipaf.h"
00047
00048
00049 #define PAF_HDR_START "PAF.HDR.START"
00050 #define PAF_TYPE "PAF.TYPE"
00051 #define PAF_ID "PAF.ID"
00052 #define PAF_NAME "PAF.NAME"
00053 #define PAF_DESC "PAF.DESC"
00054 #define PAF_CRTE_NAME "PAF.CRTE.NAME"
00055 #define PAF_CRTE_TIME "PAF.CRTE.DAYTIM"
00056 #define PAF_LCHG_NAME "PAF.LCHG.NAME"
00057 #define PAF_LCHG_TIME "PAF.LCHG.DAYTIM"
00058 #define PAF_CHCK_NAME "PAF.CHCK.NAME"
00059 #define PAF_CHCK_TIME "PAF.CHCK.DAYTIM"
00060 #define PAF_CHCK_CHECKSUM "PAF.CHCK.CHECKSUM"
00061 #define PAF_HDR_END "PAF.HDR.END"
00062
00063
00064
00065
00066
00067
00068 static const cxsize PAF_FIELD_OFFSET_VALUE = 20;
00069 static const cxsize PAF_FIELD_OFFSET_COMMENT = 45;
00070
00071
00072
00073
00074
00075
00076
00077
00078 static const cxsize PAF_RECORD_MAX = 256;
00079
00080
00089 struct GiPafHdr {
00090 cxchar *name;
00091 cxchar *type;
00092 cxchar *id;
00093 cxchar *description;
00094 };
00095
00096 typedef struct GiPafHdr GiPafHdr;
00097
00098
00099 struct GiPaf {
00100 GiPafHdr *header;
00101 cpl_propertylist *records;
00102 };
00103
00104
00105 inline static cxint
00106 _giraffe_paf_format_line(cx_string *line, const cxchar *name,
00107 const cxchar *value, const cxchar *comment,
00108 cxbool append)
00109 {
00110
00111 cxchar buffer[PAF_RECORD_MAX + 2];
00112
00113 cxsize sz = 0;
00114 cxsize cpos = 0;
00115
00116
00117 cx_assert(line != NULL);
00118
00119 if (name == NULL) {
00120 return -1;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129 sz = strlen(name);
00130
00131 if (sz + 1 > PAF_RECORD_MAX) {
00132 return 1;
00133 }
00134
00135 memset(buffer, ' ', PAF_RECORD_MAX + 1);
00136 memcpy(buffer, name, sz);
00137
00138 cpos = sz;
00139
00140 if (value != NULL) {
00141
00142 if (cpos < PAF_FIELD_OFFSET_VALUE) {
00143 cpos = PAF_FIELD_OFFSET_VALUE;
00144 }
00145 else {
00146 ++cpos;
00147 }
00148
00149 sz = strlen(value);
00150
00151
00152
00153
00154
00155
00156
00157 if (sz > PAF_RECORD_MAX - cpos + 1) {
00158 return 2;
00159 }
00160
00161 memcpy(&buffer[cpos], value, sz);
00162 cpos += sz;
00163
00164 }
00165
00166 buffer[cpos++] = ';';
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 if (comment != NULL && comment[0] != '\0' &&
00177 (PAF_RECORD_MAX - cpos + 1) > 2) {
00178
00179 if (cpos < PAF_FIELD_OFFSET_COMMENT) {
00180 cpos = PAF_FIELD_OFFSET_COMMENT;
00181 }
00182 else {
00183 ++cpos;
00184 }
00185
00186 memcpy(&buffer[cpos], "# ", 2);
00187 cpos += 2;
00188
00189 sz = strlen(comment);
00190 sz = sz < PAF_RECORD_MAX - cpos + 1 ? sz : PAF_RECORD_MAX - cpos + 1;
00191
00192 memcpy(&buffer[cpos], comment, sz);
00193 cpos += sz;
00194 }
00195
00196 buffer[cpos] = '\n';
00197 buffer[++cpos] = '\0';
00198
00199
00200 if (append == TRUE) {
00201 cx_string_append(line, buffer);
00202 }
00203 else {
00204 cx_string_set(line, buffer);
00205 }
00206
00207 return 0;
00208
00209 }
00210
00211
00212 inline static cxint
00213 _giraffe_paf_convert_property(cx_string *line, cpl_property *property,
00214 cxbool append)
00215 {
00216
00217 cxint status = 0;
00218
00219 const cxchar *name;
00220 const cxchar *comment;
00221
00222 cx_string *value = NULL;
00223
00224
00225 cx_assert(line != NULL);
00226
00227 if (property == NULL) {
00228 return -1;
00229 }
00230
00231 value = cx_string_new();
00232
00233 switch (cpl_property_get_type(property)) {
00234 case CPL_TYPE_CHAR:
00235 {
00236 cxchar c = cpl_property_get_char(property);
00237
00238 cx_string_sprintf(value, "%c", c);
00239 }
00240 break;
00241
00242 case CPL_TYPE_BOOL:
00243 {
00244 cxint b = cpl_property_get_bool(property);
00245
00246 if (b != 0) {
00247 cx_string_set(value, "T");
00248 }
00249 else {
00250 cx_string_set(value, "F");
00251 }
00252 }
00253 break;
00254
00255 case CPL_TYPE_INT:
00256 {
00257 cxint i = cpl_property_get_int(property);
00258
00259 cx_string_sprintf(value, "%d", i);
00260 }
00261 break;
00262
00263 case CPL_TYPE_LONG:
00264 {
00265 cxlong l = cpl_property_get_long(property);
00266
00267 cx_string_sprintf(value, "%ld", l);
00268 }
00269 break;
00270
00271 case CPL_TYPE_FLOAT:
00272 {
00273 cxfloat f = cpl_property_get_float(property);
00274
00275 cx_string_sprintf(value, "%.15G", f);
00276
00277 if (!strchr(cx_string_get(value), '.')) {
00278
00279 if (strchr(cx_string_get(value), 'E')) {
00280 cx_string_sprintf(value, "%.1E", f);
00281 }
00282 else {
00283 cx_string_append(value, ".");
00284 }
00285 }
00286 }
00287 break;
00288
00289 case CPL_TYPE_DOUBLE:
00290 {
00291 cxdouble d = cpl_property_get_double(property);
00292
00293 cx_string_sprintf(value, "%.15G", d);
00294
00295 if (!strchr(cx_string_get(value), '.')) {
00296
00297 if (strchr(cx_string_get(value), 'E')) {
00298 cx_string_sprintf(value, "%.1E", d);
00299 }
00300 else {
00301 cx_string_append(value, ".");
00302 }
00303 }
00304 }
00305 break;
00306
00307 case CPL_TYPE_STRING:
00308 {
00309 const cxchar *s = cpl_property_get_string(property);
00310
00311 cx_string_sprintf(value, "\"%s\"", s);
00312 }
00313 break;
00314
00315 default:
00316
00317
00318
00319
00320
00321
00322 cx_string_delete(value);
00323
00324 return 1;
00325 break;
00326 }
00327
00328 name = cpl_property_get_name(property);
00329 comment = cpl_property_get_comment(property);
00330
00331 status = _giraffe_paf_format_line(line, name, cx_string_get(value),
00332 comment, append);
00333
00334 if (status != 0) {
00335 cx_string_delete(value);
00336 return 2;
00337 }
00338
00339 cx_string_delete(value);
00340
00341 return 0;
00342
00343 }
00344
00345
00346 inline static GiPafHdr *
00347 _giraffe_pafhdr_create(const cxchar *name, const cxchar *type,
00348 const cxchar *id, const cxchar *description)
00349 {
00350
00351 GiPafHdr *self = cx_calloc(1, sizeof *self);
00352
00353
00354 self->name = cx_strdup(name);
00355 self->type = cx_strdup(type);
00356
00357 if (id != NULL) {
00358 self->id = cx_strdup(id);
00359 }
00360
00361 if (description != NULL) {
00362 self->description = cx_strdup(description);
00363 }
00364
00365 return self;
00366
00367 }
00368
00369
00370 inline static void
00371 _giraffe_pafhdr_destroy(GiPafHdr *self)
00372 {
00373
00374 if (self != NULL) {
00375 if (self->name != NULL) {
00376 cx_free(self->name);
00377 self->name = NULL;
00378 }
00379
00380 if (self->type != NULL) {
00381 cx_free(self->type);
00382 self->type = NULL;
00383 }
00384
00385 if (self->id != NULL) {
00386 cx_free(self->id);
00387 self->id = NULL;
00388 }
00389
00390 if (self->description != NULL) {
00391 cx_free(self->description);
00392 self->description = NULL;
00393 }
00394
00395 cx_free(self);
00396 }
00397
00398 return;
00399
00400 }
00401
00402
00403 inline static cxint
00404 _giraffe_pafhdr_write(GiPafHdr *self, FILE *stream)
00405 {
00406
00407 if (stream == NULL) {
00408 return -1;
00409 }
00410
00411 if (self != NULL) {
00412
00413 cxchar *user;
00414 cxchar *timestamp;
00415
00416 cx_string *header = cx_string_new();
00417
00418
00419 #if defined HAVE_GETUID && defined HAVE_GETPWUID
00420
00421 struct passwd *pw;
00422
00423 pw = getpwuid(getuid());
00424
00425 if (pw == NULL) {
00426 cx_string_delete(header);
00427 return 1;
00428 }
00429
00430 user = pw->pw_name;
00431
00432 #else
00433 user = getenv("USER");
00434 user = user == NULL ? getenv("LOGNAME") : user;
00435
00436 if (user == NULL) {
00437 cx_string_delete(header);
00438 return 1;
00439 }
00440
00441 #endif
00442
00443 timestamp = giraffe_localtime_iso8601();
00444
00445 if (timestamp == NULL) {
00446 cx_string_delete(header);
00447 return 2;
00448 }
00449
00450
00451
00452
00453
00454
00455 _giraffe_paf_format_line(header, PAF_HDR_START, NULL, NULL, TRUE);
00456 _giraffe_paf_format_line(header, PAF_TYPE, self->type, "Type of "
00457 "parameter file", TRUE);
00458
00459 if (self->id != NULL) {
00460 _giraffe_paf_format_line(header, PAF_ID, self->id, NULL, TRUE);
00461 }
00462 else {
00463 _giraffe_paf_format_line(header, PAF_ID, "", NULL, TRUE);
00464 }
00465
00466 _giraffe_paf_format_line(header, PAF_NAME, self->name, "Name of "
00467 "PAF", TRUE);
00468
00469 if (self->description != NULL) {
00470 _giraffe_paf_format_line(header, PAF_DESC, self->description,
00471 "Short description of PAF", TRUE);
00472 }
00473 else {
00474 _giraffe_paf_format_line(header, PAF_DESC, "", "Short "
00475 "description of PAF", TRUE);
00476 }
00477
00478 _giraffe_paf_format_line(header, PAF_CRTE_NAME, user, "Name of "
00479 "creator", TRUE);
00480 _giraffe_paf_format_line(header, PAF_CRTE_TIME, timestamp,
00481 "Civil time for creation", TRUE);
00482
00483 _giraffe_paf_format_line(header, PAF_LCHG_NAME, "", "Author of "
00484 "par. file", TRUE);
00485 _giraffe_paf_format_line(header, PAF_LCHG_TIME, "", "Timestamp for "
00486 "last change", TRUE);
00487
00488 _giraffe_paf_format_line(header, PAF_CHCK_NAME, "", "Name of appl. "
00489 "checking", TRUE);
00490 _giraffe_paf_format_line(header, PAF_CHCK_TIME, "", "Time for "
00491 "checking", TRUE);
00492 _giraffe_paf_format_line(header, PAF_CHCK_CHECKSUM, "", "Checksum "
00493 "for the PAF", TRUE);
00494
00495 _giraffe_paf_format_line(header, PAF_HDR_END, NULL, NULL, TRUE);
00496
00497
00498
00499
00500
00501
00502 fprintf(stream, "%s", cx_string_get(header));
00503
00504 if (ferror(stream) != 0) {
00505 cx_free(timestamp);
00506 cx_string_delete(header);
00507
00508 return 3;
00509 }
00510
00511 cx_free(timestamp);
00512 cx_string_delete(header);
00513 }
00514
00515 return 0;
00516
00517 }
00518
00519
00520 GiPaf *
00521 giraffe_paf_new(const cxchar *name, const cxchar *type, const cxchar *id,
00522 const cxchar *description)
00523 {
00524
00525 GiPaf *self = NULL;
00526
00527
00528 if (name == NULL || type == NULL) {
00529 return NULL;
00530 }
00531
00532 self = cx_malloc(sizeof *self);
00533
00534 self->header = _giraffe_pafhdr_create(name, type, id, description);
00535 self->records = cpl_propertylist_new();
00536
00537 cx_assert(self->header != NULL);
00538 cx_assert(self->records != NULL);
00539
00540 return self;
00541
00542 }
00543
00544
00545 void
00546 giraffe_paf_delete(GiPaf *self)
00547 {
00548
00549 if (self != NULL) {
00550 if (self->records != NULL) {
00551 cpl_propertylist_delete(self->records);
00552 self->records = NULL;
00553 }
00554
00555 if (self->header != NULL) {
00556 _giraffe_pafhdr_destroy(self->header);
00557 self->header = NULL;
00558 }
00559
00560 cx_free(self);
00561 }
00562
00563 return;
00564
00565 }
00566
00567
00568 cxchar *
00569 giraffe_paf_get_name(const GiPaf *self)
00570 {
00571
00572 if (self == NULL) {
00573 return NULL;
00574 }
00575
00576 cx_assert(self->header != NULL);
00577 cx_assert(self->header->name != NULL);
00578
00579 return self->header->name;
00580
00581 }
00582
00583
00584 cxint
00585 giraffe_paf_set_name(GiPaf *self, const cxchar *name)
00586 {
00587
00588 cx_assert(self != NULL);
00589
00590 if (name == NULL) {
00591 return -1;
00592 }
00593
00594 if (self->header->name != NULL) {
00595 self->header->name = cx_realloc(self->header->name,
00596 (strlen(name) + 1) * sizeof(cxchar));
00597 strcpy(self->header->name, name);
00598 }
00599 else {
00600 self->header->name = cx_strdup(name);
00601 }
00602
00603 return 0;
00604
00605 }
00606
00607
00608 cxchar *
00609 giraffe_paf_get_type(const GiPaf *self)
00610 {
00611
00612 if (self == NULL) {
00613 return NULL;
00614 }
00615
00616 cx_assert(self->header != NULL);
00617 cx_assert(self->header->type != NULL);
00618
00619 return self->header->type;
00620
00621 }
00622
00623
00624 cxint
00625 giraffe_paf_set_type(GiPaf *self, const cxchar *type)
00626 {
00627
00628 cx_assert(self != NULL);
00629
00630 if (type == NULL) {
00631 return -1;
00632 }
00633
00634 if (self->header->type != NULL) {
00635 self->header->type = cx_realloc(self->header->type,
00636 (strlen(type) + 1) * sizeof(cxchar));
00637 strcpy(self->header->type, type);
00638 }
00639 else {
00640 self->header->type = cx_strdup(type);
00641 }
00642
00643 return 0;
00644
00645 }
00646
00647
00648 cxchar *
00649 giraffe_paf_get_id(const GiPaf *self)
00650 {
00651
00652 if (self == NULL) {
00653 return NULL;
00654 }
00655
00656 cx_assert(self->header != NULL);
00657
00658 return self->header->id;
00659
00660 }
00661
00662
00663 cxint
00664 giraffe_paf_set_id(GiPaf *self, const cxchar *id)
00665 {
00666
00667 cx_assert(self != NULL);
00668
00669 if (id == NULL) {
00670 return -1;
00671 }
00672
00673 if (self->header->id != NULL) {
00674 self->header->id = cx_realloc(self->header->id,
00675 (strlen(id) + 1) * sizeof(cxchar));
00676 strcpy(self->header->id, id);
00677 }
00678 else {
00679 self->header->id = cx_strdup(id);
00680 }
00681
00682 return 0;
00683
00684 }
00685
00686
00687 cxchar *
00688 giraffe_paf_get_description(const GiPaf *self)
00689 {
00690
00691 if (self == NULL) {
00692 return NULL;
00693 }
00694
00695 cx_assert(self->header != NULL);
00696
00697 return self->header->description;
00698
00699 }
00700
00701
00702 cxint
00703 giraffe_paf_set_description(GiPaf *self, const cxchar *description)
00704 {
00705
00706 cx_assert(self != NULL);
00707
00708 if (description == NULL) {
00709 return -1;
00710 }
00711
00712 if (self->header->description != NULL) {
00713 self->header->description = cx_realloc(self->header->description,
00714 (strlen(description) + 1) *
00715 sizeof(cxchar));
00716 strcpy(self->header->description, description);
00717 }
00718 else {
00719 self->header->description = cx_strdup(description);
00720 }
00721
00722 return 0;
00723
00724 }
00725
00726
00727 cpl_propertylist *
00728 giraffe_paf_get_properties(const GiPaf *self)
00729 {
00730
00731 if (self == NULL) {
00732 return NULL;
00733 }
00734
00735 cx_assert(self->records != NULL);
00736
00737 return self->records;
00738
00739 }
00740
00741
00742 cxint
00743 giraffe_paf_set_properties(GiPaf *self, const cpl_propertylist *properties)
00744 {
00745
00746 cx_assert(self != NULL);
00747
00748 if (properties == NULL) {
00749 return -1;
00750 }
00751
00752 if (self->records != NULL) {
00753 cpl_propertylist_delete(self->records);
00754 }
00755
00756 self->records = cpl_propertylist_duplicate(properties);
00757
00758 return 0;
00759
00760 }
00761
00762
00763 cxint
00764 giraffe_paf_write(const GiPaf *self)
00765 {
00766
00767 cxint status = 0;
00768
00769 FILE *stream = NULL;
00770
00771
00772 if (self == NULL) {
00773 return -1;
00774 }
00775
00776 cx_assert(self->header != NULL);
00777
00778 stream = fopen(giraffe_paf_get_name(self), "wb");
00779
00780 if (stream == NULL) {
00781 return 1;
00782 }
00783
00784
00785
00786
00787
00788
00789 status = _giraffe_pafhdr_write(self->header, stream);
00790
00791 if (status != 0) {
00792 fclose(stream);
00793 return 2;
00794 }
00795
00796 fflush(stream);
00797
00798
00799
00800
00801
00802
00803 if (self->records != NULL && !cpl_propertylist_is_empty(self->records)) {
00804
00805 cxchar buffer[PAF_RECORD_MAX];
00806
00807 register cxlong i;
00808
00809 cx_string *line = NULL;
00810
00811
00812 buffer[0] = '#';
00813 memset(&buffer[1], '-', 78);
00814 buffer[79] = '\0';
00815 fprintf(stream, "%s\n", buffer);
00816
00817 if (ferror(stream) != 0) {
00818 fclose(stream);
00819 return 3;
00820 }
00821
00822 line = cx_string_new();
00823
00824 for (i = 0; i < cpl_propertylist_get_size(self->records); i++) {
00825
00826 cpl_property *p = cpl_propertylist_get(self->records, i);
00827
00828
00829 status = _giraffe_paf_convert_property(line, p, FALSE);
00830
00831 if (status != 0) {
00832 cx_string_delete(line);
00833 fclose(stream);
00834
00835 return 4;
00836 }
00837
00838 fprintf(stream, "%s", cx_string_get(line));
00839
00840 if (ferror(stream) != 0) {
00841 cx_string_delete(line);
00842 fclose(stream);
00843
00844 return 5;
00845 }
00846 }
00847
00848 cx_string_delete(line);
00849 fflush(stream);
00850
00851 }
00852
00853 fclose(stream);
00854
00855 return 0;
00856
00857 }