"Fossies" - the Fresh Open Source Software Archive

Member "mlr-5.6.2/c/mapping/mapper_cut.c" (2 Sep 2019, 7576 Bytes) of package /linux/misc/mlr-5.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mapper_cut.c" see the Fossies "Dox" file reference documentation.

    1 #include "lib/mlrutil.h"
    2 #include "lib/mlrregex.h"
    3 #include "containers/lrec.h"
    4 #include "containers/sllv.h"
    5 #include "containers/hss.h"
    6 #include "containers/mixutil.h"
    7 #include "mapping/mappers.h"
    8 #include "cli/argparse.h"
    9 
   10 typedef struct _mapper_cut_state_t {
   11     ap_state_t* pargp;
   12     slls_t*  pfield_name_list;
   13     hss_t*   pfield_name_set;
   14     regex_t* regexes;
   15     int      nregex;
   16     int      do_arg_order;
   17     int      do_complement;
   18 } mapper_cut_state_t;
   19 
   20 static void      mapper_cut_usage(FILE* o, char* argv0, char* verb);
   21 static mapper_t* mapper_cut_parse_cli(int* pargi, int argc, char** argv,
   22     cli_reader_opts_t* _, cli_writer_opts_t* __);
   23 static mapper_t* mapper_cut_alloc(ap_state_t* pargp, slls_t* pfield_name_list,
   24     int do_arg_order, int do_complement, int do_regexes);
   25 static void      mapper_cut_free(mapper_t* pmapper, context_t* _);
   26 static sllv_t*   mapper_cut_process_no_regexes(lrec_t* pinrec, context_t* pctx, void* pvstate);
   27 static sllv_t*   mapper_cut_process_with_regexes(lrec_t* pinrec, context_t* pctx, void* pvstate);
   28 
   29 // ----------------------------------------------------------------
   30 mapper_setup_t mapper_cut_setup = {
   31     .verb = "cut",
   32     .pusage_func = mapper_cut_usage,
   33     .pparse_func = mapper_cut_parse_cli,
   34     .ignores_input = FALSE,
   35 };
   36 
   37 // ----------------------------------------------------------------
   38 static void mapper_cut_usage(FILE* o, char* argv0, char* verb) {
   39     fprintf(o, "Usage: %s %s [options]\n", argv0, verb);
   40     fprintf(o, "Passes through input records with specified fields included/excluded.\n");
   41     fprintf(o, "-f {a,b,c}       Field names to include for cut.\n");
   42     fprintf(o, "-o               Retain fields in the order specified here in the argument list.\n");
   43     fprintf(o, "                 Default is to retain them in the order found in the input data.\n");
   44     fprintf(o, "-x|--complement  Exclude, rather than include, field names specified by -f.\n");
   45     fprintf(o, "-r               Treat field names as regular expressions. \"ab\", \"a.*b\" will\n");
   46     fprintf(o, "                 match any field name containing the substring \"ab\" or matching\n");
   47     fprintf(o, "                 \"a.*b\", respectively; anchors of the form \"^ab$\", \"^a.*b$\" may\n");
   48     fprintf(o, "                 be used. The -o flag is ignored when -r is present.\n");
   49     fprintf(o, "Examples:\n");
   50     fprintf(o, "  %s %s -f hostname,status\n", argv0, verb);
   51     fprintf(o, "  %s %s -x -f hostname,status\n", argv0, verb);
   52     fprintf(o, "  %s %s -r -f '^status$,sda[0-9]'\n", argv0, verb);
   53     fprintf(o, "  %s %s -r -f '^status$,\"sda[0-9]\"'\n", argv0, verb);
   54     fprintf(o, "  %s %s -r -f '^status$,\"sda[0-9]\"i' (this is case-insensitive)\n", argv0, verb);
   55 }
   56 
   57 // ----------------------------------------------------------------
   58 static mapper_t* mapper_cut_parse_cli(int* pargi, int argc, char** argv,
   59     cli_reader_opts_t* _, cli_writer_opts_t* __)
   60 {
   61     slls_t* pfield_name_list  = NULL;
   62     int     do_arg_order  = FALSE;
   63     int     do_complement = FALSE;
   64     int     do_regexes    = FALSE;
   65 
   66     char* verb = argv[(*pargi)++];
   67 
   68     ap_state_t* pstate = ap_alloc();
   69     ap_define_string_list_flag(pstate, "-f",    &pfield_name_list);
   70     ap_define_true_flag(pstate, "-o",           &do_arg_order);
   71     ap_define_true_flag(pstate, "-x",           &do_complement);
   72     ap_define_true_flag(pstate, "--complement", &do_complement);
   73     ap_define_true_flag(pstate, "-r",           &do_regexes);
   74 
   75     if (!ap_parse(pstate, verb, pargi, argc, argv)) {
   76         mapper_cut_usage(stderr, argv[0], verb);
   77         return NULL;
   78     }
   79 
   80     if (pfield_name_list == NULL) {
   81         mapper_cut_usage(stderr, argv[0], verb);
   82         return NULL;
   83     }
   84 
   85     return mapper_cut_alloc(pstate, pfield_name_list, do_arg_order, do_complement, do_regexes);
   86 }
   87 
   88 // ----------------------------------------------------------------
   89 static mapper_t* mapper_cut_alloc(ap_state_t* pargp, slls_t* pfield_name_list,
   90     int do_arg_order, int do_complement, int do_regexes)
   91 {
   92     mapper_t* pmapper = mlr_malloc_or_die(sizeof(mapper_t));
   93 
   94     mapper_cut_state_t* pstate = mlr_malloc_or_die(sizeof(mapper_cut_state_t));
   95     pstate->pargp = pargp;
   96     if (!do_regexes) {
   97         pstate->pfield_name_list   = pfield_name_list;
   98         slls_reverse(pstate->pfield_name_list);
   99         pstate->pfield_name_set    = hss_from_slls(pfield_name_list);
  100         pstate->nregex             = 0;
  101         pstate->regexes            = NULL;
  102         pmapper->pprocess_func     = mapper_cut_process_no_regexes;
  103     } else {
  104         pstate->pfield_name_list   = NULL;
  105         pstate->pfield_name_set    = NULL;
  106         pstate->nregex = pfield_name_list->length;
  107         pstate->regexes = mlr_malloc_or_die(pstate->nregex * sizeof(regex_t));
  108         int i = 0;
  109         for (sllse_t* pe = pfield_name_list->phead; pe != NULL; pe = pe->pnext, i++) {
  110             // Let them type in a.*b if they want, or "a.*b", or "a.*b"i.
  111             // Strip off the leading " and trailing " or "i.
  112             regcomp_or_die_quoted(&pstate->regexes[i], pe->value, REG_NOSUB);
  113         }
  114         slls_free(pfield_name_list);
  115         pmapper->pprocess_func = mapper_cut_process_with_regexes;
  116     }
  117     pstate->do_arg_order  = do_arg_order;
  118     pstate->do_complement = do_complement;
  119 
  120     pmapper->pvstate      = (void*)pstate;
  121     pmapper->pfree_func   = mapper_cut_free;
  122 
  123     return pmapper;
  124 }
  125 
  126 static void mapper_cut_free(mapper_t* pmapper, context_t* _) {
  127     mapper_cut_state_t* pstate = pmapper->pvstate;
  128     slls_free(pstate->pfield_name_list);
  129     hss_free(pstate->pfield_name_set);
  130     for (int i = 0; i < pstate->nregex; i++)
  131         regfree(&pstate->regexes[i]);
  132     free(pstate->regexes);
  133     ap_free(pstate->pargp);
  134     free(pstate);
  135     free(pmapper);
  136 }
  137 
  138 // ----------------------------------------------------------------
  139 static sllv_t* mapper_cut_process_no_regexes(lrec_t* pinrec, context_t* pctx, void* pvstate) {
  140     if (pinrec != NULL) {
  141         mapper_cut_state_t* pstate = (mapper_cut_state_t*)pvstate;
  142         if (!pstate->do_complement) {
  143             // Loop over the record and free the fields not in the
  144             // to-be-retained set, being careful about the fact that we're
  145             // modifying what we're looping over.
  146             for (lrece_t* pe = pinrec->phead; pe != NULL; /* next in loop */) {
  147                 if (!hss_has(pstate->pfield_name_set, pe->key)) {
  148                     lrece_t* pf = pe->pnext;
  149                     lrec_remove(pinrec, pe->key);
  150                     pe = pf;
  151                 } else {
  152                     pe = pe->pnext;
  153                 }
  154             }
  155             if (pstate->do_arg_order) {
  156                 // OK since the field-name list was reversed at construction time.
  157                 for (sllse_t* pe = pstate->pfield_name_list->phead; pe != NULL; pe = pe->pnext) {
  158                     char* field_name = pe->value;
  159                     lrec_move_to_head(pinrec, field_name);
  160                 }
  161             }
  162             return sllv_single(pinrec);
  163         } else {
  164             for (sllse_t* pe = pstate->pfield_name_list->phead; pe != NULL; pe = pe->pnext) {
  165                 char* field_name = pe->value;
  166                 lrec_remove(pinrec, field_name);
  167             }
  168             return sllv_single(pinrec);
  169         }
  170     }
  171     else {
  172         return sllv_single(NULL);
  173     }
  174 }
  175 
  176 // ----------------------------------------------------------------
  177 static sllv_t* mapper_cut_process_with_regexes(lrec_t* pinrec, context_t* pctx, void* pvstate) {
  178     if (pinrec != NULL) {
  179         mapper_cut_state_t* pstate = (mapper_cut_state_t*)pvstate;
  180         // Loop over the record and free the fields to be discarded, being
  181         // careful about the fact that we're modifying what we're looping over.
  182         for (lrece_t* pe = pinrec->phead; pe != NULL; /* next in loop */) {
  183             int matches_any = FALSE;
  184             for (int i = 0; i < pstate->nregex; i++) {
  185                 if (regmatch_or_die(&pstate->regexes[i], pe->key, 0, NULL)) {
  186                     matches_any = TRUE;
  187                     break;
  188                 }
  189             }
  190             if (matches_any ^ pstate->do_complement) {
  191                 pe = pe->pnext;
  192             } else {
  193                 lrece_t* pf = pe->pnext;
  194                 lrec_remove(pinrec, pe->key);
  195                 pe = pf;
  196             }
  197         }
  198         return sllv_single(pinrec);
  199     }
  200     else {
  201         return sllv_single(NULL);
  202     }
  203 }