"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/extension/rwarray0.c" (20 Mar 2020, 10412 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


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 "rwarray0.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

    1 /*
    2  * rwarray.c - Builtin functions to binary read / write arrays to a file.
    3  *
    4  * Arnold Robbins
    5  * May 2009
    6  * Redone June 2012
    7  */
    8 
    9 /*
   10  * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2018, 2020,
   11  * the Free Software Foundation, Inc.
   12  *
   13  * This file is part of GAWK, the GNU implementation of the
   14  * AWK Programming Language.
   15  *
   16  * GAWK is free software; you can redistribute it and/or modify
   17  * it under the terms of the GNU General Public License as published by
   18  * the Free Software Foundation; either version 3 of the License, or
   19  * (at your option) any later version.
   20  *
   21  * GAWK is distributed in the hope that it will be useful,
   22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   24  * GNU General Public License for more details.
   25  *
   26  * You should have received a copy of the GNU General Public License
   27  * along with this program; if not, write to the Free Software
   28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   29  */
   30 
   31 #ifdef HAVE_CONFIG_H
   32 #include <config.h>
   33 #endif
   34 
   35 #include <stdio.h>
   36 #include <assert.h>
   37 #include <errno.h>
   38 #include <fcntl.h>
   39 #include <stdlib.h>
   40 #include <string.h>
   41 #include <unistd.h>
   42 
   43 #include <arpa/inet.h>
   44 #include <sys/types.h>
   45 #include <sys/stat.h>
   46 
   47 #include "gawkapi.h"
   48 
   49 #include "gettext.h"
   50 #define _(msgid)  gettext(msgid)
   51 #define N_(msgid) msgid
   52 
   53 #define MAGIC "awkrulz\n"
   54 #define MAJOR 3
   55 #define MINOR 0
   56 
   57 static const gawk_api_t *api;   /* for convenience macros to work */
   58 static awk_ext_id_t ext_id;
   59 static const char *ext_version = "rwarray0 extension: version 1.0";
   60 static awk_bool_t (*init_func)(void) = NULL;
   61 
   62 int plugin_is_GPL_compatible;
   63 
   64 static awk_bool_t write_array(int fd, awk_array_t array);
   65 static awk_bool_t write_elem(int fd, awk_element_t *element);
   66 static awk_bool_t write_value(int fd, awk_value_t *val);
   67 
   68 static awk_bool_t read_array(int fd, awk_array_t array);
   69 static awk_bool_t read_elem(int fd, awk_element_t *element);
   70 static awk_bool_t read_value(int fd, awk_value_t *value);
   71 
   72 /*
   73  * Format of array info:
   74  *
   75  * MAGIC        8 bytes
   76  * Major version    4 bytes - network order
   77  * Minor version    4 bytes - network order
   78  * Element count    4 bytes - network order
   79  * Elements
   80  *
   81  * For each element:
   82  * Length of index val: 4 bytes - network order
   83  * Index val as characters (N bytes)
   84  * Value type       4 bytes (0 = string, 1 = number, 2 = array)
   85  * IF string:
   86  *  Length of value 4 bytes
   87  *  Value as characters (N bytes)
   88  * ELSE IF number:
   89  *  8 bytes as native double
   90  * ELSE
   91  *  Element count
   92  *  Elements
   93  * END IF
   94  */
   95 
   96 /* do_writea --- write an array */
   97 
   98 static awk_value_t *
   99 do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused)
  100 {
  101     awk_value_t filename, array;
  102     int fd = -1;
  103     uint32_t major = MAJOR;
  104     uint32_t minor = MINOR;
  105 
  106     assert(result != NULL);
  107     make_number(0.0, result);
  108 
  109     if (nargs < 2)
  110         goto out;
  111 
  112     /* directory is first arg, array to dump is second */
  113     if (! get_argument(0, AWK_STRING, & filename)) {
  114         warning(ext_id, _("do_writea: argument 0 is not a string"));
  115         errno = EINVAL;
  116         goto done1;
  117     }
  118 
  119     if (! get_argument(1, AWK_ARRAY, & array)) {
  120         warning(ext_id, _("do_writea: argument 1 is not an array"));
  121         errno = EINVAL;
  122         goto done1;
  123     }
  124 
  125     /* open the file, if error, set ERRNO and return */
  126     fd = creat(filename.str_value.str, 0600);
  127     if (fd < 0)
  128         goto done1;
  129 
  130     if (write(fd, MAGIC, strlen(MAGIC)) != strlen(MAGIC))
  131         goto done1;
  132 
  133     major = htonl(major);
  134     if (write(fd, & major, sizeof(major)) != sizeof(major))
  135         goto done1;
  136 
  137     minor = htonl(minor);
  138     if (write(fd, & minor, sizeof(minor)) != sizeof(minor))
  139         goto done1;
  140 
  141     if (write_array(fd, array.array_cookie)) {
  142         make_number(1.0, result);
  143         goto done0;
  144     }
  145 
  146 done1:
  147     update_ERRNO_int(errno);
  148     unlink(filename.str_value.str);
  149 
  150 done0:
  151     close(fd);
  152 out:
  153     return result;
  154 }
  155 
  156 
  157 /* write_array --- write out an array or a sub-array */
  158 
  159 static awk_bool_t
  160 write_array(int fd, awk_array_t array)
  161 {
  162     uint32_t i;
  163     uint32_t count;
  164     awk_flat_array_t *flat_array;
  165 
  166     if (! flatten_array(array, & flat_array)) {
  167         warning(ext_id, _("write_array: could not flatten array"));
  168         return awk_false;
  169     }
  170 
  171     count = htonl(flat_array->count);
  172     if (write(fd, & count, sizeof(count)) != sizeof(count))
  173         return awk_false;
  174 
  175     for (i = 0; i < flat_array->count; i++) {
  176         if (! write_elem(fd, & flat_array->elements[i]))
  177             return awk_false;
  178     }
  179 
  180     if (! release_flattened_array(array, flat_array)) {
  181         warning(ext_id, _("write_array: could not release flattened array"));
  182         return awk_false;
  183     }
  184 
  185     return awk_true;
  186 }
  187 
  188 /* write_elem --- write out a single element */
  189 
  190 static awk_bool_t
  191 write_elem(int fd, awk_element_t *element)
  192 {
  193     uint32_t indexval_len;
  194     ssize_t write_count;
  195 
  196     indexval_len = htonl(element->index.str_value.len);
  197     if (write(fd, & indexval_len, sizeof(indexval_len)) != sizeof(indexval_len))
  198         return awk_false;
  199 
  200     if (element->index.str_value.len > 0) {
  201         write_count = write(fd, element->index.str_value.str,
  202                 element->index.str_value.len);
  203         if (write_count != (ssize_t) element->index.str_value.len)
  204             return awk_false;
  205     }
  206 
  207     return write_value(fd, & element->value);
  208 }
  209 
  210 /* write_value --- write a number or a string or a array */
  211 
  212 static awk_bool_t
  213 write_value(int fd, awk_value_t *val)
  214 {
  215     uint32_t code, len;
  216 
  217     if (val->val_type == AWK_ARRAY) {
  218         code = htonl(2);
  219         if (write(fd, & code, sizeof(code)) != sizeof(code))
  220             return awk_false;
  221         return write_array(fd, val->array_cookie);
  222     }
  223 
  224     if (val->val_type == AWK_NUMBER) {
  225         code = htonl(1);
  226         if (write(fd, & code, sizeof(code)) != sizeof(code))
  227             return awk_false;
  228 
  229         if (write(fd, & val->num_value, sizeof(val->num_value)) != sizeof(val->num_value))
  230             return awk_false;
  231     } else {
  232         code = 0;
  233         if (write(fd, & code, sizeof(code)) != sizeof(code))
  234             return awk_false;
  235 
  236         len = htonl(val->str_value.len);
  237         if (write(fd, & len, sizeof(len)) != sizeof(len))
  238             return awk_false;
  239 
  240         if (write(fd, val->str_value.str, val->str_value.len)
  241                 != (ssize_t) val->str_value.len)
  242             return awk_false;
  243     }
  244 
  245     return awk_true;
  246 }
  247 
  248 /* do_reada --- read an array */
  249 
  250 static awk_value_t *
  251 do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused)
  252 {
  253     awk_value_t filename, array;
  254     int fd = -1;
  255     uint32_t major;
  256     uint32_t minor;
  257     char magic_buf[30];
  258 
  259     assert(result != NULL);
  260     make_number(0.0, result);
  261 
  262     if (nargs < 2)
  263         goto out;
  264 
  265     /* directory is first arg, array to read is second */
  266     if (! get_argument(0, AWK_STRING, & filename)) {
  267         warning(ext_id, _("do_reada: argument 0 is not a string"));
  268         errno = EINVAL;
  269         goto done1;
  270     }
  271 
  272     if (! get_argument(1, AWK_ARRAY, & array)) {
  273         warning(ext_id, _("do_reada: argument 1 is not an array"));
  274         errno = EINVAL;
  275         goto done1;
  276     }
  277 
  278     fd = open(filename.str_value.str, O_RDONLY);
  279     if (fd < 0)
  280         goto done1;
  281 
  282     memset(magic_buf, '\0', sizeof(magic_buf));
  283     if (read(fd, magic_buf, strlen(MAGIC)) != strlen(MAGIC)) {
  284         errno = EBADF;
  285         goto done1;
  286     }
  287 
  288     if (strcmp(magic_buf, MAGIC) != 0) {
  289         errno = EBADF;
  290         goto done1;
  291     }
  292 
  293     if (read(fd, & major, sizeof(major)) != sizeof(major)) {
  294         errno = EBADF;
  295         goto done1;
  296     }
  297     major = ntohl(major);
  298 
  299     if (major != MAJOR) {
  300         errno = EBADF;
  301         goto done1;
  302     }
  303 
  304     if (read(fd, & minor, sizeof(minor)) != sizeof(minor)) {
  305         /* read() sets errno */
  306         goto done1;
  307     }
  308 
  309     minor = ntohl(minor);
  310     if (minor != MINOR) {
  311         errno = EBADF;
  312         goto done1;
  313     }
  314 
  315     if (! clear_array(array.array_cookie)) {
  316         errno = ENOMEM;
  317         warning(ext_id, _("do_reada: clear_array failed"));
  318         goto done1;
  319     }
  320 
  321     if (read_array(fd, array.array_cookie)) {
  322         make_number(1.0, result);
  323         goto done0;
  324     }
  325 
  326 done1:
  327     update_ERRNO_int(errno);
  328 done0:
  329     close(fd);
  330 out:
  331     return result;
  332 }
  333 
  334 
  335 /* read_array --- read in an array or sub-array */
  336 
  337 static awk_bool_t
  338 read_array(int fd, awk_array_t array)
  339 {
  340     uint32_t i;
  341     uint32_t count;
  342     awk_element_t new_elem;
  343 
  344     if (read(fd, & count, sizeof(count)) != sizeof(count)) {
  345         return awk_false;
  346     }
  347     count = ntohl(count);
  348 
  349     for (i = 0; i < count; i++) {
  350         if (read_elem(fd, & new_elem)) {
  351             /* add to array */
  352             if (! set_array_element_by_elem(array, & new_elem)) {
  353                 warning(ext_id, _("read_array: set_array_element failed"));
  354                 return awk_false;
  355             }
  356         } else
  357             break;
  358     }
  359 
  360     if (i != count)
  361         return awk_false;
  362 
  363     return awk_true;
  364 }
  365 
  366 /* read_elem --- read in a single element */
  367 
  368 static awk_bool_t
  369 read_elem(int fd, awk_element_t *element)
  370 {
  371     uint32_t index_len;
  372     static char *buffer;
  373     static uint32_t buflen;
  374     ssize_t ret;
  375 
  376     if ((ret = read(fd, & index_len, sizeof(index_len))) != sizeof(index_len)) {
  377         return awk_false;
  378     }
  379     index_len = ntohl(index_len);
  380 
  381     memset(element, 0, sizeof(*element));
  382 
  383     if (index_len > 0) {
  384         if (buffer == NULL) {
  385             // allocate buffer
  386             emalloc(buffer, char *, index_len, "read_elem");
  387             buflen = index_len;
  388         } else if (buflen < index_len) {
  389             // reallocate buffer
  390             char *cp = realloc(buffer, index_len);
  391 
  392             if (cp == NULL)
  393                 return awk_false;
  394 
  395             buffer = cp;
  396             buflen = index_len;
  397         }
  398 
  399         if (read(fd, buffer, index_len) != (ssize_t) index_len) {
  400             return awk_false;
  401         }
  402         make_const_string(buffer, index_len, & element->index);
  403     } else {
  404         make_null_string(& element->index);
  405     }
  406 
  407     if (! read_value(fd, & element->value))
  408         return awk_false;
  409 
  410     return awk_true;
  411 }
  412 
  413 /* read_value --- read a number or a string */
  414 
  415 static awk_bool_t
  416 read_value(int fd, awk_value_t *value)
  417 {
  418     uint32_t code, len;
  419 
  420     if (read(fd, & code, sizeof(code)) != sizeof(code))
  421         return awk_false;
  422 
  423     code = ntohl(code);
  424 
  425     if (code == 2) {
  426         awk_array_t array = create_array();
  427 
  428         if (read_array(fd, array) != 0)
  429             return awk_false;
  430 
  431         /* hook into value */
  432         value->val_type = AWK_ARRAY;
  433         value->array_cookie = array;
  434     } else if (code == 1) {
  435         double d;
  436 
  437         if (read(fd, & d, sizeof(d)) != sizeof(d))
  438             return awk_false;
  439 
  440         /* hook into value */
  441         value->val_type = AWK_NUMBER;
  442         value->num_value = d;
  443     } else {
  444         if (read(fd, & len, sizeof(len)) != sizeof(len)) {
  445             return awk_false;
  446         }
  447         len = ntohl(len);
  448         value->val_type = AWK_STRING;
  449         value->str_value.len = len;
  450         value->str_value.str = malloc(len + 1);
  451 
  452         if (read(fd, value->str_value.str, len) != (ssize_t) len) {
  453             free(value->str_value.str);
  454             return awk_false;
  455         }
  456         value->str_value.str[len] = '\0';
  457     }
  458 
  459     return awk_true;
  460 }
  461 
  462 static awk_ext_func_t func_table[] = {
  463     { "writea", do_writea, 2, 2, awk_false, NULL },
  464     { "reada", do_reada, 2, 2, awk_false, NULL },
  465 };
  466 
  467 
  468 /* define the dl_load function using the boilerplate macro */
  469 
  470 dl_load_func(func_table, rwarray, "")