git @ Cat's Eye Technologies Kosheri / master src / file.c
master

Tree @master (Download .tar.gz)

file.c @masterraw · history · blame

/*
 * file.c
 * Native processes for communicating with (reading, writing) files,
 * exposing a stream-like interface.
 */

#include <stdio.h>

#include "lib.h"
#include "process.h"
#include "file.h"

#ifdef DEBUG
#include "stream.h"
#include "portray.h"
#include "cmdline.h"
#endif

static void run(struct process *p)
{
	struct value msg;
	struct value response;
	struct process *sender;
	size_t result;
	char *buffer;
	size_t size;

	assert(p != NULL);
	assert(p->aux != NULL);

	while (process_dequeue(p, &msg)) {
#ifdef DEBUG
/*
		stream_write(NULL, process_err, "-->", 3);
		value_portray(process_err, &msg);
		stream_write(NULL, process_err, "<--", 3);
*/
#endif
		if (value_is_tuple(&msg)) {
			const char *tag = value_symbol_get_token(value_tuple_get_tag(&msg));
		        if (strcmp(tag, "write") == 0) {
				struct value *payload = value_tuple_fetch(&msg, 0);

				result = fwrite(
				    value_symbol_get_token(payload),
				    value_symbol_get_length(payload),
				    1, (FILE *)p->aux
				);
                        	if (result) {
					/* some kind of error occurred */
				}
		        } else if (strcmp(tag, "read") == 0) {
				sender = value_get_process(value_tuple_fetch(&msg, 0));
				size = value_get_integer(value_tuple_fetch(&msg, 1));

				buffer = value_symbol_new_buffer(&response, size);
				result = fread(buffer, size, 1, (FILE *)p->aux);
                        	if (result) {
					/* some kind of error occurred, or we just need more */
				}
				process_enqueue(sender, &response);
			} else if (strcmp(tag, "eof") == 0) {
				sender = value_get_process(value_tuple_fetch(&msg, 0));

				value_boolean_set(&response, feof((FILE *)p->aux));
				process_enqueue(sender, &response);
			} else if (strcmp(tag, "close") == 0) {
				fclose((FILE *)p->aux);
				p->aux = NULL;
			}
		}
	}

	p->waiting = 1;
}

static struct process *
file_fopen(FILE *file)
{
	struct process *p;

	p = process_new();
	p->run = run;
	p->aux = file;

	return p;
}

struct process *
file_open(const char *locator, const char *mode)
{
	FILE *f;

	if (strcmp(locator, "*stdin") == 0) {
		return file_fopen(stdin);
	}
	if (strcmp(locator, "*stdout") == 0) {
		return file_fopen(stdout);
	}
	if (strcmp(locator, "*stderr") == 0) {
		return file_fopen(stderr);
	}

	if ((f = fopen(locator, mode)) == NULL) {
		/* XXX only if mode contains a 'strict' char flag... */
		/* XXX this should use report.c somehow someday */
		fprintf(stderr,
		   "Could not open '%s' in mode '%s'", locator, mode);
		exit(1);
	}

	return file_fopen(f);
}