1
/* $Id: er_paramutils.c,v 1.39 2010/04/27 17:11:48 cgarcia Exp $
3
* This file is part of the ESO Common Pipeline Library
4
* Copyright (C) 2001-2004 European Southern Observatory
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
* $Date: 2010/04/27 17:11:48 $
25
* $Name: esorex-3_9_0 $
41
#include "er_plugin.h"
42
#include "er_paramutils.h"
43
#include "er_stringutils.h"
46
#define MAXSTR MAXSTRLENCONF - 4
49
* @defgroup er_params_utils EsoRex Parameter Utility Functions
51
* EsoRex Parameter Utility Functions
57
/**********************************************************************/
59
* @brief Replaces any tilde in parameters within a parameter list.
61
* @param param_list List of Parameters
65
* Function searches @em param_list for parameters whose values begin
66
* with a tilde (~) and if found, replace the tilde with the user's
67
* home directory (using the $HOME environment variable).
70
/**********************************************************************/
72
void er_paramutils_tilde_convert (cpl_parameterlist * param_list)
75
cpl_parameter *p = NULL;
78
int f_is_present = 0; /* FALSE */
80
const char *old_str = NULL;
87
p = cpl_parameterlist_get_first (param_list);
91
f_is_present = cpl_parameter_get_default_flag (p);
95
ptype = cpl_parameter_get_type (p);
96
if (ptype == CPL_TYPE_STRING)
98
old_str = cpl_parameter_get_string (p);
104
/* use C library (glibc) routine wordexp() to expand ~/ or ~name/ */
106
if (wordexp(old_str,&result,0) != 0)
108
cpl_msg_error (er_func, "Expansion of ~ (tilde) failed...");
112
cpp = *result.we_wordv; /* use 1st and only result word */
115
cpl_msg_error (er_func, "Env. variable HOME not set");
119
cpl_parameter_set_string (p, cpp);
125
/* Get the next parameter in the list */
126
p = cpl_parameterlist_get_next (param_list);
127
} /* End of loop through all parameters in the list */
134
/**********************************************************************/
136
* @brief Neatly print a parameter and its description.
138
* @param flag_prefix This is the prefix used to flag certain types of
139
* switches/parameters. For example a double hypen
140
* "--" may be used before the long form of command
142
* @param keyword This is the keyword itself. It is appended to the
143
* flag-prefix, if any.
144
* @param description This is the descriptive text that follows the
145
* keyword. It is put at a tab-stop, so that all the
146
* descriptions are neatly aligned.
148
* This function neatly prints a keyword and its associated description
149
* to the normal output channel. The formatting is handled automatically
150
* to get neat alignment of the output.
152
/**********************************************************************/
154
void er_paramutils_print_key_desc
155
(const char *flag_prefix, const char *keyword, const char *description)
158
int i, ii, tab = COMMENT_TAB_POSITION;
160
char *mystr, *ptr, *mykeyword;
166
mystr = (char *) cpl_malloc((size_t) SIZE_X);
169
cpl_msg_warning (er_func,
170
"Could not allocate initial %d bytes for help description",
175
/* store the indent, optional flag ("--") and keyword */
177
i = (int) strlen(flag_prefix);
178
ii = (int) strlen(keyword);
179
if ((i+ii) > (SIZE_X-4))
181
cpl_msg_warning (er_func,
182
"Size of keyword (= %d) too large - will be truncated...",ii);
183
mykeyword = (char *) cpl_malloc((size_t) SIZE_X);
184
(void) strncpy(mykeyword,keyword,(SIZE_X-6));
185
mykeyword[SIZE_X-6] = '\0';
188
mykeyword = (char *) keyword;
190
i = sprintf(mystr," %s%s",flag_prefix,mykeyword);
191
if (tab < i) tab = i + 2; /* if keyword quite long, move the tab */
194
/* pad out to the tab-point, then append ": " */
197
for (ii = i; ii < tab; ii++) *ptr++ = ' ';
203
/* append description */
205
i = tab + (int) strlen(description) + 2;
208
er_enlarge("paramutils_print_key_desc",&mystr,i);
210
(void) strcpy(mystr+tab, description); /* append full description */
213
/* finally, print the nicely wrapped string */
215
(void) printf ("%s\n",er_strutils_split(mystr,tab,er_strutils_termwidth()));
223
/**********************************************************************/
225
* @brief Manage buffer of sources of all used parameters (Esorex + recipes)
227
* @param flag Control flag:
228
* = 1, for given param. save source in internal buffer
229
* = 2, for given param. pull out source from internal buffer
230
* = 3, free allocated memory
231
* @param name Name of parameter
232
* @param source desription of source of a param.
233
* maybe "default", config-file name, "command line", etc
235
* This function manages a buffer of sources of all used parameters
236
* in Esorex + all called recipes.
237
* Max MAX_SRC can be handled, i.e. for at most MAX_SRC different params.
238
* Esorex has already 23 parameters...
239
* Max length of parameter name is PAR_LEN chars.
241
/**********************************************************************/
243
int er_manage_sources(const int flag, const char *name, char **source)
249
int offset, n, m, indx, lp;
250
static int no_sources = -1;
252
static char *ptr, *p_sources[MAX_SRC];
253
static char p_names[MAX_SRC*PAR_LEN];
260
/* write parameter + source into save buffer */
264
if (no_sources < 0) /* first time */
271
{ /* loop through existing list */
274
for (n=0; n<no_sources; n++)
276
offset = n * PAR_LEN;
277
m = strncmp(name,p_names+offset,lp);
281
cpl_free(p_sources[indx]); /* free space for new source */
285
if (indx == -1) /* we need to add new entry */
287
if (no_sources < MAX_SRC)
290
indx = no_sources - 1;
291
offset = indx * PAR_LEN;
294
return 1; /* buffer full... */
298
(void) strncpy(p_names+offset,name,PAR_LEN-1); /* save parameter name */
299
*(p_names+offset+PAR_LEN-1) = '\0';
301
slen = strlen(*source) + 1; /* get memory for source */
302
ptr = (char *) cpl_malloc(slen);
303
if (ptr == NULL) return (-2); /* no space? just leave... */
305
(void) strcpy(ptr,*source);
306
p_sources[indx] = ptr;
311
/* for given parameter read source out of save buffer */
316
for (n=0; n<no_sources; n++)
319
m = strncmp(name,p_names+offset,lp);
322
*source = p_sources[n];
326
return (-1); /* par. name not found */
330
/* free all the allocated memory */
334
for (n=0; n<no_sources; n++)
336
cpl_free(p_sources[n]);
346
/**********************************************************************/
348
* @brief Neatly print auxiliary information for a parameter
350
* @param flag_prefix This is the prefix used to flag certain types of
351
* switches/parameters. For example a double hypen
352
* "--" may be used before the long form of command
353
* line options. It is only used for spacing.
354
* @param keyword This is the keyword itself. It is only used for
356
* @param description This is the descriptive text that is to be
357
* printed. It is aligned to a tab stop to ensure
358
* that the output is neat.
360
* This function neatly prints an auxiliary line of information
361
* regarding a parameter. The infomation is printed to the normal output
362
* stream. The formatting is handled automatically to get neat alignment
365
/**********************************************************************/
367
void er_paramutils_print_aux_info
368
(const char *flag_prefix, const char *keyword, const char *description)
371
int i, ii, tab = COMMENT_TAB_POSITION;
373
char spc[88]; /* to determine string padding */
374
char str[MAXSTRLENCONF];
381
i = (int) strlen(flag_prefix);
382
ii = (int) strlen(keyword);
385
cpl_msg_error (er_func, "Size of prefix (= %d), keyword (= %d) too large",i,ii);
386
cpl_error_set (er_func, CPL_ERROR_ILLEGAL_INPUT);
390
i = sprintf (spc, " %s%s", flag_prefix, keyword);
391
if (tab < i) tab = i + 2; /* if the keyword is quite long, move the tab */
394
/* for the real string, pad out to the tab-point */
396
memset ((void *) str, 32,(size_t) tab); /* int 32 = ' ' */
399
(void) strcat (str, " (source = "); /* build up string with the description */
400
i = (int) strlen(description);
403
ii = (int) strlen(str);
404
(void) sprintf (&str[ii], "%900.900s",description); /* truncate description */
407
(void) strcat (str, description);
408
(void) strcat (str, ")");
410
/* finally, print the nicely wrapped string */
412
(void) printf("%s\n", er_strutils_split (str, (tab + 2), er_strutils_termwidth ()));
418
/**********************************************************************/
420
* @brief Pretty-print a parameter list with a given header text.
422
* @param param_list List of Parameters
423
* @param header Header Text
425
* @returns Zero on sucess, or non-zero in the case of error.
427
* This function takes a parameter list, and a title and prints them.
428
* The function makes use of the @c COMMENT_TAB_POSITION constant that
429
* is defined in @c er_main.h .
431
/**********************************************************************/
433
int er_paramutils_print_list (cpl_parameterlist * param_list, const char * header)
437
cpl_msg_severity msg_level = CPL_MSG_ERROR;
440
const char *tmp_cmdl_keywd;
441
const char *tmp_string;
442
char tmp_cmdl_descr[MAXSTRLENCONF];
453
tmp_cmdl_descr[0] = '\0';
455
/* Check that the inputs are valid */
457
if (param_list == NULL) return -1;
458
if (header == NULL) return -1;
460
/* Determine the message level (for printing auxiliary information) */
461
msg_level = cpl_msg_get_level ();
463
/* Print some header text */
464
(void) printf ("%s :\n\n", header);
466
/* Get the first parameter from the list */
467
p = cpl_parameterlist_get_first (param_list);
469
/* Loop through all the parameters in the list */
471
{ /* Get and print the keyword */
472
tmp_cmdl_keywd = cpl_parameter_get_alias (p, CPL_PARAMETER_MODE_CLI);
474
/* Determine the type of the parameter */
475
ptype = cpl_parameter_get_type (p);
477
/* Depending on the parameter type, print the parameter appropriately */
481
(void) sprintf (tmp_cmdl_descr, "%s",
482
cpl_parameter_get_bool (p) ? "TRUE" : "FALSE");
486
tmp_int = cpl_parameter_get_int (p);
487
(void) sprintf (tmp_cmdl_descr, "%d", tmp_int);
490
case CPL_TYPE_DOUBLE:
491
tmp_double = cpl_parameter_get_double (p);
492
(void) sprintf (tmp_cmdl_descr, "%s", er_strutils_dblstr (tmp_double));
495
case CPL_TYPE_STRING:
496
tmp_string = cpl_parameter_get_string (p);
497
i = (int) strlen(tmp_string);
499
(void) sprintf (tmp_cmdl_descr, "%MAXSTR.MAXSTR", tmp_string);
501
(void) sprintf (tmp_cmdl_descr, "%s", tmp_string ? tmp_string : "-");
508
/* Actually print the parameter pair */
509
er_paramutils_print_key_desc ("", tmp_cmdl_keywd, tmp_cmdl_descr);
511
/* If we are set to DEBUG level, then print the source of the value too */
512
if (msg_level == CPL_MSG_DEBUG)
516
i = er_manage_sources(2,cpl_parameter_get_name (p),&myptr);
518
er_paramutils_print_aux_info ("", tmp_cmdl_keywd, myptr);
520
er_paramutils_print_aux_info ("", tmp_cmdl_keywd, "ambiguous...");
523
/* Determine the next parameter in the list */
524
p = cpl_parameterlist_get_next (param_list);
531
} /* End of er_paramutils_print_list() */
535
/**********************************************************************/
537
* @brief Set the value of a parameter from that of a given string.
539
* @param p Parameter that will have its value set.
540
* @param value A string containing the value to be assigned to the
542
* @param source The source of @c value
544
* @returns 0 if successfull, !=0 otherwise
546
* Function sets the current value of the given parameter. Converts
547
* the string value to the necessary type if needed.
549
/**********************************************************************/
551
int paramutils_set_from_string
552
(cpl_parameter * p, const char * value, const char *source)
555
cpl_parameter_class pclass;
558
int f_found = 0; /* FALSE */
559
int n, scanlen = 0, tmp_int = 0, i = 0;
561
double tmp_double = 0.0;
571
cpl_error_set (er_func, CPL_ERROR_NULL_INPUT);
576
/* save for later where the value came from */
578
pptr = (char **) &source;
579
er_manage_sources(1,cpl_parameter_get_name(p),pptr);
581
cpl_parameter_set_default_flag (p, TRUE);
583
pclass = cpl_parameter_get_class (p);
584
ptype = cpl_parameter_get_type (p);
587
* ????? - This is a mess. The following switch blocks should be a
588
* single switch block, calling a function fn_class(p, value); depending
589
* on the class. Each of those functions would determine the type and then
590
* do the actual processing.
595
case CPL_PARAMETER_CLASS_VALUE:
599
if ((strcmp (value, "TRUE") == 0) || (strcmp (value, "true") == 0))
601
cpl_parameter_set_bool (p, TRUE);
603
else if ((strcmp (value, "FALSE") == 0) || (strcmp (value, "false") == 0))
605
cpl_parameter_set_bool (p, FALSE);
609
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
615
scanlen = sscanf (value, " %d ", &tmp_int);
618
cpl_parameter_set_int (p, tmp_int);
622
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
627
case CPL_TYPE_DOUBLE:
628
scanlen = sscanf (value, " %le ", &tmp_double);
631
cpl_parameter_set_double (p, tmp_double);
635
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
640
case CPL_TYPE_STRING:
641
cpl_parameter_set_string (p, value);
651
case CPL_PARAMETER_CLASS_RANGE:
659
scanlen = sscanf (value, " %d ", &tmp_int);
662
if ((tmp_int <= cpl_parameter_get_range_max_int (p)) &&
663
(tmp_int >= cpl_parameter_get_range_min_int (p)))
665
cpl_parameter_set_int (p, tmp_int);
669
cpl_error_set (er_func, CPL_ERROR_ILLEGAL_INPUT);
670
cpl_msg_error (er_func,
671
"Specified 'int' value (%d) for the parameter '%s' was outside the "
672
"permitted range %d to %d\n", tmp_int,
673
cpl_parameter_get_alias (p, CPL_PARAMETER_MODE_CLI),
674
cpl_parameter_get_range_min_int (p),
675
cpl_parameter_get_range_max_int (p));
681
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
686
case CPL_TYPE_DOUBLE:
687
scanlen = sscanf (value, " %le ", &tmp_double);
690
if ((tmp_double <= cpl_parameter_get_range_max_double (p)) &&
691
(tmp_double >= cpl_parameter_get_range_min_double (p)))
693
cpl_parameter_set_double (p, tmp_double);
700
cpl_error_set (er_func, CPL_ERROR_ILLEGAL_INPUT);
704
cpl_msg_error (er_func,
705
"Specified 'double' value (%lg) for the parameter '%s' was outside the "
706
"permitted range %lg to %lg\n", tmp_double,
707
cpl_parameter_get_alias (p, CPL_PARAMETER_MODE_CLI),
708
cpl_parameter_get_range_min_double (p),
709
cpl_parameter_get_range_max_double (p));
713
tmp = (char *) cpl_malloc((size_t) 1024);
716
cpl_msg_error (er_func, "Could not allocate 1024 bytes for tmp");
721
* formulate the error message in steps...
722
* er_strutils_dblstr() uses an internal static buffer!
725
(void) strcpy (tmp, "Specified 'double' value (");
726
(void) strcat (tmp, er_strutils_dblstr (tmp_double));
727
(void) strcat (tmp, ") for the parameter '");
728
(void) strcat (tmp, cpl_parameter_get_alias (p, CPL_PARAMETER_MODE_CLI));
729
(void) strcat (tmp, "' was outside the permitted range ");
730
(void) strcat (tmp, er_strutils_dblstr (cpl_parameter_get_range_min_double (p)));
731
(void) strcat (tmp, " to ");
732
(void) strcat (tmp, er_strutils_dblstr (cpl_parameter_get_range_max_double (p)));
733
(void) strcat (tmp, ".\n");
734
cpl_msg_error (er_func, tmp);
742
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
747
case CPL_TYPE_STRING:
757
case CPL_PARAMETER_CLASS_ENUM:
766
scanlen = sscanf (value, " %d ", &tmp_int);
769
for (i=0; i<cpl_parameter_get_enum_size (p); i++)
771
if (tmp_int == cpl_parameter_get_enum_int (p, i))
773
cpl_parameter_set_int (p, tmp_int);
779
cpl_error_set (er_func, CPL_ERROR_INCOMPATIBLE_INPUT);
785
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
790
case CPL_TYPE_DOUBLE:
791
scanlen = sscanf (value, " %le ", &tmp_double);
795
/* WARNING --- The following code may need fabs() */
797
for (i=0; i<cpl_parameter_get_enum_size (p); i++)
799
if ((cpl_parameter_get_enum_double (p, i) - tmp_double) < 0.000001)
801
cpl_parameter_set_double (p, tmp_double);
807
cpl_error_set (er_func, CPL_ERROR_INCOMPATIBLE_INPUT);
814
cpl_error_set (er_func, CPL_ERROR_TYPE_MISMATCH);
819
case CPL_TYPE_STRING:
820
for (i=0; i<cpl_parameter_get_enum_size (p); i++)
822
if (strcmp (cpl_parameter_get_enum_string (p, i), value) == 0)
824
cpl_parameter_set_string (p, value);
830
cpl_error_set (er_func, CPL_ERROR_INCOMPATIBLE_INPUT);
846
} /* End of switch(pclass) */