• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

RecConfigParse.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   Parse the records.config configuration file.
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "TextBuffer.h"
00025 #include "Tokenizer.h"
00026 #include "ink_defs.h"
00027 #include "ink_string.h"
00028 
00029 #include "P_RecFile.h"
00030 #include "P_RecUtils.h"
00031 #include "P_RecMessage.h"
00032 #include "P_RecCore.h"
00033 #include "I_Layout.h"
00034 
00035 const char     *g_rec_config_fpath = NULL;
00036 LLQ            *g_rec_config_contents_llq = NULL;
00037 InkHashTable   *g_rec_config_contents_ht = NULL;
00038 ink_mutex       g_rec_config_lock;
00039 
00040 //-------------------------------------------------------------------------
00041 // RecConfigFileInit
00042 //-------------------------------------------------------------------------
00043 void
00044 RecConfigFileInit(void)
00045 {
00046     ink_mutex_init(&g_rec_config_lock, NULL);
00047     g_rec_config_contents_llq = create_queue();
00048     g_rec_config_contents_ht = ink_hash_table_create(InkHashTableKeyType_String);
00049 }
00050 
00051 //-------------------------------------------------------------------------
00052 // RecFileImport_Xmalloc
00053 //-------------------------------------------------------------------------
00054 static int
00055 RecFileImport_Xmalloc(const char *file, char **file_buf, int *file_size)
00056 {
00057   int err = REC_ERR_FAIL;
00058   RecHandle h_file;
00059   int bytes_read;
00060 
00061   if (file && file_buf && file_size) {
00062     *file_buf = 0;
00063     *file_size = 0;
00064     if ((h_file = RecFileOpenR(file)) != REC_HANDLE_INVALID) {
00065       *file_size = RecFileGetSize(h_file);
00066       *file_buf = (char *)ats_malloc(*file_size + 1);
00067       if (RecFileRead(h_file, *file_buf, *file_size, &bytes_read) != REC_ERR_FAIL && bytes_read == *file_size) {
00068         (*file_buf)[*file_size] = '\0';
00069         err = REC_ERR_OKAY;
00070       } else {
00071         ats_free(*file_buf);
00072         *file_buf = 0;
00073         *file_size = 0;
00074       }
00075       RecFileClose(h_file);
00076     }
00077   }
00078 
00079   return err;
00080 }
00081 
00082 //-------------------------------------------------------------------------
00083 // RecConfigOverrideFromEnvironment
00084 //-------------------------------------------------------------------------
00085 const char *
00086 RecConfigOverrideFromEnvironment(const char * name, const char * value)
00087 {
00088   ats_scoped_str envname(ats_strdup(name));
00089   const char * envval = NULL;
00090 
00091   // Munge foo.bar.config into FOO_BAR_CONFIG.
00092   for (char * c = envname; *c != '\0'; ++c) {
00093     switch (*c) {
00094       case '.': *c = '_'; break;
00095       default: *c = ParseRules::ink_toupper(*c); break;
00096     }
00097   }
00098 
00099   envval = getenv((const char *)envname);
00100   if (envval) {
00101     return envval;
00102   }
00103 
00104   return value;
00105 }
00106 
00107 //-------------------------------------------------------------------------
00108 // RecParseConfigFile
00109 //-------------------------------------------------------------------------
00110 int
00111 RecConfigFileParse(const char * path, RecConfigEntryCallback handler, bool inc_version)
00112 {
00113   char *fbuf;
00114   int fsize;
00115 
00116   const char *line;
00117   int line_num;
00118 
00119   char *rec_type_str, *name_str, *data_type_str, *data_str;
00120   RecT rec_type;
00121   RecDataT data_type;
00122 
00123   Tokenizer line_tok("\r\n");
00124   tok_iter_state line_tok_state;
00125 
00126   RecConfigFileEntry *cfe;
00127 
00128   RecDebug(DL_Note, "Reading '%s'", path);
00129 
00130   // watch out, we're altering our g_rec_config_xxx structures
00131   ink_mutex_acquire(&g_rec_config_lock);
00132 
00133   if (RecFileImport_Xmalloc(path, &fbuf, &fsize) == REC_ERR_FAIL) {
00134     RecLog(DL_Warning, "Could not import '%s'", path);
00135     ink_mutex_release(&g_rec_config_lock);
00136     return REC_ERR_FAIL;
00137   }
00138   // clear our g_rec_config_contents_xxx structures
00139   while (!queue_is_empty(g_rec_config_contents_llq)) {
00140     cfe = (RecConfigFileEntry *) dequeue(g_rec_config_contents_llq);
00141     ats_free(cfe->entry);
00142     ats_free(cfe);
00143   }
00144   ink_hash_table_destroy(g_rec_config_contents_ht);
00145   g_rec_config_contents_ht = ink_hash_table_create(InkHashTableKeyType_String);
00146 
00147   line_tok.Initialize(fbuf, SHARE_TOKS);
00148   line = line_tok.iterFirst(&line_tok_state);
00149   line_num = 1;
00150   while (line) {
00151     char *lc = ats_strdup(line);
00152     char *lt = lc;
00153     char *ln;
00154 
00155     while (isspace(*lt))
00156       lt++;
00157     rec_type_str = strtok_r(lt, " \t", &ln);
00158 
00159     // check for blank lines and comments
00160     if ((!rec_type_str) || (rec_type_str && (*rec_type_str == '#'))) {
00161       goto L_next_line;
00162     }
00163 
00164     name_str = strtok_r(NULL, " \t", &ln);
00165     data_type_str = strtok_r(NULL, " \t", &ln);
00166 
00167     // extract the string data (a little bit tricker since it can have spaces)
00168     if (ln) {
00169       // 'ln' will point to either the next token or a bunch of spaces
00170       // if the user didn't supply a value (e.g. 'STRING   ').  First
00171       // scan past all of the spaces.  If we hit a '\0', then we we
00172       // know we didn't have a valid value.  If not, set 'data_str' to
00173       // the start of the token and scan until we find the end.  Once
00174       // the end is found, back-peddle to remove any trailing spaces.
00175       while (isspace(*ln))
00176         ln++;
00177       if (*ln == '\0') {
00178         data_str = NULL;
00179       } else {
00180         data_str = ln;
00181         while (*ln != '\0')
00182           ln++;
00183         ln--;
00184         while (isspace(*ln) && (ln > data_str))
00185           ln--;
00186         ln++;
00187         *ln = '\0';
00188       }
00189     } else {
00190       data_str = NULL;
00191     }
00192 
00193     // check for errors
00194     if (!(rec_type_str && name_str && data_type_str && data_str)) {
00195       RecLog(DL_Warning, "Could not parse line at '%s:%d' -- skipping line: '%s'", path, line_num, line);
00196       goto L_next_line;
00197     }
00198 
00199     // record type
00200     if (strcmp(rec_type_str, "CONFIG") == 0) {
00201       rec_type = RECT_CONFIG;
00202     } else if (strcmp(rec_type_str, "PROCESS") == 0) {
00203       rec_type = RECT_PROCESS;
00204     } else if (strcmp(rec_type_str, "NODE") == 0) {
00205       rec_type = RECT_NODE;
00206     } else if (strcmp(rec_type_str, "CLUSTER") == 0) {
00207       rec_type = RECT_CLUSTER;
00208     } else if (strcmp(rec_type_str, "LOCAL") == 0) {
00209       rec_type = RECT_LOCAL;
00210     } else {
00211       RecLog(DL_Warning, "Unknown record type '%s' at '%s:%d' -- skipping line", rec_type_str, path, line_num);
00212       goto L_next_line;
00213     }
00214 
00215     // data_type
00216     if (strcmp(data_type_str, "INT") == 0) {
00217       data_type = RECD_INT;
00218     } else if (strcmp(data_type_str, "FLOAT") == 0) {
00219       data_type = RECD_FLOAT;
00220     } else if (strcmp(data_type_str, "STRING") == 0) {
00221       data_type = RECD_STRING;
00222     } else if (strcmp(data_type_str, "COUNTER") == 0) {
00223       data_type = RECD_COUNTER;
00224     } else {
00225       RecLog(DL_Warning, "Unknown data type '%s' at '%s:%d' -- skipping line", data_type_str, path, line_num);
00226       goto L_next_line;
00227     }
00228 
00229     // OK, we parsed the record, send it to the handler ...
00230     handler(rec_type, data_type, name_str, RecConfigOverrideFromEnvironment(name_str, data_str), inc_version);
00231 
00232     // update our g_rec_config_contents_xxx
00233     cfe = (RecConfigFileEntry *)ats_malloc(sizeof(RecConfigFileEntry));
00234     cfe->entry_type = RECE_RECORD;
00235     cfe->entry = ats_strdup(name_str);
00236     enqueue(g_rec_config_contents_llq, (void *) cfe);
00237     ink_hash_table_insert(g_rec_config_contents_ht, name_str, NULL);
00238     goto L_done;
00239 
00240   L_next_line:
00241     // store this line into g_rec_config_contents_llq so that we can
00242     // write it out later
00243     cfe = (RecConfigFileEntry *)ats_malloc(sizeof(RecConfigFileEntry));
00244     cfe->entry_type = RECE_COMMENT;
00245     cfe->entry = ats_strdup(line);
00246     enqueue(g_rec_config_contents_llq, (void *) cfe);
00247 
00248   L_done:
00249     line = line_tok.iterNext(&line_tok_state);
00250     line_num++;
00251     ats_free(lc);
00252   }
00253 
00254   ink_mutex_release(&g_rec_config_lock);
00255   ats_free(fbuf);
00256 
00257   return REC_ERR_OKAY;
00258 }

Generated by  doxygen 1.7.1