Mapper
get_apps_defaults.c
Go to the documentation of this file.
1 /* Pgm: get_apps_defaults.c
2  *
3  * Program to resolve the value of a requested string.
4  *
5  * The requested string to be resolved is supplied as the string
6  * variable <request>, the resolved request is returned as the string
7  * variable <reply>.
8  *
9  * Request resolution occurs in one of three ways:
10  *
11  * 1. an environment variable matching in name to <request> is found;
12  * <reply> is then the value of that environment variable,
13  *
14  * 2. <request> is found as a match in a file that establishes
15  * token - resource (t-r) relationships. Three files may be scanned in
16  * this order:
17  * APPS_DEFAULTS_USER ..... a personal users set of tokens
18  * APPS_DEFAULTS_PROG ..... a program specific set of tokens
19  * APPS_DEFAULTS_SITE ..... a site wide set of tokens
20  * APPS_DEFAULTS .......... a system-wide (national) set of tokens
21  * to find the first token match to get a request.
22  *
23  * 3. if <request> can not be resolved, <reply> is assigned as the
24  * null string.
25  *
26  * Each file is scanned from top to bottom looking for the first match
27  * between <request> and a defined token. The syntax needed in either
28  * file is:
29  *
30  * <token> <delimiter> <resource>
31  *
32  * where:
33  * <token> is defined as a string delimited by white space or <delimiter>,
34  * <delimiter> is the : (colon),
35  * <resource> is any string, the value returned depends
36  * on certain file conventions:
37  *
38  * 1. A valid t-r requires a valid token followed by a valid
39  * resource,
40  * 2. the t-r relationship must be contained on a single line,
41  * 3. no white space needs to surround <delimiter>,
42  * 4. comments are indicated by a #,
43  * 5. neither <token> nor <resource> can begin with a # or :,
44  * 6. a # or a : can be embedded within <resource>,
45  * 7. <resource> can contain white space if it is bounded by
46  * the ' or " characters,
47  * 8. blank lines are allowed in the file,
48  * 9. referbacks are indicated by $(...). The '...' is resolved
49  * the same way any other token is, and is substituted for
50  * the $(...) string to compose the final resource value.
51  * 10. Multiple referbacks are allowed in <resource>, but embedded
52  * referbacks are not allowed (i.e. no $($(...)) allowed).
53  * 11. First in wins. That is, first finding of <token>
54  * matching <request> uses that resource value, even if null.
55  *
56  * A sample of a t-r file:
57  * #-----------------------------------------------------------------------
58  * # This is a comment line; so was previous line. Blank lines are
59  * # intentional and are allowed in file.
60  *
61  * ofs_level : testcase # this is a comment on valid t-r
62  * ofs_reor_lvl : test:reor # ':' allowed in body of <resource>
63  * ofs_inpt_grp : "test case" # white space allowed in <resource>
64  *
65  * ofs_file_grp : /home/$(ofs_level)/files # referback to prior token;
66  * # returned resource will be
67  * # /home/testcase/files
68  *
69  * ofs_xxx xxx # invalid t-r, no delimiter
70  * ofs_yyy : #yyy # invalid t-r, no resource
71  *
72  * # This is comment line; so is following line
73  * #-----------------------------------------------------------------------
74  *
75  * Function originally written by JTOstrowski - HRL - 11/92
76  */
77 
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <ctype.h>
82 
83 #define LEN_TOKEN 128 /* maximum length of token in file */
84 #define LEN_REPLY 512 /* maximum length of reply in single line in file */
85  /* (also the max size of the reply output, incl \0) */
86  /* (must be <= LEN_TOTREPLY) */
87 #define LEN_LINE 520 /* maximum length of line in file */
88 #define LEN_TOTREPLY 600 /* maximum length of all concatenated reply strings */
89 
90 #define RECUR_LIMIT 40 /* limit number of referback recursions */
91 
92 #define ENV_VAR_1 "APPS_DEFAULTS_USER" /* env. var. for personal t-r file */
93 #define ENV_VAR_2 "APPS_DEFAULTS_PROG" /* env. var. for specific program */
94 #define ENV_VAR_3 "APPS_DEFAULTS_SITE" /* env. var. for local site t-r file */
95 #define ENV_VAR_4 "APPS_DEFAULTS" /* env. var. for default t-r file */
96 #define ENV_VAR_LENGTH 20 /* default length of env. var. */
97 #define ENV_VAR_NUMBER 4 /* no. of env. vars. to use */
98 
99 #define RFR_OPEN "$(" /* referback opening string */
100 #define RFR_CLOSE ")" /* referback closing string */
101 #define DELIM ':' /* delimiter character */
102 #define COMMENT '#' /* comment character */
103 #define QUOTE1 '\"' /* 1st valid quote character */
104 #define QUOTE2 '\'' /* 2nd valid quote character */
105 #define BSLASH '\\' /* back slash */
106 
107 #define QPHRASE1 (opt_line[ilast] == QUOTE1 && ilast > 0 && opt_line[ilast - 1] != BSLASH)
108 #define QPHRASE2 (opt_line[ilast] == QUOTE2 && ilast > 0 && opt_line[ilast - 1] != BSLASH)
109 #define NPHRASE2 (isspace(opt_line[ilast]) && ilast > 0 && opt_line[ilast - 1] != BSLASH)
110 
111 static int r_cou = 0; /* counter to limit recursion */
112 static int ifile = 0; /* file loop counter */
113 static int i = 0; /* miscellaneous counter */
114 static int i_tok = 0; /* found token index */
115 static int i_rep = 0; /* found reply in variable resource */
116 static int ilast = 0; /* last character position holder */
117 static int opt_line_len; /* number of chars in opt_line */
118 static int iphrase = 0; /* conditional phrase-ending indicator */
119 static char token[LEN_TOKEN+1]; /* working token array */
120 static char *as_env_var; /* returned env. var. value */
121 static char env_var_array[ENV_VAR_NUMBER][ENV_VAR_LENGTH];
122 static int r_len = 0; /* length of reply in referback */
123 static int e_len = 0; /* length of end of reply after a referback */
124 
125 static FILE *in[ENV_VAR_NUMBER]; /* file descripter */
126 static char *opts_file[ENV_VAR_NUMBER]; /* file name holder */
127 
128 
129 /*------------------------------------------------------------------------------------------------*/
130 int get_apps_defaults(char *request, int *request_len, char *reply, int *reply_len)
131 
132 {
133  void get_apps_defaults_r(char *, char *);
134 
135  char inquest[LEN_TOKEN+1]; /* entered token string recopied */
136  char resource[LEN_TOTREPLY+1]; /* working resource array */
137 
138 /* Set output to null in case something goes wrong, check input length for bad number */
139 
140  reply[0] = '\0';
141  if ( *request_len>0 && *request_len<=LEN_TOKEN && *request_len<=LEN_TOTREPLY )
142  {
143 
144 /* Place entered string into local variable; append '\0';set recursion count global */
145 
146  (void)strncpy(inquest,request,*request_len);
147  inquest[*request_len] = '\0';
148  r_cou = 0;
149 
150 /* Fill the environment variable array */
151 
152  for (i = 0; i < ENV_VAR_NUMBER; i++)
153  {
154  (void)memset(env_var_array[i], '\0', ENV_VAR_LENGTH);
155  }
156 
157  (void)strcpy(env_var_array[0], ENV_VAR_1);
158  (void)strcpy(env_var_array[1], ENV_VAR_2);
159  (void)strcpy(env_var_array[2], ENV_VAR_3);
160  (void)strcpy(env_var_array[3], ENV_VAR_4);
161 
162 /* Make sure apps files are initialized as not-opened */
163 
164  for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++)
165  {
166  in[ifile] = NULL;
167  opts_file[ifile] = '\0';
168  }
169 
170 /* Call true "C" routine that can be recursive using global variable "r_cou" */
171 
172  get_apps_defaults_r(inquest,resource);
173 
174 /* Close any apps files that may have been opened */
175 
176  for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++)
177  {
178  if (in[ifile] != NULL) (void)fclose(in[ifile]);
179  }
180 
181 /* Place local output string into returned string */
182 
183  if ( (r_cou <= RECUR_LIMIT) && ((int)strlen(resource) < LEN_REPLY) )
184  {
185  (void)strcpy(reply, &resource[0]);
186  }
187  }
188 
189 /* Get length, set return error status ( 0=token found, 1=error or no token ) */
190 /* old return was: return ( (*reply) ? 0 : 1 ); */
191 
192  *reply_len = strlen(reply);
193  return ( ( *reply_len != 0 ) ? 0 : 1 );
194 }
195 
196 /*------------------------------------------------------------------------------------------------*/
197 void get_apps_defaults_r(char inquest[], char resource[])
198 
199 {
200  char *pOpen; /* referback opening position holder */
201  char *pClose; /* referback closing position holder */
202  int diff = 0; /* string comparison result */
203  char referback[LEN_TOKEN+1]; /* referback token array */
204  char refer_val[LEN_TOTREPLY+1]; /* referback value array */
205  char substitute[LEN_TOTREPLY+1]; /* expanded referback-ed resource */
206 
207 /* Initialize the result to NULL */
208 
209  (void)memset(resource, '\0', LEN_TOTREPLY+1);
210 
211 /* Check for the requested variable found as an environment variable */
212 
213  as_env_var = getenv(inquest);
214 
215  if ( as_env_var ) /* SAM, RTi */
216  (void)strcpy(resource, as_env_var);
217  else
218  {
219 
220 /* Increment recursive counter (needed to avoid referbacks calling itself) */
221 
222  r_cou += 1;
223  if (r_cou <= RECUR_LIMIT+1)
224  {
225 
226 /* The resource file to be read is indicated by the value of an
227  environment variable */
228 
229  for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++)
230  {
231  char opt_line[LEN_LINE+1]; /* t-r file line array */
232  int found_token = 0;
233 
234 /* See if file can be opened for reading */
235 
236  if (in[ifile] == NULL)
237  {
238  opts_file[ifile] = getenv(env_var_array[ifile]);
239  if ( opts_file[ifile] != NULL )
240  {
241  int olen;
242  olen=(int)strlen(opts_file[ifile]);
243  if ( olen > 0 )
244  in[ifile] = fopen(opts_file[ifile], "r");
245  }
246  }
247  else
248  {
249  rewind(in[ifile]);
250  }
251 
252  if (in[ifile] != NULL)
253  {
254 
255 /* Read file until either match is found or EOF reached */
256 
257  while (fgets(opt_line, LEN_LINE+1, in[ifile]) != NULL)
258  {
259 
260 /* Only scan lines with the delimiter in them */
261 
262  if (strchr(opt_line, DELIM) != NULL)
263  {
264  i = 0;
265  opt_line_len = strlen(opt_line);
266 
267 /* Look for first non-blank character on line */
268 
269  while (i < opt_line_len-1 && isspace(opt_line[i]) != 0)
270  i++;
271 
272 /* Discard line if first character is either delimiter or comment indicator */
273 
274  if (opt_line[i] != COMMENT && opt_line[i] != DELIM)
275  {
276  ilast = i;
277  i_tok = 0;
278 
279 /* Look for token based on rules for delimiting tokens */
280 
281  while (ilast <= opt_line_len &&
282  i_tok <= LEN_TOKEN &&
283  isprint(opt_line[ilast]) != 0 &&
284  isspace(opt_line[ilast]) == 0 &&
285  opt_line[ilast] != DELIM )
286  {
287  token[i_tok++] = opt_line[ilast++];
288  }
289  token[i_tok] = '\0';
290 
291 /* Got proposed token, skip thru spaces */
292 
293  while (ilast < opt_line_len && isspace(opt_line[ilast]) != 0 )
294  ilast++;
295 
296 /* See if token on line is one to be retrieved */
297 
298  if (opt_line[ilast] == DELIM &&
299  strlen(inquest) == strlen(token) &&
300  strncmp(token, inquest, i_tok) == 0 )
301  {
302 
303 /* Match found, now determine associated resource. */
304 /* Resource can not start with DELIM or COMMENT characters */
305 /* or any non-printing characters */
306 
307  i = ilast+1;
308  resource[0] = '\0';
309  found_token = 1;
310 
311 /* Skip space after colon */
312 
313  while (i < opt_line_len-1 && isspace(opt_line[i]) != 0)
314  i++;
315 
316 /* Determine contents of resource until: */
317 /* 1. End of line is reached, or */
318 /* 2. White space is found for resources not quoted, or */
319 /* 3. Closing matching quote character is found for quoted strings. */
320 
321  if (i < opt_line_len)
322  {
323  if (opt_line[i] != COMMENT)
324  {
325  ilast = i;
326  i_rep = 0;
327 
328 /* Check to see if resource string is quoted (single or double) */
329 
330  if (QPHRASE1)
331  iphrase = 1;
332  else if (QPHRASE2)
333  iphrase = 2;
334  else
335  iphrase = 0;
336 
337 /* Complete resource based on start character conditions */
338 
339  switch (iphrase)
340  {
341  case 0:
342  while (isprint(opt_line[ilast]) && !NPHRASE2)
343  resource[i_rep++] = opt_line[ilast++];
344  break;
345  case 1:
346  ilast++;
347  while (isprint(opt_line[ilast]) && !QPHRASE1)
348  resource[i_rep++] = opt_line[ilast++];
349  break;
350  case 2:
351  ilast++;
352  while (isprint(opt_line[ilast]) && !QPHRASE2)
353  resource[i_rep++] = opt_line[ilast++];
354  break;
355  }
356  resource[i_rep] = '\0';
357 
358 /* Now look for any embedded referbacks in the resource string */
359 
360  while ( ((pOpen = strstr(resource, RFR_OPEN)) != NULL) &&
361  ((pClose = strstr(pOpen, RFR_CLOSE)) != NULL) &&
362  ((diff = (int)(pClose - pOpen) - 2) >= 0 ) )
363  {
364  (void)memset(substitute, '\0', LEN_TOTREPLY+1);
365  if (strcmp(resource, pOpen)) /* SAM, RTi */
366  (void)strncpy(substitute, resource, (pOpen - &resource[0]));
367  if ( diff > 0)
368  {
369  (void)memset(referback, '\0', LEN_TOKEN+1);
370  (void)memset(refer_val, '\0', LEN_REPLY+1);
371  (void)strncpy(referback, pOpen + 2, diff);
372 
373  (void)get_apps_defaults_r(referback, refer_val);
374 
375  if (r_cou > RECUR_LIMIT+1)
376  break;
377 
378  e_len = (int)(strlen(resource) - (int)(pClose - &resource[0]));
379  e_len = e_len - 1;
380  r_len = (int)(strlen(refer_val));
381  if ( ((int)strlen(substitute) + r_len + e_len) > LEN_TOTREPLY)
382  {
383  r_cou = RECUR_LIMIT+1;
384  break;
385  }
386  else
387  {
388  if (r_len > 0)
389  (void)strcat(substitute, refer_val);
390  }
391  }
392  (void)strcat(substitute, pClose + 1);
393  (void)strcpy(resource, substitute);
394  } /* end of referback expansion while-loop */
395  break;
396  } /* end of non-comment part of resource request if-loop */
397  } /* end of resource request characters if-loop */
398  } /* end of token-been-found if-loop */
399  } /* end of discard-if-delimiter-or-comment check if-loop */
400  } /* end of check for line with a delimiter in it if-loop */
401  } /* end of t-r file read to EOL if-loop */
402  } /* end of legitimate file opening loop */
403 
404 /* Break out of file loop if token is found, else will search lower priority files */
405 /* This will also end search if token gives null reply, old way: */
406 /* if (resource[0]) break; */
407 /* searched later files if token reply was null */
408 
409  if ( found_token == 1 )
410  break;
411 
412  } /* end of loop thru files named by env vars */
413  } /* end of loop where recursion is less than limit */
414  else
415  {
416  resource[0] = '\0';
417  }
418  } /* end obtaining of resource for given token */
419 
420 /* ============== Statements containing RCS keywords: */
421 {static char rcs_id1[] = "$Source: /fs/hseb/ob6/rfc/util/src/util_gen1/RCS/get_apps_defaults.c,v $";
422  static char rcs_id2[] = "$Id: get_apps_defaults.c,v 1.8 2005/07/07 19:20:36 dws Exp $";}
423 /* =================================================== */
424 
425 }