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 {
00332 return NULL;
00333 }
00334 #endif
00335
00336
00337
00338 timestamp = getTimeISO8601();
00339
00340 pos[0] = 0;
00341
00342 _forsPAFAppend(&hdr, pos, PAF_HDR_START, PAF_TYPE_NONE, NULL, NULL);
00343 _forsPAFAppend(&hdr, pos, PAF_TYPE, PAF_TYPE_STRING, type,
00344 "Type of parameter file");
00345
00346 if (id) {
00347 _forsPAFAppend(&hdr, pos, PAF_ID, PAF_TYPE_STRING, id, NULL);
00348 }
00349 else {
00350 _forsPAFAppend(&hdr, pos, PAF_ID, PAF_TYPE_STRING, "", NULL);
00351 }
00352
00353 _forsPAFAppend(&hdr, pos, PAF_NAME, PAF_TYPE_STRING, name, "Name of PAF");
00354
00355 if (desc)
00356 _forsPAFAppend(&hdr, pos, PAF_DESC, PAF_TYPE_STRING, desc,
00357 "Short description of PAF");
00358 else
00359 _forsPAFAppend(&hdr, pos, PAF_DESC, PAF_TYPE_STRING, "",
00360 "Short description of PAF");
00361
00362 _forsPAFAppend(&hdr, pos, PAF_CRTE_NAME, PAF_TYPE_STRING, user,
00363 "Name of creator");
00364 _forsPAFAppend(&hdr, pos, PAF_CRTE_TIME, PAF_TYPE_STRING, timestamp,
00365 "Civil time for creation");
00366 _forsPAFAppend(&hdr, pos, PAF_LCHG_NAME, PAF_TYPE_STRING, user,
00367 "Author of par. file");
00368 _forsPAFAppend(&hdr, pos, PAF_LCHG_TIME, PAF_TYPE_STRING, timestamp,
00369 "Timestamp for last change");
00370 _forsPAFAppend(&hdr, pos, PAF_CHCK_NAME, PAF_TYPE_STRING, "",
00371 "Name of appl. checking");
00372 _forsPAFAppend(&hdr, pos, PAF_CHCK_TIME, PAF_TYPE_STRING, "",
00373 "Time for checking");
00374 _forsPAFAppend(&hdr, pos, PAF_CHCK_CHECKSUM, PAF_TYPE_STRING, "",
00375 "Checksum for the PAF");
00376 _forsPAFAppend(&hdr, pos, PAF_HDR_END, PAF_TYPE_NONE, NULL, NULL);
00377
00378 return hdr;
00379
00380 }
00381
00382
00383
00384
00385
00386
00387
00388 inline static const char *
00389 _forsPAFFormatRecord(ForsPAFRecord *record)
00390 {
00391
00392 static char buffer[PAF_RECORD_MAX + 1];
00393 char value[PAF_RECORD_MAX + 1];
00394
00395 int pos, sz;
00396
00397
00398 memset(buffer, ' ', PAF_RECORD_MAX);
00399
00400
00401
00402
00403
00404
00405
00406 if (strlen(record->name) + 1 > PAF_RECORD_MAX)
00407 return NULL;
00408
00409
00410
00411
00412
00413
00414 sz = strlen(record->name);
00415 strncpy(buffer, record->name, sz);
00416
00417 pos = sz;
00418 if (record->data.sval) {
00419 if (pos < PAF_FIELD_OFFSET_VALUE)
00420 pos = PAF_FIELD_OFFSET_VALUE;
00421 else
00422 pos++;
00423
00424 switch (record->type) {
00425 case PAF_TYPE_BOOL:
00426 snprintf(value, PAF_RECORD_MAX, "%c",
00427 *record->data.bval ? 'T' : 'F');
00428 break;
00429
00430 case PAF_TYPE_INT:
00431 snprintf(value, PAF_RECORD_MAX, "%d", *record->data.ival);
00432 break;
00433
00434 case PAF_TYPE_DOUBLE:
00435 snprintf(value, PAF_RECORD_MAX, "%.15G", *record->data.dval);
00436 if (!strchr(value, '.')) {
00437 if (strchr(value, 'E'))
00438 snprintf(value, PAF_RECORD_MAX, "%.1E",
00439 *record->data.dval);
00440 else
00441 strcat(value, ".");
00442 }
00443 break;
00444
00445 case PAF_TYPE_STRING:
00446 snprintf(value, PAF_RECORD_MAX, "\"%s\"", record->data.sval);
00447 break;
00448
00449 case PAF_TYPE_NONE:
00450
00451
00452
00453
00454
00455
00456 break;
00457 }
00458
00459 sz = strlen(value);
00460
00461
00462
00463
00464
00465 if (sz > PAF_RECORD_MAX - pos + 1)
00466 return NULL;
00467
00468 strncpy(&buffer[pos], value, sz);
00469 pos += sz;
00470 }
00471
00472 buffer[pos++] = ';';
00473
00474
00475
00476
00477
00478
00479
00480
00481 if (record->comment && (PAF_RECORD_MAX - pos) >= 2) {
00482 if (pos < PAF_FIELD_OFFSET_COMMENT)
00483 pos = PAF_FIELD_OFFSET_COMMENT;
00484 else
00485 pos++;
00486
00487 strncpy(&buffer[pos], "# ", 2);
00488 pos += 2;
00489 sz = strlen(record->comment);
00490 strncpy(&buffer[pos], record->comment, sz);
00491 pos += sz;
00492 }
00493
00494 buffer[pos] = '\0';
00495
00496 return buffer;
00497 }
00498
00499
00511 inline void deleteForsPAF(ForsPAF *paf)
00512 {
00513
00514 int i;
00515
00516 if (paf) {
00517 for (i = 0; i < paf->nh; i++)
00518 _forsPAFRecordDestroy(paf->header[i]);
00519 for (i = 0; i < paf->nr; i++)
00520 _forsPAFRecordDestroy(paf->records[i]);
00521 cpl_free(paf->header);
00522 cpl_free(paf->records);
00523 cpl_free(paf->name);
00524 cpl_free(paf);
00525 }
00526
00527 return;
00528
00529 }
00530
00531
00550 ForsPAF *newForsPAF(const char *name, const char *type, const char *id,
00551 const char *desc)
00552 {
00553
00554 ForsPAF *paf;
00555 int pos = 0;
00556
00557
00558 if (!name || !type)
00559 return NULL;
00560
00561 paf = (ForsPAF *)cpl_malloc(sizeof(ForsPAF));
00562 if (paf) {
00563 paf->header = _forsPAFHeaderCreate(name, type, id, desc, &pos);
00564 if(paf->header == NULL)
00565 {
00566 cpl_free(paf);
00567 return NULL;
00568 }
00569 paf->records = NULL;
00570 paf->nh = pos;
00571 paf->nr = 0;
00572 paf->name = cpl_strdup(name);
00573 }
00574
00575 return paf;
00576
00577 }
00578
00579
00593 int
00594 forsPAFIsEmpty(const ForsPAF *paf)
00595 {
00596
00597 assert(paf != NULL);
00598
00599 return paf->nr == 0 ? 1 : 0;
00600
00601 }
00602
00603
00618 size_t forsPAFGetSize(const ForsPAF *paf)
00619 {
00620 assert(paf != NULL);
00621
00622 return (size_t)paf->nr;
00623
00624 }
00625
00626
00641 inline int
00642 forsPAFIsValidName(const char *name)
00643 {
00644
00645 register size_t i, sz;
00646
00647
00648 assert(name != NULL);
00649
00650 if (strchr(name, ' '))
00651 return 0;
00652
00653 sz = strlen(name);
00654 for (i = 0; i <sz; i++) {
00655 char c = name[i];
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669 if (!(isupper)(c) && !(isdigit)(c) && c != '.' && c != '_' && c != '-')
00670 return 0;
00671 }
00672
00673 return 1;
00674
00675 }
00676
00677
00694 inline int
00695 forsPAFAppendBool(ForsPAF *paf, const char *name, int value, const char *comment)
00696 {
00697 assert(paf != NULL);
00698 assert(name != NULL);
00699
00700 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00701 return EXIT_FAILURE;
00702
00703 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_BOOL,
00704 &value, comment))
00705 return EXIT_FAILURE;
00706
00707 return EXIT_SUCCESS;
00708
00709 }
00710
00711
00728 inline int
00729 forsPAFAppendInt(ForsPAF *paf, const char *name, int value, const char *comment)
00730 {
00731
00732 assert(paf != NULL);
00733 assert(name != NULL);
00734
00735 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00736 return EXIT_FAILURE;
00737
00738 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_INT,
00739 &value, comment))
00740 return EXIT_FAILURE;
00741
00742 return EXIT_SUCCESS;
00743
00744 }
00745
00746
00763 inline int
00764 forsPAFAppendDouble(ForsPAF *paf, const char *name, double value,
00765 const char *comment)
00766 {
00767
00768 assert(paf != NULL);
00769 assert(name != NULL);
00770
00771 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00772 return EXIT_FAILURE;
00773
00774 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_DOUBLE,
00775 &value, comment))
00776 return EXIT_FAILURE;
00777
00778 return EXIT_SUCCESS;
00779
00780 }
00781
00782
00799 inline int
00800 forsPAFAppendString(ForsPAF *paf, const char *name, const char *value,
00801 const char *comment)
00802 {
00803
00804 assert(paf != NULL);
00805 assert(name != NULL);
00806
00807 if (!forsPAFIsValidName(name) && name[0] != '#' && name [0] != '\0')
00808 return EXIT_FAILURE;
00809
00810 if (_forsPAFAppend(&(paf->records), &(paf->nr), name, PAF_TYPE_STRING,
00811 value, comment))
00812 return EXIT_FAILURE;
00813
00814 return EXIT_SUCCESS;
00815
00816 }
00817
00818
00833 int
00834 forsPAFWrite(ForsPAF *paf)
00835 {
00836
00837 const char *record;
00838 FILE *stream;
00839 int i;
00840
00841
00842 if (!paf)
00843 return EXIT_FAILURE;
00844
00845 assert(paf->header != NULL);
00846
00847
00848
00849
00850
00851
00852 stream = fopen(paf->name, "wb");
00853 if (!stream)
00854 return EXIT_FAILURE;
00855
00856
00857 for (i = 0; i < paf->nh; i++) {
00858 record = _forsPAFFormatRecord(paf->header[i]);
00859 if (!record) {
00860 fclose(stream);
00861 return EXIT_FAILURE;
00862 }
00863
00864 fprintf(stream, "%s\n", record);
00865 }
00866
00867
00868 if (paf->nr) {
00869 char buffer[PAF_RECORD_MAX];
00870
00871 buffer[0] = '#';
00872 memset(&buffer[1], '-', 78);
00873 buffer[79] = '\0';
00874 fprintf(stream, "%s\n", buffer);
00875 }
00876
00877 for (i = 0; i < paf->nr; i++) {
00878 record = _forsPAFFormatRecord(paf->records[i]);
00879 if (!record) {
00880 fclose(stream);
00881 return EXIT_FAILURE;
00882 }
00883
00884 fprintf(stream, "%s\n", record);
00885 }
00886
00887 fclose(stream);
00888
00889 return EXIT_SUCCESS;
00890
00891 }