Blame extension/rwarray0.c

Packit Service f629e6
/*
Packit Service f629e6
 * rwarray.c - Builtin functions to binary read / write arrays to a file.
Packit Service f629e6
 *
Packit Service f629e6
 * Arnold Robbins
Packit Service f629e6
 * May 2009
Packit Service f629e6
 * Redone June 2012
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 2009, 2010, 2011, 2012, 2013 the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_CONFIG_H
Packit Service f629e6
#include <config.h>
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#include <stdio.h>
Packit Service f629e6
#include <assert.h>
Packit Service f629e6
#include <errno.h>
Packit Service f629e6
#include <fcntl.h>
Packit Service f629e6
#include <stdlib.h>
Packit Service f629e6
#include <string.h>
Packit Service f629e6
#include <unistd.h>
Packit Service f629e6
Packit Service f629e6
#include <arpa/inet.h>
Packit Service f629e6
#include <sys/types.h>
Packit Service f629e6
#include <sys/stat.h>
Packit Service f629e6
Packit Service f629e6
#include "gawkapi.h"
Packit Service f629e6
Packit Service f629e6
#include "gettext.h"
Packit Service f629e6
#define _(msgid)  gettext(msgid)
Packit Service f629e6
#define N_(msgid) msgid
Packit Service f629e6
Packit Service f629e6
#define MAGIC "awkrulz\n"
Packit Service f629e6
#define MAJOR 3
Packit Service f629e6
#define MINOR 0
Packit Service f629e6
Packit Service f629e6
static const gawk_api_t *api;	/* for convenience macros to work */
Packit Service f629e6
static awk_ext_id_t ext_id;
Packit Service f629e6
static const char *ext_version = "rwarray0 extension: version 1.0";
Packit Service f629e6
static awk_bool_t (*init_func)(void) = NULL;
Packit Service f629e6
Packit Service f629e6
int plugin_is_GPL_compatible;
Packit Service f629e6
Packit Service f629e6
static awk_bool_t write_array(int fd, awk_array_t array);
Packit Service f629e6
static awk_bool_t write_elem(int fd, awk_element_t *element);
Packit Service f629e6
static awk_bool_t write_value(int fd, awk_value_t *val);
Packit Service f629e6
Packit Service f629e6
static awk_bool_t read_array(int fd, awk_array_t array);
Packit Service f629e6
static awk_bool_t read_elem(int fd, awk_element_t *element);
Packit Service f629e6
static awk_bool_t read_value(int fd, awk_value_t *value);
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Format of array info:
Packit Service f629e6
 *
Packit Service f629e6
 * MAGIC		8 bytes
Packit Service f629e6
 * Major version	4 bytes - network order
Packit Service f629e6
 * Minor version	4 bytes - network order
Packit Service f629e6
 * Element count	4 bytes - network order
Packit Service f629e6
 * Elements
Packit Service f629e6
 *
Packit Service f629e6
 * For each element:
Packit Service f629e6
 * Length of index val:	4 bytes - network order
Packit Service f629e6
 * Index val as characters (N bytes)
Packit Service f629e6
 * Value type		4 bytes (0 = string, 1 = number, 2 = array)
Packit Service f629e6
 * IF string:
Packit Service f629e6
 * 	Length of value	4 bytes
Packit Service f629e6
 * 	Value as characters (N bytes)
Packit Service f629e6
 * ELSE IF number:
Packit Service f629e6
 * 	8 bytes as native double
Packit Service f629e6
 * ELSE
Packit Service f629e6
 * 	Element count
Packit Service f629e6
 * 	Elements
Packit Service f629e6
 * END IF
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/* do_writea --- write an array */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_writea(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t filename, array;
Packit Service f629e6
	int fd = -1;
Packit Service f629e6
	uint32_t major = MAJOR;
Packit Service f629e6
	uint32_t minor = MINOR;
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
	make_number(0.0, result);
Packit Service f629e6
Packit Service f629e6
	if (nargs < 2)
Packit Service f629e6
		goto out;
Packit Service f629e6
Packit Service f629e6
	/* directory is first arg, array to dump is second */
Packit Service f629e6
	if (! get_argument(0, AWK_STRING, & filename)) {
Packit Service f629e6
		fprintf(stderr, _("do_writea: argument 0 is not a string\n"));
Packit Service f629e6
		errno = EINVAL;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! get_argument(1, AWK_ARRAY, & array)) {
Packit Service f629e6
		fprintf(stderr, _("do_writea: argument 1 is not an array\n"));
Packit Service f629e6
		errno = EINVAL;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	/* open the file, if error, set ERRNO and return */
Packit Service f629e6
	fd = creat(filename.str_value.str, 0600);
Packit Service f629e6
	if (fd < 0)
Packit Service f629e6
		goto done1;
Packit Service f629e6
Packit Service f629e6
	if (write(fd, MAGIC, strlen(MAGIC)) != strlen(MAGIC))
Packit Service f629e6
		goto done1;
Packit Service f629e6
Packit Service f629e6
	major = htonl(major);
Packit Service f629e6
	if (write(fd, & major, sizeof(major)) != sizeof(major))
Packit Service f629e6
		goto done1;
Packit Service f629e6
Packit Service f629e6
	minor = htonl(minor);
Packit Service f629e6
	if (write(fd, & minor, sizeof(minor)) != sizeof(minor))
Packit Service f629e6
		goto done1;
Packit Service f629e6
Packit Service f629e6
	if (write_array(fd, array.array_cookie)) {
Packit Service f629e6
		make_number(1.0, result);
Packit Service f629e6
		goto done0;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
done1:
Packit Service f629e6
	update_ERRNO_int(errno);
Packit Service f629e6
	unlink(filename.str_value.str);
Packit Service f629e6
Packit Service f629e6
done0:
Packit Service f629e6
	close(fd);
Packit Service f629e6
out:
Packit Service f629e6
	return result;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* write_array --- write out an array or a sub-array */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
write_array(int fd, awk_array_t array)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t i;
Packit Service f629e6
	uint32_t count;
Packit Service f629e6
	awk_flat_array_t *flat_array;
Packit Service f629e6
Packit Service f629e6
	if (! flatten_array(array, & flat_array)) {
Packit Service f629e6
		fprintf(stderr, _("write_array: could not flatten array\n"));
Packit Service f629e6
		return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	count = htonl(flat_array->count);
Packit Service f629e6
	if (write(fd, & count, sizeof(count)) != sizeof(count))
Packit Service f629e6
		return awk_false;
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < flat_array->count; i++) {
Packit Service f629e6
		if (! write_elem(fd, & flat_array->elements[i]))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! release_flattened_array(array, flat_array)) {
Packit Service f629e6
		fprintf(stderr, _("write_array: could not release flattened array\n"));
Packit Service f629e6
		return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return awk_true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* write_elem --- write out a single element */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
write_elem(int fd, awk_element_t *element)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t indexval_len;
Packit Service f629e6
	ssize_t write_count;
Packit Service f629e6
Packit Service f629e6
	indexval_len = htonl(element->index.str_value.len);
Packit Service f629e6
	if (write(fd, & indexval_len, sizeof(indexval_len)) != sizeof(indexval_len))
Packit Service f629e6
		return awk_false;
Packit Service f629e6
Packit Service f629e6
	if (element->index.str_value.len > 0) {
Packit Service f629e6
		write_count = write(fd, element->index.str_value.str,
Packit Service f629e6
				element->index.str_value.len);
Packit Service f629e6
		if (write_count != (ssize_t) element->index.str_value.len)
Packit Service f629e6
			return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return write_value(fd, & element->value);
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* write_value --- write a number or a string or a array */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
write_value(int fd, awk_value_t *val)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t code, len;
Packit Service f629e6
Packit Service f629e6
	if (val->val_type == AWK_ARRAY) {
Packit Service f629e6
		code = htonl(2);
Packit Service f629e6
		if (write(fd, & code, sizeof(code)) != sizeof(code))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
		return write_array(fd, val->array_cookie);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (val->val_type == AWK_NUMBER) {
Packit Service f629e6
		code = htonl(1);
Packit Service f629e6
		if (write(fd, & code, sizeof(code)) != sizeof(code))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
Packit Service f629e6
		if (write(fd, & val->num_value, sizeof(val->num_value)) != sizeof(val->num_value))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
	} else {
Packit Service f629e6
		code = 0;
Packit Service f629e6
		if (write(fd, & code, sizeof(code)) != sizeof(code))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
Packit Service f629e6
		len = htonl(val->str_value.len);
Packit Service f629e6
		if (write(fd, & len, sizeof(len)) != sizeof(len))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
Packit Service f629e6
		if (write(fd, val->str_value.str, val->str_value.len)
Packit Service f629e6
				!= (ssize_t) val->str_value.len)
Packit Service f629e6
			return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return awk_true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* do_reada --- read an array */
Packit Service f629e6
Packit Service f629e6
static awk_value_t *
Packit Service f629e6
do_reada(int nargs, awk_value_t *result, struct awk_ext_func *unused)
Packit Service f629e6
{
Packit Service f629e6
	awk_value_t filename, array;
Packit Service f629e6
	int fd = -1;
Packit Service f629e6
	uint32_t major;
Packit Service f629e6
	uint32_t minor;
Packit Service f629e6
	char magic_buf[30];
Packit Service f629e6
Packit Service f629e6
	assert(result != NULL);
Packit Service f629e6
	make_number(0.0, result);
Packit Service f629e6
Packit Service f629e6
	if (nargs < 2)
Packit Service f629e6
		goto out;
Packit Service f629e6
Packit Service f629e6
	/* directory is first arg, array to read is second */
Packit Service f629e6
	if (! get_argument(0, AWK_STRING, & filename)) {
Packit Service f629e6
		fprintf(stderr, _("do_reada: argument 0 is not a string\n"));
Packit Service f629e6
		errno = EINVAL;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! get_argument(1, AWK_ARRAY, & array)) {
Packit Service f629e6
		fprintf(stderr, _("do_reada: argument 1 is not an array\n"));
Packit Service f629e6
		errno = EINVAL;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	fd = open(filename.str_value.str, O_RDONLY);
Packit Service f629e6
	if (fd < 0)
Packit Service f629e6
		goto done1;
Packit Service f629e6
Packit Service f629e6
	memset(magic_buf, '\0', sizeof(magic_buf));
Packit Service f629e6
	if (read(fd, magic_buf, strlen(MAGIC)) != strlen(MAGIC)) {
Packit Service f629e6
		errno = EBADF;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (strcmp(magic_buf, MAGIC) != 0) {
Packit Service f629e6
		errno = EBADF;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (read(fd, & major, sizeof(major)) != sizeof(major)) {
Packit Service f629e6
		errno = EBADF;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
	major = ntohl(major);
Packit Service f629e6
Packit Service f629e6
	if (major != MAJOR) {
Packit Service f629e6
		errno = EBADF;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (read(fd, & minor, sizeof(minor)) != sizeof(minor)) {
Packit Service f629e6
		/* read() sets errno */
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	minor = ntohl(minor);
Packit Service f629e6
	if (minor != MINOR) {
Packit Service f629e6
		errno = EBADF;
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! clear_array(array.array_cookie)) {
Packit Service f629e6
		errno = ENOMEM;
Packit Service f629e6
		fprintf(stderr, _("do_reada: clear_array failed\n"));
Packit Service f629e6
		goto done1;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (read_array(fd, array.array_cookie)) {
Packit Service f629e6
		make_number(1.0, result);
Packit Service f629e6
		goto done0;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
done1:
Packit Service f629e6
	update_ERRNO_int(errno);
Packit Service f629e6
done0:
Packit Service f629e6
	close(fd);
Packit Service f629e6
out:
Packit Service f629e6
	return result;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* read_array --- read in an array or sub-array */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
read_array(int fd, awk_array_t array)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t i;
Packit Service f629e6
	uint32_t count;
Packit Service f629e6
	awk_element_t new_elem;
Packit Service f629e6
Packit Service f629e6
	if (read(fd, & count, sizeof(count)) != sizeof(count)) {
Packit Service f629e6
		return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
	count = ntohl(count);
Packit Service f629e6
Packit Service f629e6
	for (i = 0; i < count; i++) {
Packit Service f629e6
		if (read_elem(fd, & new_elem)) {
Packit Service f629e6
			/* add to array */
Packit Service f629e6
			if (! set_array_element_by_elem(array, & new_elem)) {
Packit Service f629e6
				fprintf(stderr, _("read_array: set_array_element failed\n"));
Packit Service f629e6
				return awk_false;
Packit Service f629e6
			}
Packit Service f629e6
		} else
Packit Service f629e6
			break;
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (i != count)
Packit Service f629e6
		return awk_false;
Packit Service f629e6
Packit Service f629e6
	return awk_true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* read_elem --- read in a single element */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
read_elem(int fd, awk_element_t *element)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t index_len;
Packit Service f629e6
	static char *buffer;
Packit Service f629e6
	static uint32_t buflen;
Packit Service f629e6
	ssize_t ret;
Packit Service f629e6
Packit Service f629e6
	if ((ret = read(fd, & index_len, sizeof(index_len))) != sizeof(index_len)) {
Packit Service f629e6
		return awk_false;
Packit Service f629e6
	}
Packit Service f629e6
	index_len = ntohl(index_len);
Packit Service f629e6
Packit Service f629e6
	memset(element, 0, sizeof(*element));
Packit Service f629e6
Packit Service f629e6
	if (index_len > 0) {
Packit Service f629e6
		if (buffer == NULL) {
Packit Service f629e6
			// allocate buffer
Packit Service f629e6
			emalloc(buffer, char *, index_len, "read_elem");
Packit Service f629e6
			buflen = index_len;
Packit Service f629e6
		} else if (buflen < index_len) {
Packit Service f629e6
			// reallocate buffer
Packit Service f629e6
			char *cp = realloc(buffer, index_len);
Packit Service f629e6
Packit Service f629e6
			if (cp == NULL)
Packit Service f629e6
				return awk_false;
Packit Service f629e6
Packit Service f629e6
			buffer = cp;
Packit Service f629e6
			buflen = index_len;
Packit Service f629e6
		}
Packit Service f629e6
Packit Service f629e6
		if (read(fd, buffer, index_len) != (ssize_t) index_len) {
Packit Service f629e6
			return awk_false;
Packit Service f629e6
		}
Packit Service f629e6
		make_const_string(buffer, index_len, & element->index);
Packit Service f629e6
	} else {
Packit Service f629e6
		make_null_string(& element->index);
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if (! read_value(fd, & element->value))
Packit Service f629e6
		return awk_false;
Packit Service f629e6
Packit Service f629e6
	return awk_true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
/* read_value --- read a number or a string */
Packit Service f629e6
Packit Service f629e6
static awk_bool_t
Packit Service f629e6
read_value(int fd, awk_value_t *value)
Packit Service f629e6
{
Packit Service f629e6
	uint32_t code, len;
Packit Service f629e6
Packit Service f629e6
	if (read(fd, & code, sizeof(code)) != sizeof(code))
Packit Service f629e6
		return awk_false;
Packit Service f629e6
Packit Service f629e6
	code = ntohl(code);
Packit Service f629e6
Packit Service f629e6
	if (code == 2) {
Packit Service f629e6
		awk_array_t array = create_array();
Packit Service f629e6
Packit Service f629e6
		if (read_array(fd, array) != 0)
Packit Service f629e6
			return awk_false;
Packit Service f629e6
Packit Service f629e6
		/* hook into value */
Packit Service f629e6
		value->val_type = AWK_ARRAY;
Packit Service f629e6
		value->array_cookie = array;
Packit Service f629e6
	} else if (code == 1) {
Packit Service f629e6
		double d;
Packit Service f629e6
Packit Service f629e6
		if (read(fd, & d, sizeof(d)) != sizeof(d))
Packit Service f629e6
			return awk_false;
Packit Service f629e6
Packit Service f629e6
		/* hook into value */
Packit Service f629e6
		value->val_type = AWK_NUMBER;
Packit Service f629e6
		value->num_value = d;
Packit Service f629e6
	} else {
Packit Service f629e6
		if (read(fd, & len, sizeof(len)) != sizeof(len)) {
Packit Service f629e6
			return awk_false;
Packit Service f629e6
		}
Packit Service f629e6
		len = ntohl(len);
Packit Service f629e6
		value->val_type = AWK_STRING;
Packit Service f629e6
		value->str_value.len = len;
Packit Service f629e6
		value->str_value.str = malloc(len + 1);
Packit Service f629e6
Packit Service f629e6
		if (read(fd, value->str_value.str, len) != (ssize_t) len) {
Packit Service f629e6
			free(value->str_value.str);
Packit Service f629e6
			return awk_false;
Packit Service f629e6
		}
Packit Service f629e6
		value->str_value.str[len] = '\0';
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	return awk_true;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
static awk_ext_func_t func_table[] = {
Packit Service f629e6
	{ "writea", do_writea, 2, 2, awk_false, NULL },
Packit Service f629e6
	{ "reada", do_reada, 2, 2, awk_false, NULL },
Packit Service f629e6
};
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* define the dl_load function using the boilerplate macro */
Packit Service f629e6
Packit Service f629e6
dl_load_func(func_table, rwarray, "")