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 <string.h>
00035 #include <ctype.h>
00036 #include <unistd.h>
00037 #include <pwd.h>
00038 #include <sys/types.h>
00039 #include <time.h>
00040 #include <assert.h>
00041
00042 #include <cpl.h>
00043 #include <fors_paf.h>
00044
00045
00046
00047
00048
00049
00050 #define PAF_HDR_START "PAF.HDR.START"
00051 #define PAF_TYPE "PAF.TYPE"
00052 #define PAF_ID "PAF.ID"
00053 #define PAF_NAME "PAF.NAME"
00054 #define PAF_DESC "PAF.DESC"
00055 #define PAF_CRTE_NAME "PAF.CRTE.NAME"
00056 #define PAF_CRTE_TIME "PAF.CRTE.DAYTIM"
00057 #define PAF_LCHG_NAME "PAF.LCHG.NAME"
00058 #define PAF_LCHG_TIME "PAF.LCHG.DAYTIM"
00059 #define PAF_CHCK_NAME "PAF.CHCK.NAME"
00060 #define PAF_CHCK_TIME "PAF.CHCK.DAYTIM"
00061 #define PAF_CHCK_CHECKSUM "PAF.CHCK.CHECKSUM"
00062 #define PAF_HDR_END "PAF.HDR.END"
00063
00064
00065
00066
00067
00068
00069 #define PAF_FIELD_OFFSET_VALUE 20
00070 #define PAF_FIELD_OFFSET_COMMENT 45
00071
00072
00081
00082
00083
00084
00085 struct _FORS_PAF_RECORD_ {
00086 char *name;
00087 char *comment;
00088 ForsPAFType type;
00089
00090 union {
00091 int *bval;
00092 int *ival;
00093 double *dval;
00094 char *sval;
00095 } data;
00096 };
00097
00098 typedef struct _FORS_PAF_RECORD_ ForsPAFRecord;
00099
00100
00101
00102
00103
00104
00105 struct _FORS_PAF_ {
00106 char *name;
00107 int nh;
00108 int nr;
00109 ForsPAFRecord **header;
00110 ForsPAFRecord **records;
00111 };
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 #define TIME_ISO8601_LENGTH (20)
00125
00126 static char *getTimeISO8601(void)
00127 {
00128
00129 static char timeISO8601[TIME_ISO8601_LENGTH];
00130 time_t seconds = time((time_t *)0);
00131
00132 if (strftime(timeISO8601, TIME_ISO8601_LENGTH,
00133 "%Y-%m-%dT%T", localtime(&seconds)) == 0)
00134 strcpy(timeISO8601, "0000-00-00T00:00:00");
00135
00136 return timeISO8601;
00137
00138 }
00139
00140
00141
00142
00143
00144
00145 inline static size_t
00146 _forsPAFValueSize(ForsPAFType type, const void *value)
00147 {
00148 size_t sz;
00149
00150 switch (type) {
00151 case PAF_TYPE_BOOL:
00152 sz = sizeof(int);
00153 break;
00154
00155 case PAF_TYPE_INT:
00156 sz = sizeof(int);
00157 break;
00158
00159 case PAF_TYPE_DOUBLE:
00160 sz = sizeof(double);
00161 break;
00162
00163 case PAF_TYPE_STRING:
00164 sz = (strlen((char *)value) + 1) * sizeof(char);
00165 break;
00166
00167 default:
00168 sz = 0;
00169 break;
00170 }
00171
00172 return sz;
00173
00174 }
00175
00176
00177
00178
00179
00180
00181 inline static void
00182 _forsPAFRecordDestroy(ForsPAFRecord *record)
00183 {
00184
00185 if (record) {
00186 cpl_free(record->name);
00187 cpl_free((void *)record->data.sval);
00188 cpl_free(record->comment);
00189 cpl_free(record);
00190 }
00191
00192 return;
00193
00194 }
00195
00196
00197
00198
00199
00200
00201 inline static ForsPAFRecord *
00202 _forsPAFRecordCreate(const char *name, ForsPAFType type, const void *value,
00203 const char *comment)
00204 {
00205
00206 size_t sz;
00207
00208 ForsPAFRecord *record = cpl_malloc(sizeof(ForsPAFRecord));
00209
00210
00211 record->name = cpl_strdup(name);
00212 record->comment = comment ? cpl_strdup(comment) : NULL;
00213 record->type = type;
00214
00215 sz = _forsPAFValueSize(type, value);
00216
00217 if (sz == 0) {
00218 record->data.sval = NULL;
00219 }
00220 else {
00221 record->data.sval = (char *)cpl_malloc(sz);
00222 }
00223
00224 memcpy(record->data.sval, value, sz);
00225
00226 return record;
00227
00228 }
00229
00230
00231
00232
00233
00234 inline static void
00235 _forsPAFRecordSet(ForsPAFRecord *record, const char *name, ForsPAFType type,
00236 const void *value, const char *comment)
00237 {
00238
00239 if (name) {
00240 cpl_free(record->name);
00241 record->name = cpl_strdup(name);
00242 }
00243
00244 if (comment) {
00245 cpl_free(record->comment);
00246 record->comment = cpl_strdup(comment);
00247 }
00248
00249 if (value) {
00250 size_t sz = _forsPAFValueSize(type, value);
00251
00252 if (record->data.sval) {
00253 size_t size = _forsPAFValueSize(record->type, record->data.sval);
00254
00255 if (sz != size)
00256 record->data.sval = (char *)cpl_realloc(record->data.sval, sz);
00257 }
00258 else
00259 record->data.sval = (char *)cpl_malloc(sz);
00260
00261 memcpy(record->data.sval, value, sz);
00262 record->type = type;
00263 }
00264
00265 return;
00266
00267 }
00268
00269
00270
00271
00272
00273
00274
00275 inline static int
00276 _forsPAFAppend(ForsPAFRecord ***list, int *pos, const char *name,
00277 ForsPAFType type, const void *value, const char *comment)
00278 {
00279
00280 ForsPAFRecord *record;
00281
00282
00283 record = _forsPAFRecordCreate(name, type, value, comment);
00284 if (!record)
00285 return 1;
00286
00287 if (pos[0] == 0) {
00288 *list = cpl_malloc(sizeof(ForsPAFRecord *));
00289 }
00290 else {
00291 *list = cpl_realloc(*list, (pos[0]+1) * sizeof(ForsPAFRecord *));
00292 }
00293
00294 (*list)[pos[0]] = record;
00295 pos[0]++;
00296
00297 return 0;
00298
00299 }
00300
00301
00302
00303
00304
00305
00306 inline static ForsPAFRecord **
00307 _forsPAFHeaderCreate(const char *name, const char *type, const char *id,
00308 const char *desc, int *pos)
00309 {
00310
00311 ForsPAFRecord **hdr;
00312 const char *user, *timestamp;
00313 #if defined HAVE_GETUID && defined HAVE_GETPWUID
00314 struct passwd *pw;
00315 #endif
00316
00317
00318
00319 #if defined HAVE_GETUID && defined HAVE_GETPWUID
00320 pw = getpwuid(getuid());
00321
00322 if (!pw)
00323 return NULL;
00324
00325 user = pw->pw_name;
00326 #else
00327 user = getenv("USER");
00328 user = user == NULL ? getenv("LOGNAME") : user;
00329
00330 if (!user)
00331 return NULL;
00332 #endif
00333
00334
00335
00336 timestamp = getTimeISO8601();
00337
00338 pos[0] = 0;
00339
00340 _forsPAFAppend(&hdr, pos, PAF_HDR_START, PAF_TYPE_NONE, NULL, NULL);
00341 _forsPAFAppend(&hdr, pos, PAF_TYPE, PAF_TYPE_STRING, type,
00342 "Type of parameter file");
00343
00344 if (id) {
00345 _forsPAFAppend(&hdr, pos, PAF_ID, PAF_TYPE_STRING, id, NULL);
00346 }
00347 else {
00348 _forsPAFAppend(&hdr, pos, PAF_ID, PAF_TYPE_STRING, "", NULL);
00349 }
00350
00351 _forsPAFAppend(&hdr, pos, PAF_NAME, PAF_TYPE_STRING, name, "Name of PAF");
00352
00353 if (desc)
00354 _forsPAFAppend(&hdr, pos, PAF_DESC, PAF_TYPE_STRING, desc,
00355 "Short description of PAF");
00356 else
00357 _forsPAFAppend(&hdr, pos, PAF_DESC, PAF_TYPE_STRING, "",
00358 "Short description of PAF");
00359
00360 _forsPAFAppend(&hdr, pos, PAF_CRTE_NAME, PAF_TYPE_STRING, user,
00361 "Name of creator");
00362 _forsPAFAppend(&hdr, pos, PAF_CRTE_TIME, PAF_TYPE_STRING, timestamp,
00363 "Civil time for creation");
00364 _forsPAFAppend(&hdr, pos, PAF_LCHG_NAME, PAF_TYPE_STRING, user,
00365 "Author of par. file");
00366 _forsPAFAppend(&hdr, pos, PAF_LCHG_TIME, PAF_TYPE_STRING, timestamp,
00367 "Timestamp for last change");
00368 _forsPAFAppend(&hdr, pos, PAF_CHCK_NAME, PAF_TYPE_STRING, "",
00369 "Name of appl. checking");
00370 _forsPAFAppend(&hdr, pos, PAF_CHCK_TIME, PAF_TYPE_STRING, "",
00371 "Time for checking");
00372 _forsPAFAppend(&hdr, pos, PAF_CHCK_CHECKSUM, PAF_TYPE_STRING, "",
00373 "Checksum for the PAF");
00374 _forsPAFAppend(&hdr, pos, PAF_HDR_END, PAF_TYPE_NONE, NULL, NULL);
00375
00376 return hdr;
00377
00378 }
00379
00380
00381
00382
00383
00384
00385
00386 inline static const char *
00387 _forsPAFFormatRecord(ForsPAFRecord *record)
00388 {
00389
00390 static char buffer[PAF_RECORD_MAX + 1];
00391 char value[PAF_RECORD_MAX + 1];
00392
00393 int pos, sz;
00394
00395
00396 memset(buffer, ' ', PAF_RECORD_MAX);
00397
00398
00399
00400
00401
00402
00403
00404 if (strlen(record->name) + 1 > PAF_RECORD_MAX)
00405 return NULL;
00406
00407
00408
00409
00410
00411
00412 sz = strlen(record->name);
00413 strncpy(buffer, record->name, sz);
00414
00415 pos = sz;
00416 if (record->data.sval) {
00417 if (pos < PAF_FIELD_OFFSET_VALUE)
00418 pos = PAF_FIELD_OFFSET_VALUE;
00419 else
00420 pos++;
00421
00422 switch (record->type) {
00423 case PAF_TYPE_BOOL:
00424 snprintf(value, PAF_RECORD_MAX, "%c",
00425 *record->data.bval ? 'T' : 'F');
00426 break;
00427
00428 case PAF_TYPE_INT:
00429 snprintf(value, PAF_RECORD_MAX, "%d", *record->data.ival);
00430 break;
00431
00432 case PAF_TYPE_DOUBLE:
00433 snprintf(value, PAF_RECORD_MAX, "%.15G", *record->data.dval);
00434 if (!strchr(value, '.')) {
00435 if (strchr(value, 'E'))
00436 snprintf(value, PAF_RECORD_MAX, "%.1E",
00437 *record->data.dval);
00438 else
00439 strcat(value, ".");
00440 }
00441 break;
00442
00443 case PAF_TYPE_STRING:
00444 snprintf(value, PAF_RECORD_MAX, "\"%s\"", record->data.sval);
00445 break;
00446
00447 case PAF_TYPE_NONE:
00448
00449
00450
00451
00452
00453
00454 break;
00455 }
00456
00457 sz = strlen(value);
00458
00459
00460
00461
00462
00463 if (sz > PAF_RECORD_MAX - pos + 1)
00464 return NULL;
00465
00466 strncpy(&buffer[pos], value, sz);
00467 pos += sz;
00468 }
00469
00470 buffer[pos++] = ';';
00471
00472
00473
00474
00475
00476
00477
00478
00479 if (record->comment && (PAF_RECORD_MAX - pos) >= 2) {
00480 if (pos < PAF_FIELD_OFFSET_COMMENT)
00481 pos = PAF_FIELD_OFFSET_COMMENT;
00482 else
00483 pos++;
00484
00485 strncpy(&buffer[pos], "# ", 2);
00486 pos += 2;
00487 sz = strlen(record->comment);
00488 strncpy(&buffer[pos], record->comment, sz);
00489 pos += sz;
00490 }
00491
00492 buffer[pos] = '\0';
00493
00494 return buffer;
00495 }
00496
00497
00509 inline void deleteForsPAF(ForsPAF *paf)
00510 {
00511
00512 int i;
00513
00514 if (paf) {
00515 for (i = 0; i < paf->nh; i++)
00516 _forsPAFRecordDestroy(paf->header[i]);
00517 for (i = 0; i < paf->nr; i++)
00518 _forsPAFRecordDestroy(paf->records[i]);
00519 cpl_free(paf->header);
00520 cpl_free(paf->records);
00521 cpl_free(paf->name);
00522 cpl_free(paf);
00523 }
00524
00525 return;
00526
00527 }
00528
00529
00548 ForsPAF *newForsPAF(const char *name, const char *type, const char *id,
00549 const char *desc)
00550 {
00551
00552 ForsPAF *paf;
00553 int pos = 0;
00554
00555
00556 if (!name || !type)
00557 return NULL;
00558
00559 paf = (ForsPAF *)cpl_malloc(sizeof(ForsPAF));
00560 if (paf) {
00561 paf->header = _forsPAFHeaderCreate(name, type, id, desc, &pos);
00562 paf->records = NULL;
00563 paf->nh = pos;
00564 paf->nr = 0;
00565 paf->name = cpl_strdup(name);
00566 }
00567
00568 return paf;
00569
00570 }
00571
00572
00586 int
00587 forsPAFIsEmpty(const ForsPAF *paf)
00588 {
00589
00590 assert(paf != NULL);
00591
00592 return paf->nr == 0 ? 1 : 0;
00593
00594 }
00595
00596
00611 size_t forsPAFGetSize(const ForsPAF *paf)
00612 {
00613 assert(paf != NULL);
00614
00615 return (size_t)paf->nr;
00616
00617 }
00618
00619
00634 inline int
00635 forsPAFIsValidName(const char *name)
00636 {
00637
00638 register size_t i, sz;
00639
00640
00641 assert(name != NULL);
00642
00643 if (strchr(name, ' '))
00644 return 0;
00645
00646 sz = strlen(name);
00647 for (i = 0; i <sz; i++) {
00648 char c = name[i];
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 if (!(isupper)(c) && !(isdigit)(c) && c != '.' && c != '_' && c != '-')
00663 return 0;
00664 }
00665
00666 return 1;
00667
00668 }
00669
00670
00687 inline int
00688 forsPAFAppendBool(ForsPAF *paf, const char *name, int value, const char *comment)
00689 {
00690 assert(paf != NULL);
00691 assert(name != NULL);
00692
00693 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00694 return EXIT_FAILURE;
00695
00696 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_BOOL,
00697 &value, comment))
00698 return EXIT_FAILURE;
00699
00700 return EXIT_SUCCESS;
00701
00702 }
00703
00704
00721 inline int
00722 forsPAFAppendInt(ForsPAF *paf, const char *name, int value, const char *comment)
00723 {
00724
00725 assert(paf != NULL);
00726 assert(name != NULL);
00727
00728 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00729 return EXIT_FAILURE;
00730
00731 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_INT,
00732 &value, comment))
00733 return EXIT_FAILURE;
00734
00735 return EXIT_SUCCESS;
00736
00737 }
00738
00739
00756 inline int
00757 forsPAFAppendDouble(ForsPAF *paf, const char *name, double value,
00758 const char *comment)
00759 {
00760
00761 assert(paf != NULL);
00762 assert(name != NULL);
00763
00764 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00765 return EXIT_FAILURE;
00766
00767 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_DOUBLE,
00768 &value, comment))
00769 return EXIT_FAILURE;
00770
00771 return EXIT_SUCCESS;
00772
00773 }
00774
00775
00792 inline int
00793 forsPAFAppendString(ForsPAF *paf, const char *name, const char *value,
00794 const char *comment)
00795 {
00796
00797 assert(paf != NULL);
00798 assert(name != NULL);
00799
00800 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00801 return EXIT_FAILURE;
00802
00803 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_STRING,
00804 value, comment))
00805 return EXIT_FAILURE;
00806
00807 return EXIT_SUCCESS;
00808
00809 }
00810
00811
00826 int
00827 forsPAFWrite(ForsPAF *paf)
00828 {
00829
00830 const char *record;
00831 FILE *stream;
00832 int i;
00833
00834
00835 if (!paf)
00836 return EXIT_FAILURE;
00837
00838 assert(paf->header != NULL);
00839
00840
00841
00842
00843
00844
00845 stream = fopen(paf->name, "wb");
00846 if (!stream)
00847 return EXIT_FAILURE;
00848
00849
00850 for (i = 0; i < paf->nh; i++) {
00851 record = _forsPAFFormatRecord(paf->header[i]);
00852 if (!record) {
00853 fclose(stream);
00854 return EXIT_FAILURE;
00855 }
00856
00857 fprintf(stream, "%s\n", record);
00858 }
00859
00860
00861 if (paf->nr) {
00862 char buffer[PAF_RECORD_MAX];
00863
00864 buffer[0] = '#';
00865 memset(&buffer[1], '-', 78);
00866 buffer[79] = '\0';
00867 fprintf(stream, "%s\n", buffer);
00868 }
00869
00870 for (i = 0; i < paf->nr; i++) {
00871 record = _forsPAFFormatRecord(paf->records[i]);
00872 if (!record) {
00873 fclose(stream);
00874 return EXIT_FAILURE;
00875 }
00876
00877 fprintf(stream, "%s\n", record);
00878 }
00879
00880 fclose(stream);
00881
00882 return EXIT_SUCCESS;
00883
00884 }