#include <stdio.h>
#include <libmawk.h>
#include "vio_hash.h"


/*
	Purpose: register "/dev/foo" to a custion vio that does calculates some
	         sort of hash from all data written to it.
	         The hash files are set up in a dynamic manner: a hash is created
	         when the script opens it. It is possible to have at most 16 hashes.
	Run: ./app -f test.awk
*/

/* any hash ever existed will get into this array and won't be freed until
   the end of the app. This means if the script writes /dev/hash/3, the value
   is preserved even after close("/dev/hash/3"), to allow multiple reads.
   The hash value/seed is reset when the file is open for writing. */
mawk_vio_t *vf_hash[16];

mawk_vio_t *dispatch_open(mawk_state_t *MAWK, const char *name, mawk_vio_open_mode_t mode)
{
	/* hijack /dev/hash/* for the hash vio */
	if (strncmp(name, "/dev/hash/", 10) == 0) {
		int idx;
		char *end;
		idx = strtol(name+10, &end, 10);
		if (*end != '\0') {
			fprintf(stderr, "Warning: invalid hash %s: hash id not an integer\n", name);
			return NULL;
		}
		if ((idx < 0) || (idx >= 16)) {
			fprintf(stderr, "Warning: invalid hash %s: hash id out of range\n", name);
			return NULL;
		}

		/* allocate non-existing hashes or reopen existing ones */
		if (vf_hash[idx] == NULL)
			vf_hash[idx] = mawk_vio_hash_open(MAWK, name, mode);
		else
			mawk_vio_hash_reopen(MAWK, vf_hash[idx], mode);

		return vf_hash[idx];
	}

	/* call the original open function for any other name */
	return mawk_vio_orig_init.vopen(MAWK, name, mode);
}


void print_all_hashes(mawk_state_t *m, char *banner)
{
	int n;
	printf("app: %s\n", banner);
	for(n = 0; n < 16; n++) {
		if (vf_hash[n] != NULL)
			printf(" /dev/hash/%d=%d\n", n, mawk_vio_hash_val(m, vf_hash[n]));
	}
}

int main(int argc, char **argv)
{
	mawk_state_t *m;


	/* init a context in stages */
	m = libmawk_initialize_stage1();              /* alloc context */

	m->vio_init.vopen = dispatch_open;

	/* set up all pipes */
	mawk_vio_orig_setup_stdio(m, 0, 1, 1); /* whether bind to the app's stdio: 0,1,1=stdin,stdout,stderr */

	m = libmawk_initialize_stage2(m, argc, argv); /* set up with CLI arguments */
	m = libmawk_initialize_stage3(m);             /* execute BEGIN */

	if (m == NULL) {
		fprintf(stderr, "libmawk_initialize failed, exiting\n");
		return 1;
	}

	print_all_hashes(m, "hash after begin");

	/* run END */
	libmawk_uninitialize_stage1(m);

	print_all_hashes(m, "hash after end");

	/* free things */
	libmawk_uninitialize_stage2(m);

	/* no need to free vf_hash[]:
	   - uninitialize_stage2 will close all existing files
	   - final destruction of m will free any allocation left
	*/
	return 0;
}

