text_utils.c

00001 #include <net-snmp/net-snmp-config.h>
00002 #include <net-snmp/net-snmp-includes.h>
00003 
00004 #include <stdio.h>
00005 #include <ctype.h>
00006 #if HAVE_STDLIB_H
00007 #   include <stdlib.h>
00008 #endif
00009 #if HAVE_UNISTD_H
00010 #   include <unistd.h>
00011 #endif
00012 #if HAVE_STRING_H
00013 #   include <string.h>
00014 #else
00015 #  include <strings.h>
00016 #endif
00017 
00018 #include <sys/types.h>
00019 
00020 #if HAVE_LIMITS_H
00021 #   include <limits.h>
00022 #endif
00023 #if HAVE_SYS_PARAM_H
00024 #   include <sys/param.h>
00025 #endif
00026 #ifdef HAVE_SYS_STAT_H
00027 #   include <sys/stat.h>
00028 #endif
00029 #ifdef HAVE_FCNTL_H
00030 #   include <fcntl.h>
00031 #endif
00032 
00033 #include <errno.h>
00034 
00035 #if HAVE_DMALLOC_H
00036 #  include <dmalloc.h>
00037 #endif
00038 
00039 #include <net-snmp/types.h>
00040 #include <net-snmp/library/snmp_debug.h>
00041 #include <net-snmp/library/container.h>
00042 #include <net-snmp/library/file_utils.h>
00043 #include <net-snmp/library/text_utils.h>
00044 
00045 
00046 /*------------------------------------------------------------------
00047  *
00048  * Prototypes
00049  *
00050  */
00051 /*
00052  * parse methods
00053  */
00054 void
00055 _pm_save_index_string_string(FILE *f, netsnmp_container *cin,
00056                              int flags);
00057 void
00058 _pm_save_everything(FILE *f, netsnmp_container *cin, int flags);
00059 void
00060 _pm_user_function(FILE *f, netsnmp_container *cin,
00061                   netsnmp_line_process_info *lpi, int flags);
00062 
00063 
00064 /*
00065  * line processors
00066  */
00067 int _process_line_tvi(netsnmp_line_info *line_info, void *mem,
00068                       struct netsnmp_line_process_info_s* lpi);
00069 
00070 
00071 
00072 /*------------------------------------------------------------------
00073  *
00074  * Text file processing functions
00075  *
00076  */
00077 
00081 netsnmp_container *
00082 netsnmp_file_text_parse(netsnmp_file *f, netsnmp_container *cin,
00083                         int parse_mode, u_int flags, void *context)
00084 {
00085     netsnmp_container *c = cin;
00086     FILE              *fin;
00087     int                rc;
00088 
00089     if (NULL == f)
00090         return NULL;
00091 
00092     if ((NULL == c) && (!(flags & PM_FLAG_NO_CONTAINER))) {
00093         c = netsnmp_container_find("text_parse:binary_array");
00094         if (NULL == c)
00095             return NULL;
00096     }
00097 
00098     rc = netsnmp_file_open(f);
00099     if (rc < 0) { 
00100         if ((NULL !=c) && (c != cin))
00101             CONTAINER_FREE(c);
00102         return NULL;
00103     }
00104     
00105     /*
00106      * get a stream from the file descriptor. This DOES NOT rewind the
00107      * file (if fd was previously opened).
00108      */
00109     fin = fdopen(f->fd, "r");
00110     if (NULL == fin) {
00111         if (NS_FI_AUTOCLOSE(f->ns_flags))
00112             close(f->fd);
00113         if ((NULL !=c) && (c != cin))
00114             CONTAINER_FREE(c);
00115         return NULL;
00116     }
00117 
00118     switch (parse_mode) {
00119 
00120         case PM_SAVE_EVERYTHING:
00121             _pm_save_everything(fin, c, flags);
00122             break;
00123 
00124         case PM_INDEX_STRING_STRING:
00125             _pm_save_index_string_string(fin, c, flags);
00126             break;
00127 
00128         case PM_USER_FUNCTION:
00129             if (NULL != context)
00130                 _pm_user_function(fin, c, (netsnmp_line_process_info*)context,
00131                                   flags);
00132             break;
00133 
00134         default:
00135             snmp_log(LOG_ERR, "unknown parse mode %d\n", parse_mode);
00136             break;
00137     }
00138 
00139 
00140     /*
00141      * close the stream, which will have the side effect of also closing
00142      * the file descriptor, so we need to reset it.
00143      */
00144     fclose(fin);
00145     f->fd = -1;
00146 
00147     return c;
00148 }
00149 
00150 netsnmp_container *
00151 netsnmp_text_token_container_from_file(const char *file, u_int flags,
00152                                        netsnmp_container *cin, void *context)
00153 {
00154     netsnmp_line_process_info  lpi;
00155     netsnmp_container         *c = cin, *c_rc;
00156     netsnmp_file              *fp;
00157 
00158     if (NULL == file)
00159         return NULL;
00160 
00161     /*
00162      * allocate file resources
00163      */
00164     fp = netsnmp_file_fill(NULL, file, O_RDONLY, 0, 0);
00165     if (NULL == fp) 
00166         return NULL;
00167 
00168     memset(&lpi, 0x0, sizeof(lpi));
00169     lpi.mem_size = sizeof(netsnmp_token_value_index);
00170     lpi.process = _process_line_tvi;
00171     lpi.user_context = context;
00172 
00173     if (NULL == c) {
00174         c = netsnmp_container_find("string:binary_array");
00175         if (NULL == c) {
00176             snmp_log(LOG_ERR,"malloc failed\n");
00177             netsnmp_file_release(fp);
00178             return NULL;
00179         }
00180     }
00181 
00182     c_rc = netsnmp_file_text_parse(fp, c, PM_USER_FUNCTION, 0, &lpi);
00183 
00184     /*
00185      * if we got a bad return and the user didn't pass us a container,
00186      * we need to release the container we allocated.
00187      */
00188     if ((NULL == c_rc) && (NULL == cin)) {
00189         CONTAINER_FREE(c);
00190         c = NULL;
00191     }
00192     else
00193         c = c_rc;
00194 
00195     /*
00196      * release file resources
00197      */
00198     netsnmp_file_release(fp);
00199     
00200     return c;
00201 }
00202 
00203 
00204 /*------------------------------------------------------------------
00205  *
00206  * Text file process modes helper functions
00207  *
00208  */
00209 
00214 void
00215 _pm_save_everything(FILE *f, netsnmp_container *cin, int flags)
00216 {
00217     char               line[STRINGMAX], *ptr;
00218     size_t             len;
00219 
00220     netsnmp_assert(NULL != f);
00221     netsnmp_assert(NULL != cin);
00222 
00223     while (fgets(line, sizeof(line), f) != NULL) {
00224 
00225         ptr = line;
00226         len = strlen(line) - 1;
00227         if (line[len] == '\n')
00228             line[len] = 0;
00229 
00230         /*
00231          * save blank line or comment?
00232          */
00233         if (flags & PM_FLAG_SKIP_WHITESPACE) {
00234             if (NULL == (ptr = skip_white(ptr)))
00235                 continue;
00236         }
00237 
00238         ptr = strdup(line);
00239         if (NULL == ptr) {
00240             snmp_log(LOG_ERR,"malloc failed\n");
00241             break;
00242         }
00243 
00244         CONTAINER_INSERT(cin,ptr);
00245     }
00246 }
00247 
00252 void
00253 _pm_save_index_string_string(FILE *f, netsnmp_container *cin,
00254                              int flags)
00255 {
00256     char                        line[STRINGMAX], *ptr;
00257     netsnmp_token_value_index  *tvi;
00258     size_t                      count = 0, len;
00259 
00260     netsnmp_assert(NULL != f);
00261     netsnmp_assert(NULL != cin);
00262 
00263     while (fgets(line, sizeof(line), f) != NULL) {
00264 
00265         ++count;
00266         ptr = line;
00267         len = strlen(line) - 1;
00268         if (line[len] == '\n')
00269             line[len] = 0;
00270 
00271         /*
00272          * save blank line or comment?
00273          */
00274         if (flags & PM_FLAG_SKIP_WHITESPACE) {
00275             if (NULL == (ptr = skip_white(ptr)))
00276                 continue;
00277         }
00278 
00279         tvi = SNMP_MALLOC_TYPEDEF(netsnmp_token_value_index);
00280         if (NULL == tvi) {
00281             snmp_log(LOG_ERR,"malloc failed\n");
00282             break;
00283         }
00284             
00285         /*
00286          * copy whole line, then set second pointer to
00287          * after token. One malloc, 2 strings!
00288          */
00289         tvi->index = count;
00290         tvi->token = strdup(line);
00291         if (NULL == tvi->token) {
00292             snmp_log(LOG_ERR,"malloc failed\n");
00293             free(tvi);
00294             break;
00295         }
00296         tvi->value.cp = skip_not_white(tvi->token);
00297         if (NULL != tvi->value.cp) {
00298             *(tvi->value.cp) = 0;
00299             ++(tvi->value.cp);
00300         }
00301         CONTAINER_INSERT(cin, tvi);
00302     }
00303 }
00304 
00309 void
00310 _pm_user_function(FILE *f, netsnmp_container *cin,
00311                   netsnmp_line_process_info *lpi, int flags)
00312 {
00313     char                        buf[STRINGMAX];
00314     netsnmp_line_info           li;
00315     void                       *mem = NULL;
00316     int                         rc;
00317 
00318     netsnmp_assert(NULL != f);
00319     netsnmp_assert(NULL != cin);
00320 
00321     /*
00322      * static buf, or does the user want the memory?
00323      */
00324     if (flags & PMLP_FLAG_ALLOC_LINE) {
00325         if (0 != lpi->line_max)
00326             li.line_max =  lpi->line_max;
00327         else
00328             li.line_max = STRINGMAX;
00329         li.line = calloc(li.line_max, 1);
00330         if (NULL == li.line) {
00331             snmp_log(LOG_ERR,"malloc failed\n");
00332             return;
00333         }
00334     }
00335     else {
00336         li.line = buf;
00337         li.line_max = sizeof(buf);
00338     }
00339         
00340     li.index = 0;
00341     while (fgets(li.line, li.line_max, f) != NULL) {
00342 
00343         ++li.index;
00344         li.start = li.line;
00345         li.line_len = strlen(li.line) - 1;
00346         if ((!(lpi->flags & PMLP_FLAG_LEAVE_NEWLINE)) &&
00347             (li.line[li.line_len] == '\n'))
00348             li.line[li.line_len] = 0;
00349         
00350         /*
00351          * save blank line or comment?
00352          */
00353         if (!(lpi->flags & PMLP_FLAG_PROCESS_WHITESPACE)) {
00354             if (NULL == (li.start = skip_white(li.start)))
00355                 continue;
00356         }
00357 
00358         /*
00359          *  do we need to allocate memory for the use?
00360          * if the last call didn't use the memory we allocated,
00361          * re-use it. Otherwise, allocate new chunk.
00362          */
00363         if ((0 != lpi->mem_size) && (NULL == mem)) {
00364             mem = calloc(lpi->mem_size, 1);
00365             if (NULL == mem) {
00366                 snmp_log(LOG_ERR,"malloc failed\n");
00367                 break;
00368             }
00369         }
00370 
00371         /*
00372          * do they want a copy ot the line?
00373          */
00374         if (lpi->flags & PMLP_FLAG_STRDUP_LINE) {
00375             li.start = strdup(li.start);
00376             if (NULL == li.start) {
00377                 snmp_log(LOG_ERR,"malloc failed\n");
00378                 break;
00379             }
00380         }
00381         else if (lpi->flags & PMLP_FLAG_ALLOC_LINE) {
00382             li.start = li.line;
00383         }
00384 
00385         /*
00386          * call the user function. If the function wants to save
00387          * the memory chunk, insert it in the container, the clear
00388          * pointer so we reallocate next time.
00389          */
00390         li.start_len = strlen(li.start);
00391         rc = (*lpi->process)(&li, mem, lpi);
00392         if (PMLP_RC_MEMORY_USED == rc) {
00393 
00394             if (!(lpi->flags & PMLP_FLAG_NO_CONTAINER))
00395                 CONTAINER_INSERT(cin, mem);
00396             
00397             mem = NULL;
00398             
00399             if (lpi->flags & PMLP_FLAG_ALLOC_LINE) {
00400                 li.line = calloc(li.line_max, 1);
00401                 if (NULL == li.line) {
00402                     snmp_log(LOG_ERR,"malloc failed\n");
00403                     break;
00404                 }
00405             }
00406         }
00407         else if (PMLP_RC_MEMORY_UNUSED == rc ) {
00408             /*
00409              * they didn't use the memory. if li.start was a strdup, we have
00410              * to release it. leave mem, we can re-use it (its a fixed size).
00411              */
00412             if (lpi->flags & PMLP_FLAG_STRDUP_LINE)
00413                 free(li.start); /* no point in SNMP_FREE */
00414         }
00415         else {
00416             if (PMLP_RC_STOP_PROCESSING != rc )
00417                 snmp_log(LOG_ERR, "unknown rc %d from text processor\n", rc);
00418             break;
00419         }
00420     }
00421     SNMP_FREE(mem);
00422 }
00423 
00424 /*------------------------------------------------------------------
00425  *
00426  * Test line process helper functions
00427  *
00428  */
00433 int
00434 _process_line_tvi(netsnmp_line_info *line_info, void *mem,
00435                   struct netsnmp_line_process_info_s* lpi)
00436 {
00437     netsnmp_token_value_index *tvi = (netsnmp_token_value_index *)mem;
00438     char                      *ptr;
00439 
00440     /*
00441      * get token
00442      */
00443     ptr = skip_not_white(line_info->start);
00444     if (NULL == ptr) {
00445         DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n",
00446                     line_info->start));
00447         return PMLP_RC_MEMORY_UNUSED;
00448     }
00449 
00450     /*
00451      * null terminate, search for value;
00452      */
00453     *(ptr++) = 0;
00454     ptr = skip_white(ptr);
00455     if (NULL == ptr) {
00456         DEBUGMSGTL(("text:util:tvi", "no value after token '%s'\n",
00457                     line_info->start));
00458         return PMLP_RC_MEMORY_UNUSED;
00459     }
00460 
00461     /*
00462      * get value
00463      */
00464     switch((int)lpi->user_context) {
00465 
00466         case PMLP_TYPE_UNSIGNED:
00467             tvi->value.ul = strtoul(ptr, NULL, 0);
00468             if ((errno == ERANGE) &&(ULONG_MAX == tvi->value.sl))
00469                 snmp_log(LOG_WARNING,"value overflow\n");
00470             break;
00471 
00472 
00473         case PMLP_TYPE_INTEGER:
00474             tvi->value.ul = strtol(ptr, NULL, 0);
00475             if ((errno == ERANGE) &&
00476                 ((LONG_MAX == tvi->value.sl) ||
00477                  (LONG_MIN == tvi->value.sl)))
00478                 snmp_log(LOG_WARNING,"value over/under-flow\n");
00479             break;
00480 
00481         case PMLP_TYPE_STRING:
00482             tvi->value.cp = strdup(ptr);
00483             break;
00484 
00485         case PMLP_TYPE_BOOLEAN:
00486             if (isdigit(*ptr))
00487                 tvi->value.ul = strtoul(ptr, NULL, 0);
00488             else if (strcasecmp(ptr,"true") == 0)
00489                 tvi->value.ul = 1;
00490             else if (strcasecmp(ptr,"false") == 0)
00491                 tvi->value.ul = 0;
00492             else {
00493                 snmp_log(LOG_WARNING,"bad value for boolean\n");
00494                 return PMLP_RC_MEMORY_UNUSED;
00495             }
00496             break;
00497 
00498         default:
00499             snmp_log(LOG_ERR,"unsupported value type %d\n",
00500                      (int)lpi->user_context);
00501             break;
00502     }
00503     
00504     /*
00505      * save token and value
00506      */
00507     tvi->token = strdup(line_info->start);
00508     tvi->index = line_info->index;
00509 
00510     return PMLP_RC_MEMORY_USED;
00511 }
00512 

net-snmpに対してSat Sep 5 13:14:27 2009に生成されました。  doxygen 1.4.7