/* Pgm: get_apps_defaults.c * * Program to resolve the value of a requested string. * * The requested string to be resolved is supplied as the string * variable , the resolved request is returned as the string * variable . * * Request resolution occurs in one of three ways: * * 1. an environment variable matching in name to is found; * is then the value of that environment variable, * * 2. is found as a match in a file that establishes * token - resource (t-r) relationships. Three files may be scanned in * this order: * APPS_DEFAULTS_USER ..... a personal users set of tokens * APPS_DEFAULTS_PROG ..... a program specific set of tokens * APPS_DEFAULTS_SITE ..... a site wide set of tokens * APPS_DEFAULTS .......... a system-wide (national) set of tokens * to find the first token match to get a request. * * 3. if can not be resolved, is assigned as the * null string. * * Each file is scanned from top to bottom looking for the first match * between and a defined token. The syntax needed in either * file is: * * * * where: * is defined as a string delimited by white space or , * is the : (colon), * is any string, the value returned depends * on certain file conventions: * * 1. A valid t-r requires a valid token followed by a valid * resource, * 2. the t-r relationship must be contained on a single line, * 3. no white space needs to surround , * 4. comments are indicated by a #, * 5. neither nor can begin with a # or :, * 6. a # or a : can be embedded within , * 7. can contain white space if it is bounded by * the ' or " characters, * 8. blank lines are allowed in the file, * 9. referbacks are indicated by $(...). The '...' is resolved * the same way any other token is, and is substituted for * the $(...) string to compose the final resource value. * 10. Multiple referbacks are allowed in , but embedded * referbacks are not allowed (i.e. no $($(...)) allowed). * 11. First in wins. That is, first finding of * matching uses that resource value, even if null. * * A sample of a t-r file: * #----------------------------------------------------------------------- * # This is a comment line; so was previous line. Blank lines are * # intentional and are allowed in file. * * ofs_level : testcase # this is a comment on valid t-r * ofs_reor_lvl : test:reor # ':' allowed in body of * ofs_inpt_grp : "test case" # white space allowed in * * ofs_file_grp : /home/$(ofs_level)/files # referback to prior token; * # returned resource will be * # /home/testcase/files * * ofs_xxx xxx # invalid t-r, no delimiter * ofs_yyy : #yyy # invalid t-r, no resource * * # This is comment line; so is following line * #----------------------------------------------------------------------- * * Function originally written by JTOstrowski - HRL - 11/92 */ #include #include #include #include #define LEN_TOKEN 128 /* maximum length of token in file */ #define LEN_REPLY 512 /* maximum length of reply in single line in file */ /* (also the max size of the reply output, incl \0) */ /* (must be <= LEN_TOTREPLY) */ #define LEN_LINE 520 /* maximum length of line in file */ #define LEN_TOTREPLY 600 /* maximum length of all concatenated reply strings */ #define RECUR_LIMIT 40 /* limit number of referback recursions */ #define ENV_VAR_1 "APPS_DEFAULTS_USER" /* env. var. for personal t-r file */ #define ENV_VAR_2 "APPS_DEFAULTS_PROG" /* env. var. for specific program */ #define ENV_VAR_3 "APPS_DEFAULTS_SITE" /* env. var. for local site t-r file */ #define ENV_VAR_4 "APPS_DEFAULTS" /* env. var. for default t-r file */ #define ENV_VAR_LENGTH 20 /* default length of env. var. */ #define ENV_VAR_NUMBER 4 /* no. of env. vars. to use */ #define RFR_OPEN "$(" /* referback opening string */ #define RFR_CLOSE ")" /* referback closing string */ #define DELIM ':' /* delimiter character */ #define COMMENT '#' /* comment character */ #define QUOTE1 '\"' /* 1st valid quote character */ #define QUOTE2 '\'' /* 2nd valid quote character */ #define BSLASH '\\' /* back slash */ #define QPHRASE1 (opt_line[ilast] == QUOTE1 && ilast > 0 && opt_line[ilast - 1] != BSLASH) #define QPHRASE2 (opt_line[ilast] == QUOTE2 && ilast > 0 && opt_line[ilast - 1] != BSLASH) #define NPHRASE2 (isspace(opt_line[ilast]) && ilast > 0 && opt_line[ilast - 1] != BSLASH) static int r_cou = 0; /* counter to limit recursion */ static int ifile = 0; /* file loop counter */ static int i = 0; /* miscellaneous counter */ static int i_tok = 0; /* found token index */ static int i_rep = 0; /* found reply in variable resource */ static int ilast = 0; /* last character position holder */ static int opt_line_len; /* number of chars in opt_line */ static int iphrase = 0; /* conditional phrase-ending indicator */ static char token[LEN_TOKEN+1]; /* working token array */ static char *as_env_var; /* returned env. var. value */ static char env_var_array[ENV_VAR_NUMBER][ENV_VAR_LENGTH]; static int r_len = 0; /* length of reply in referback */ static int e_len = 0; /* length of end of reply after a referback */ static FILE *in[ENV_VAR_NUMBER]; /* file descripter */ static char *opts_file[ENV_VAR_NUMBER]; /* file name holder */ /*------------------------------------------------------------------------------------------------*/ int get_apps_defaults(char *request, int *request_len, char *reply, int *reply_len) { void get_apps_defaults_r(char *, char *); char inquest[LEN_TOKEN+1]; /* entered token string recopied */ char resource[LEN_TOTREPLY+1]; /* working resource array */ /* Set output to null in case something goes wrong, check input length for bad number */ reply[0] = '\0'; if ( *request_len>0 && *request_len<=LEN_TOKEN && *request_len<=LEN_TOTREPLY ) { /* Place entered string into local variable; append '\0';set recursion count global */ (void)strncpy(inquest,request,*request_len); inquest[*request_len] = '\0'; r_cou = 0; /* Fill the environment variable array */ for (i = 0; i < ENV_VAR_NUMBER; i++) { (void)memset(env_var_array[i], '\0', ENV_VAR_LENGTH); } (void)strcpy(env_var_array[0], ENV_VAR_1); (void)strcpy(env_var_array[1], ENV_VAR_2); (void)strcpy(env_var_array[2], ENV_VAR_3); (void)strcpy(env_var_array[3], ENV_VAR_4); /* Make sure apps files are initialized as not-opened */ for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++) { in[ifile] = NULL; opts_file[ifile] = '\0'; } /* Call true "C" routine that can be recursive using global variable "r_cou" */ get_apps_defaults_r(inquest,resource); /* Close any apps files that may have been opened */ for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++) { if (in[ifile] != NULL) (void)fclose(in[ifile]); } /* Place local output string into returned string */ if ( (r_cou <= RECUR_LIMIT) && ((int)strlen(resource) < LEN_REPLY) ) { (void)strcpy(reply, &resource[0]); } } /* Get length, set return error status ( 0=token found, 1=error or no token ) */ /* old return was: return ( (*reply) ? 0 : 1 ); */ *reply_len = strlen(reply); return ( ( *reply_len != 0 ) ? 0 : 1 ); } /*------------------------------------------------------------------------------------------------*/ void get_apps_defaults_r(char inquest[], char resource[]) { char *pOpen; /* referback opening position holder */ char *pClose; /* referback closing position holder */ int diff = 0; /* string comparison result */ char referback[LEN_TOKEN+1]; /* referback token array */ char refer_val[LEN_TOTREPLY+1]; /* referback value array */ char substitute[LEN_TOTREPLY+1]; /* expanded referback-ed resource */ /* Initialize the result to NULL */ (void)memset(resource, '\0', LEN_TOTREPLY+1); /* Check for the requested variable found as an environment variable */ as_env_var = getenv(inquest); if ( as_env_var ) /* SAM, RTi */ (void)strcpy(resource, as_env_var); else { /* Increment recursive counter (needed to avoid referbacks calling itself) */ r_cou += 1; if (r_cou <= RECUR_LIMIT+1) { /* The resource file to be read is indicated by the value of an environment variable */ for (ifile = 0; ifile < ENV_VAR_NUMBER; ifile++) { char opt_line[LEN_LINE+1]; /* t-r file line array */ int found_token = 0; /* See if file can be opened for reading */ if (in[ifile] == NULL) { opts_file[ifile] = getenv(env_var_array[ifile]); if ( opts_file[ifile] != NULL ) { int olen; olen=(int)strlen(opts_file[ifile]); if ( olen > 0 ) in[ifile] = fopen(opts_file[ifile], "r"); } } else { rewind(in[ifile]); } if (in[ifile] != NULL) { /* Read file until either match is found or EOF reached */ while (fgets(opt_line, LEN_LINE+1, in[ifile]) != NULL) { /* Only scan lines with the delimiter in them */ if (strchr(opt_line, DELIM) != NULL) { i = 0; opt_line_len = strlen(opt_line); /* Look for first non-blank character on line */ while (i < opt_line_len-1 && isspace(opt_line[i]) != 0) i++; /* Discard line if first character is either delimiter or comment indicator */ if (opt_line[i] != COMMENT && opt_line[i] != DELIM) { ilast = i; i_tok = 0; /* Look for token based on rules for delimiting tokens */ while (ilast <= opt_line_len && i_tok <= LEN_TOKEN && isprint(opt_line[ilast]) != 0 && isspace(opt_line[ilast]) == 0 && opt_line[ilast] != DELIM ) { token[i_tok++] = opt_line[ilast++]; } token[i_tok] = '\0'; /* Got proposed token, skip thru spaces */ while (ilast < opt_line_len && isspace(opt_line[ilast]) != 0 ) ilast++; /* See if token on line is one to be retrieved */ if (opt_line[ilast] == DELIM && strlen(inquest) == strlen(token) && strncmp(token, inquest, i_tok) == 0 ) { /* Match found, now determine associated resource. */ /* Resource can not start with DELIM or COMMENT characters */ /* or any non-printing characters */ i = ilast+1; resource[0] = '\0'; found_token = 1; /* Skip space after colon */ while (i < opt_line_len-1 && isspace(opt_line[i]) != 0) i++; /* Determine contents of resource until: */ /* 1. End of line is reached, or */ /* 2. White space is found for resources not quoted, or */ /* 3. Closing matching quote character is found for quoted strings. */ if (i < opt_line_len) { if (opt_line[i] != COMMENT) { ilast = i; i_rep = 0; /* Check to see if resource string is quoted (single or double) */ if (QPHRASE1) iphrase = 1; else if (QPHRASE2) iphrase = 2; else iphrase = 0; /* Complete resource based on start character conditions */ switch (iphrase) { case 0: while (isprint(opt_line[ilast]) && !NPHRASE2) resource[i_rep++] = opt_line[ilast++]; break; case 1: ilast++; while (isprint(opt_line[ilast]) && !QPHRASE1) resource[i_rep++] = opt_line[ilast++]; break; case 2: ilast++; while (isprint(opt_line[ilast]) && !QPHRASE2) resource[i_rep++] = opt_line[ilast++]; break; } resource[i_rep] = '\0'; /* Now look for any embedded referbacks in the resource string */ while ( ((pOpen = strstr(resource, RFR_OPEN)) != NULL) && ((pClose = strstr(pOpen, RFR_CLOSE)) != NULL) && ((diff = (int)(pClose - pOpen) - 2) >= 0 ) ) { (void)memset(substitute, '\0', LEN_TOTREPLY+1); if (strcmp(resource, pOpen)) /* SAM, RTi */ (void)strncpy(substitute, resource, (pOpen - &resource[0])); if ( diff > 0) { (void)memset(referback, '\0', LEN_TOKEN+1); (void)memset(refer_val, '\0', LEN_REPLY+1); (void)strncpy(referback, pOpen + 2, diff); (void)get_apps_defaults_r(referback, refer_val); if (r_cou > RECUR_LIMIT+1) break; e_len = (int)(strlen(resource) - (int)(pClose - &resource[0])); e_len = e_len - 1; r_len = (int)(strlen(refer_val)); if ( ((int)strlen(substitute) + r_len + e_len) > LEN_TOTREPLY) { r_cou = RECUR_LIMIT+1; break; } else { if (r_len > 0) (void)strcat(substitute, refer_val); } } (void)strcat(substitute, pClose + 1); (void)strcpy(resource, substitute); } /* end of referback expansion while-loop */ break; } /* end of non-comment part of resource request if-loop */ } /* end of resource request characters if-loop */ } /* end of token-been-found if-loop */ } /* end of discard-if-delimiter-or-comment check if-loop */ } /* end of check for line with a delimiter in it if-loop */ } /* end of t-r file read to EOL if-loop */ } /* end of legitimate file opening loop */ /* Break out of file loop if token is found, else will search lower priority files */ /* This will also end search if token gives null reply, old way: */ /* if (resource[0]) break; */ /* searched later files if token reply was null */ if ( found_token == 1 ) break; } /* end of loop thru files named by env vars */ } /* end of loop where recursion is less than limit */ else { resource[0] = '\0'; } } /* end obtaining of resource for given token */ }