IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ticket #506: psAdditionals.c

File psAdditionals.c, 14.7 KB (added by Paul Price, 21 years ago)

psAdditionals.c

Line 
1#include <stdio.h>
2#include <string.h>
3#include "pslib.h"
4#include "psAdditionals.h"
5
6psMetadata *psMetadataLookupMD(bool *status, const psMetadata *md, const char *key)
7{
8 psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
9 psMetadata *value = NULL; // The value to return
10 if (!item) {
11 // The given key isn't in the metadata
12 if (status) {
13 *status = false;
14 } else {
15 psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n");
16 }
17 } else if (item->type != PS_META_META) {
18 // The value at the key isn't metadata
19 if (status) {
20 *status = false;
21 } else {
22 psLogMsg(__func__, PS_LOG_WARN, "%s isn't of type PS_META_META, as expected.\n");
23 }
24 value = NULL;
25 } else {
26 // We have the requested metadata
27 if (status) {
28 *status = true;
29 }
30 value = item->data.md; // The requested metadata
31 }
32 return value;
33}
34
35
36char *psMetadataLookupString(bool *status, const psMetadata *md, const char *key)
37{
38 psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
39 char *value = NULL; // The value to return
40 if (!item) {
41 // The given key isn't in the metadata
42 if (status) {
43 *status = false;
44 } else {
45 psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n");
46 }
47 } else if (item->type != PS_META_STR) {
48 // The value at the key isn't of the desired type
49 if (status) {
50 *status = false;
51 } else {
52 psLogMsg(__func__, PS_LOG_WARN, "%s isn't of type PS_META_STR, as expected.\n");
53 }
54 value = NULL;
55 } else {
56 // We have the requested metadata
57 if (status) {
58 *status = true;
59 }
60 value = item->data.V; // The requested metadata
61 }
62 return value;
63}
64
65
66void psMetadataPrint(psMetadata *md, int level)
67{
68 psMetadataIterator *iter = psMetadataIteratorAlloc(md, PS_LIST_HEAD, NULL); // Iterator
69 psMetadataItem *item = NULL; // Item from metadata
70 while (item = psMetadataGetAndIncrement(iter)) {
71 // Indent...
72 for (int i = 0; i < level; i++) {
73 printf(" ");
74 }
75 printf("%s", item->name);
76 if (item->comment && strlen(item->comment) > 0) {
77 printf(" (%s)", item->comment);
78 }
79 printf(": ");
80 switch (item->type) {
81 case PS_META_STR:
82 printf("%s", item->data.V);
83 break;
84 case PS_META_BOOL:
85 if (item->data.B) {
86 printf("True");
87 } else {
88 printf("False");
89 }
90 break;
91 case PS_META_S32:
92 printf("%d", item->data.S32);
93 break;
94 case PS_META_F32:
95 printf("%f", item->data.F32);
96 break;
97 case PS_META_F64:
98 printf("%f", item->data.F64);
99 break;
100 case PS_META_META:
101 printf("\n");
102 psMetadataPrint(item->data.V, level + 1);
103 break;
104 default:
105 psError(PS_ERR_IO, false, "Non-printable metadata type: %x\n", item->type);
106 }
107 printf("\n");
108 }
109 psFree(iter);
110
111 return;
112}
113
114
115// Set verbosity level
116int psArgumentVerbosity(int *argc, char **argv)
117{
118 int logLevel = 2; // Default log level
119 int argnum = 0; // Argument number
120
121 // set in order, so that -vvv overrides -vv overrides -v
122 if (argnum = psArgumentGet(*argc, argv, "-v")) {
123 psArgumentRemove(argnum, argc, argv);
124 logLevel = 3;
125 }
126 if (argnum = psArgumentGet(*argc, argv, "-vv")) {
127 psArgumentRemove(argnum, argc, argv);
128 logLevel = 4;
129 }
130 if (argnum = psArgumentGet(*argc, argv, "-vvv")) {
131 psArgumentRemove(argnum, argc, argv);
132 logLevel = 5;
133 }
134 psLogSetLevel (logLevel); // XXX: This function should return an error if the log level is invalid
135
136 if (argnum = psArgumentGet(*argc, argv, "-logfmt")) {
137 if (*argc < argnum + 2) {
138 psError(PS_ERR_IO, true, "-logfmt switch specified without a format.");
139 } else {
140 psArgumentRemove(argnum, argc, argv);
141 psLogSetFormat(argv[argnum]); // XXX EAM : this function should return an error if the log format is invalid
142 psArgumentRemove(argnum, argc, argv);
143 }
144 }
145
146 // Now the trace stuff
147 // argument format is: -trace (facil) (level)
148 while (argnum = psArgumentGet(*argc, argv, "-trace")) {
149 if (*argc < argnum + 3) {
150 psError(PS_ERR_IO, true, "-trace switch specified without facility and level.");
151 }
152 psArgumentRemove(argnum, argc, argv);
153 psTraceSetLevel(argv[argnum], atoi(argv[argnum+1])); // XXX: This function should return an error if the trace level is invalid
154 psArgumentRemove(argnum, argc, argv);
155 psArgumentRemove(argnum, argc, argv);
156 }
157 if ((argnum = psArgumentGet(*argc, argv, "-trace-levels"))) {
158 psTracePrintLevels();
159 exit(2);
160 }
161
162 return logLevel;
163}
164
165// Find the location of the specified argument
166int psArgumentGet(int argc, char **argv, const char *arg)
167{
168 for (int i = 1; i < argc; i++) {
169 if (!strcmp(argv[i], arg))
170 return i;
171 }
172
173 return 0;
174}
175
176// Remove the specified argument (by location)
177bool psArgumentRemove(int argnum, int *argc, char **argv)
178{
179 if (argnum > 0) {
180 (*argc)--;
181 for (int i = argnum; i < *argc; i++) {
182 argv[i] = argv[i+1];
183 }
184 } else {
185 return false;
186 }
187
188 return true;
189}
190
191
192static psMetadataItem *argumentRead(psMetadataItem *item, // Item to read into
193 int argnum, // Argument number
194 int *argc, // Number of arguments in total
195 char **argv // The arguments
196 )
197{
198 psMetadataItem *newItem = NULL;
199 switch(item->type) {
200 // Only doing a representative set of types
201 case PS_META_S32:
202 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, atoi(argv[argnum]));
203 psArgumentRemove(argnum, argc, argv);
204 break;
205 case PS_META_F32:
206 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, atof(argv[argnum]));
207 psArgumentRemove(argnum, argc, argv);
208 break;
209 case PS_META_BOOL:
210 // Turn option on; no optional argument to remove
211 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, true);
212 break;
213 // XXX: Include the other numerical types
214 case PS_META_STR:
215 {
216 //psString string = psStringCopy(argv[argnum]); // Get the argument into PS memory management
217 //psFree(string);
218 newItem = psMetadataItemAlloc(item->name, item->type, item->comment, argv[argnum]);
219 psArgumentRemove(argnum, argc, argv);
220 }
221 break;
222 default:
223 psError(PS_ERR_IO, true, "Argument type (%x) is not supported --- argument %s ignored\n",
224 item->type, item->name);
225 psFree(newItem);
226 return NULL;
227 }
228
229 return newItem;
230}
231
232
233// XXX: There is a memory leak in the MULTI section. I think it might have something to do with reference
234// counting between lists and MD, in the second section of the code (copy newArgs into arguments), but I'm not
235// entirely sure.
236bool psArgumentParse(psMetadata *arguments, int *argc, char **argv)
237{
238 // We need to do a bit of mucking around in order to preserve the arguments metadata until the last
239 // minute --- if there is a bad argument, we need to return the old "arguments", since they contain
240 // the default values, which we probably want to output in a "help" message (we don't want to print
241 // the changed values and have the user think that they are default values).
242
243 psMetadata *newArgs = psMetadataAlloc(); // Place to read arguments into
244 psList *changed = psListAlloc(NULL);// List of keys that have changed
245
246 for (int i = 1; i < *argc; i++) {
247 psTrace(__func__, 7, "Looking at %s\n", argv[i]);
248 psMetadataItem *argItem = psMetadataLookup(arguments, argv[i]);
249 if (argItem) {
250 psArgumentRemove(i, argc, argv); // Remove the switch
251 if (argItem->type != PS_META_MULTI) {
252 if (argItem->type != PS_META_BOOL && *argc < i + 1) {
253 psError(PS_ERR_IO, true, "Required argument for %s is missing.\n", argItem->name);
254 // XXX: Cleanup before returning
255 psFree(newArgs);
256 return false;
257 }
258 psMetadataItem *newItem = argumentRead(argItem, i, argc, argv);
259 psMetadataAddItem(newArgs, newItem, PS_LIST_TAIL, PS_META_REPLACE);
260 psFree(newItem);
261 } else {
262 // Go through the MULTI
263 psList *multi = argItem->data.V; // The list of MULTI psMetadataItems
264 if (*argc < i + multi->size) {
265 psError(PS_ERR_IO, true, "Not enough arguments for %s.\n", argItem->name);
266 // Remove the arguments --- they will be ignored
267 for (int j = i; i < *argc; i++) {
268 psArgumentRemove(i, argc, argv);
269 }
270 // XXX: Cleanup before returning
271 psFree(newArgs);
272 return false;
273 }
274
275 // Remove any prior existence in the newArgs --- this is important because we specify
276 // adding the new items as DUPLICATE_OK, so if some idiot specifies it twice, we'd end
277 // up with two copies of everything.
278 psMetadataItem *checkItem = psMetadataLookup(newArgs, argItem->name);
279 if (checkItem) {
280 (void)psMetadataRemove(newArgs, 0, argItem->name);
281 (void)psListRemoveData(changed, argItem->name);
282 }
283
284 psListIterator *multiIter = psListIteratorAlloc(multi, PS_LIST_HEAD, true);
285 psMetadataItem *nextItem = NULL; // Item from list
286 while (nextItem = psListGetAndIncrement(multiIter)) {
287 psMetadataItem *newItem = argumentRead(nextItem, i, argc, argv);
288 psMetadataAddItem(newArgs, newItem, PS_LIST_TAIL, PS_META_DUPLICATE_OK);
289 //psFree(newItem);
290 }
291 psFree(multiIter);
292 }
293
294 // Some book-keeping
295 // psString name = psStringCopy(argItem->name);
296 psListAdd(changed, PS_LIST_TAIL, argItem->name);
297 i--;
298
299 } else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "+", 1) == 0) {
300 // Someone's specified a bad option
301 psError(PS_ERR_IO, true, "Unknown option: %s\n", argv[i]);
302 psFree(newArgs);
303 return false;
304 }
305 }
306
307 // All the arguments are good, so now we can copy the newArgs over
308 psListIterator *changedIter = psListIteratorAlloc(changed, PS_LIST_HEAD, false); // Iterator
309 psString name = NULL; // Item from iteration
310 while (name = psListGetAndIncrement(changedIter)) {
311 printf("Updating %s\n", name);
312 psMetadataItem *oldItem = psMetadataLookup(arguments, name);
313 psMetadataItem *newItem = psMetadataLookup(newArgs, name);
314 if (oldItem->type != newItem->type) {
315 psAbort(__func__, "Shouldn't reach here!\n");
316 }
317 switch (oldItem->type) {
318 // Only doing a representative set of types
319 case PS_META_S32:
320 oldItem->data.S32 = newItem->data.S32;
321 break;
322 case PS_META_F32:
323 oldItem->data.F32 = newItem->data.F32;
324 break;
325 case PS_META_BOOL:
326 oldItem->data.B = newItem->data.B;
327 break;
328 // XXX: Include the other numerical types
329 case PS_META_STR:
330 psFree(oldItem->data.V);
331 oldItem->data.V = psMemIncrRefCounter(newItem->data.V);
332 break;
333 case PS_META_MULTI:
334 {
335 psList *newMulti = psMemIncrRefCounter(newItem->data.V); // The new list of MULTI
336 psList *oldMulti = oldItem->data.V; // The old list of MULTI
337 psListIterator *newMultiIter = psListIteratorAlloc(newMulti, PS_LIST_HEAD, false);
338 psListIterator *oldMultiIter = psListIteratorAlloc(oldMulti, PS_LIST_HEAD, true);
339 psMetadataItem *newMultiItem = NULL; // Item from iterator
340 while (newMultiItem = psListGetAndIncrement(newMultiIter)) {
341 psMetadataItem *oldMultiItem = psListGetAndIncrement(oldMultiIter);
342 if (! oldMultiItem) {
343 psAbort(__func__,
344 "Something went very wrong here! The lists SHOULD be of the same length!\n");
345 }
346 switch (oldMultiItem->type) {
347 // Only doing a representative set of types
348 case PS_META_S32:
349 oldItem->data.S32 = newItem->data.S32;
350 break;
351 case PS_META_F32:
352 oldItem->data.F32 = newItem->data.F32;
353 break;
354 // XXX: Include the other numerical types
355 case PS_META_STR:
356 psFree(oldItem->data.V);
357 oldItem->data.V = psMemIncrRefCounter(newItem->data.V);
358 break;
359 default:
360 psAbort(__func__, "Should never ever get here, ever.\n");
361 }
362 psFree(oldMultiItem);
363 psFree(newMultiItem);
364 }
365 psFree(newMultiIter);
366 psFree(oldMultiIter);
367 }
368 break;
369 default:
370 psAbort(__func__, "Should never ever ever get here.\n");
371 }
372 }
373 psFree(changedIter);
374 psFree(changed);
375
376 // Now, blow away the newArgs and we're done.
377 psFree(newArgs);
378 return true;
379}
380
381
382static int argLength(psMetadataItem *arg)
383{
384 switch (arg->type) {
385 // Only doing a representative set of types
386 case PS_META_S32:
387 return arg->data.S32 >= 0 ? (int)log10f((float)arg->data.S32) + 1 :
388 (int)log10f(-(float)arg->data.S32) + 2;
389 // XXX: Other numerical types
390 case PS_META_F32:
391 return arg->data.F32 >= 0 ? 12 : 13; // -d.dddddde?dd
392 case PS_META_F64:
393 return arg->data.F64 >= 0 ? 12 : 13; // -d.dddddde?dd
394 case PS_META_BOOL:
395 return arg->data.B ? 4 : 5;
396 case PS_META_STR:
397 return strlen(arg->data.V);
398 default:
399 psAbort(__func__, "Argument type (%x) is not supported.\n", arg->type);
400 }
401
402 return 0;
403}
404
405#define NUM_SPACES 4 // Number of spaces between
406
407void psArgumentHelp(psMetadata *arguments)
408{
409 printf("Optional arguments, with default values:\n");
410 psMetadataIterator *argIter = psMetadataIteratorAlloc(arguments, PS_LIST_HEAD, NULL);
411 psMetadataItem *argItem = NULL; // Item from iterator
412 int maxName = 4; // Maximum length of a name
413 int maxValue = 4; // Maximum length of a value
414
415 // First pass to get the sizes
416 while (argItem = psMetadataGetAndIncrement(argIter)) {
417 if (strlen(argItem->name) > maxName) {
418 maxName = strlen(argItem->name);
419 }
420 int valLength = argLength(argItem);
421 if (valLength > maxValue) {
422 maxValue = valLength;
423 }
424 }
425
426 // Second pass to print
427 psMetadataIteratorSet(argIter, PS_LIST_HEAD);
428 psString lastName = NULL; // Last name we printed
429 while (argItem = psMetadataGetAndIncrement(argIter)) {
430 // Initial indent
431 for (int i = 0; i < NUM_SPACES; i++) {
432 printf(" ");
433 }
434
435 // Print the name if required
436 int position = 0; // Number of spaces in
437 if (! lastName || strcmp(lastName, argItem->name) != 0) {
438 // A new name
439 printf("%s", argItem->name);
440 position += strlen(argItem->name);
441 lastName = argItem->name;
442 }
443 for (int i = position; i < maxName + NUM_SPACES; i++) {
444 printf(" ");
445 }
446
447 // Print the value
448 printf("(");
449 switch (argItem->type) {
450 // Only doing a representative set of types
451 case PS_META_S32:
452 printf("%d", argItem->data.S32);
453 break;
454 // XXX: Other numerical types
455 case PS_META_F32:
456 printf("%.6e", argItem->data.F32);
457 break;
458 case PS_META_F64:
459 printf("%.6e", argItem->data.F64);
460 break;
461 case PS_META_BOOL:
462 if (argItem->data.B) {
463 printf("TRUE");
464 } else {
465 printf("FALSE");
466 }
467 break;
468 case PS_META_STR:
469 printf("%s", argItem->data.V);
470 break;
471 default:
472 psAbort(__func__, "Argument type (%x) is not supported.\n", argItem->type);
473 }
474 printf(")");
475 for (int i = argLength(argItem); i < maxValue + NUM_SPACES; i++) {
476 printf(" ");
477 }
478
479 // Print the comment
480 if (argItem->comment) {
481 printf("%s", argItem->comment);
482 }
483 printf("\n");
484 }
485
486 psFree(argIter);
487}