view file.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
parents 20d40cb8abf3
children
line wrap: on
line source

#include "structs.h"
#include "datum.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int vis_file_from_string(datum ** inputlist, queue_entry * worker_entry)
{
	datum * output;
	file_data * file;
	output = new_datum(BUILTIN_TYPE_FILE, 1, sizeof(file_data), worker_entry->instance->def->program);
	file = output->c.generic.data;
	file->shared = malloc(sizeof(shared_file) + inputlist[0]->c.generic.len-1);
	strcpy(file->shared->name, inputlist[0]->c.generic.data);
	DEBUGPRINTF("File from string name: %s\n", file->shared->name);
	release_ref(inputlist[0]);
	file->shared->status = FILE_NOSIZE;
	VIS_InitializeCriticalSection(file->shared->lock);
	file->shared->ref_count = 1;
	file->offset = 0;
	inputlist[0] = output;
	return 0;
}

void vis_file_read_open_check(file_data * file)
{
	switch(file->shared->status)
	{
		case FILE_NOSIZE:
		case FILE_CLOSED:
			DEBUGPUTS("File is closed, opening...\n");
			DEBUGPRINTF("File name: %s\n", file->shared->name);
			file->shared->file = fopen(file->shared->name, "rb");
			if(!file->shared->file)
			{
				file->shared->status = FILE_CANT_OPEN;
				file->shared->size = 0;
				break;
			}
			if(file->shared->status == FILE_NOSIZE)
			{
				DEBUGPUTS("Getting file size.\n");
				fseek(file->shared->file, 0, SEEK_END);
				file->shared->size = ftell(file->shared->file);
				DEBUGPRINTF("File size: %d.\n", file->shared->size);
			}
				
			file->shared->status = FILE_READ;
			break;
		default://file is already open
			break;
	}
	DEBUGPRINTF("Seeking to %d\n", file->offset);
	if(file->shared->file)
		fseek(file->shared->file, file->offset, SEEK_SET);
	DEBUGPUTS("Done.\n");
}

int vis_file_get_fstring(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	datum * output = new_datum(BUILTIN_TYPE_STRING, 1, inputlist[1]->c.integers.num_a+1, worker_entry->instance->def->program);
	inputlist[0] = copy_datum(inputlist[0], 0);
	if(inputlist[1]->c.integers.num_a > 0)
	{
		file = (file_data *)inputlist[0]->c.generic.data;
		VIS_EnterCriticalSection(file->shared->lock);
			vis_file_read_open_check(file);
			fread(output->c.generic.data,1,inputlist[1]->c.integers.num_a, file->shared->file);
		VIS_LeaveCriticalSection(file->shared->lock);
		file->offset += inputlist[1]->c.integers.num_a;
	}
	((char *)output->c.generic.data)[inputlist[1]->c.integers.num_a] = '\0';
	release_ref(inputlist[1]);
	inputlist[1] = output;
	return 0;
}
#define	FILE_SEARCH_BUFFER_SIZE	512

typedef struct bufferlist
{
	char buffer[FILE_SEARCH_BUFFER_SIZE];
	int index;
	struct bufferlist * next;
} bufferlist;

int vis_file_get_dstring(datum ** inputlist, queue_entry * worker_entry)
{
	BOOL found = FALSE;
	bufferlist buffers;
	bufferlist * current, *temp,*temp2;
	int i,j,k,startk;
	int found_entry;
	int string_offset;
	int search_offset;
	bufferlist * search_start;
	int search_start_offset;
	int *search_offsets;
	bufferlist ** search_starts;
	int *search_start_offsets;
	int read_bytes;
	
	list_data * list;
	file_data * file;
	
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = (file_data *)inputlist[0]->c.generic.data;
	buffers.next = NULL;
	DEBUGPUTS("Entering critical section.\n");
	VIS_EnterCriticalSection(file->shared->lock);
		if(file->offset >= file->shared->size)
		{
	VIS_LeaveCriticalSection(file->shared->lock);
			release_ref(inputlist[0]);
			release_ref(inputlist[1]);
			inputlist[0] = inputlist[1] = inputlist[2] = NULL;
			inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
			datum_set_yesno(inputlist[3], 1);
			return 0;
		}
		if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
		{
			
			list = ((list_data *)inputlist[1]->c.generic.data);
			DEBUGPRINTF("Delimeter input is a list with %d entries.\n", list->num_entries);
			search_offsets = malloc(sizeof(int) * (list->num_entries));
			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
			search_starts = malloc(sizeof(bufferlist *) * (list->num_entries));
			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(bufferlist *) * (list->num_entries));
			search_start_offsets = malloc(sizeof(int) * (list->num_entries));
			DEBUGPRINTF("Allocated %d bytes.\n", sizeof(int) * (list->num_entries));
			for(i = 0; i < list->num_entries; ++i)
			{
				DEBUGPRINTF("Setting search_offsets[%d] = 0.\n", i);
				search_offsets[i] = 0;
			}
		}
		search_offset = 0;
		current = &buffers;
		current->index = 0;
	
		DEBUGPUTS("In critical section.\n");
		vis_file_read_open_check(file);
		DEBUGPUTS("File open.");
		while(!found && !feof(file->shared->file))
		{
			DEBUGPRINTF("Reading %d bytes from file\n", FILE_SEARCH_BUFFER_SIZE);
			read_bytes = fread(current->buffer, 1, FILE_SEARCH_BUFFER_SIZE, file->shared->file);
			DEBUGPRINTF("fread read %d bytes\n", read_bytes);
			for(i = 0; i < read_bytes && !found; ++i)
			{
				DEBUGPRINTF("Checking character #%d (%c)\n", i, current->buffer[i]);
				switch(inputlist[1]->company->type_id)
				{
				case BUILTIN_TYPE_WHOLE:
					if((int)current->buffer[i] == inputlist[1]->c.integers.num_a)
					{
						found = TRUE;
						search_offset = 1;
						search_start = current;
						search_start_offset = i;
					}
					break;
				case BUILTIN_TYPE_STRING:
					if(current->buffer[i] == ((char *)inputlist[1]->c.generic.data)[search_offset])
					{
						if(search_offset == 0)
						{
							search_start = current;
							search_start_offset = i;
						}
						++search_offset;
						if(search_offset == (inputlist[1]->c.generic.len-1))
							found = TRUE;
					}
					else
					{
						if(search_offset > 0)
						{
							current = search_start;
							i = search_start_offset;
						}
						search_offset = 0;
					}
					break;
				case BUILTIN_TYPE_LIST:
					for(j = 0; j < list->num_entries; ++j)
					{
						DEBUGPRINTF("Testing list entry %d against character %d in buffer %d\n", j, i, current->index);
						if(list->entries[j]->company->type_id == BUILTIN_TYPE_WHOLE && (int)current->buffer[i] == list->entries[j]->c.integers.num_a)
						{
							DEBUGPUTS("Matched whole number entry.\n");
							found = TRUE;
							found_entry = j;
							search_offset = 1;
							search_start = current;
							search_start_offset = i;
							break;
						}
						else if(list->entries[j]->company->type_id == BUILTIN_TYPE_STRING)
						{
							DEBUGPUTS("String entry.\n");
							if(current->buffer[i] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
							{
								DEBUGPRINTF("%c in buffer matches character #%d in entry.\n", current->buffer[i], search_offsets[j]);
								if(search_offsets[j] == 0)
								{
									search_starts[j] = current;
									search_start_offsets[j] = i;
								}
								++search_offsets[j];
								if(search_offsets[j] == (list->entries[j]->c.generic.len-1))
								{
									DEBUGPUTS("Entire string matched.\n");
									found = TRUE;
									found_entry = j;
									search_offset = search_offsets[j];
									search_start = search_starts[j];
									search_start_offset = search_start_offsets[j];
									break;
								}
							}
							else if(search_offsets[j] > 0)
							{
								DEBUGPRINTF("%c in bufer does not match character #%d in entry.\n", current->buffer[i], search_offsets[j]);
								temp = search_starts[j];
								search_offsets[j] = 0;
								startk = search_start_offsets[j];
								while(temp && !found)
								{
									DEBUGPRINTF("Scanning block %d for possible missed match from %d to %d.\n", temp->index, startk, (temp == current ? i : FILE_SEARCH_BUFFER_SIZE)-1);
									for(k = startk; k < (temp == current ? i : FILE_SEARCH_BUFFER_SIZE); ++k)
									{
										if(temp->buffer[k] == ((char *)list->entries[j]->c.generic.data)[search_offsets[j]])
										{
											if(!search_offsets[j])
											{
												search_starts[j] = temp;
												search_start_offsets[j] = k;
											}
											++search_offsets[j];
											if(search_offset == (list->entries[j]->c.generic.len-1))
											{
												found = TRUE;
												found_entry = j;
												search_start = search_starts[j];
												search_start_offset = search_start_offsets[j];
											}
										}
										else
										{
											if(search_offsets[j] > 0)
											{
												temp = search_starts[j];
												k = search_start_offsets[j];
											}
											search_offsets[j] = 0;
										}
									}
									startk = 0;
									temp = temp->next;
								}
								
							}
							else
								search_offsets[j] = 0;
							
						}
					}
					break;
				}
			}
			if(!found && !feof(file->shared->file))
			{
				current->next = malloc(sizeof(bufferlist));
				DEBUGPRINTF("Allocated next buffer at %X (%d bytes)\n", current->next, sizeof(bufferlist));
				current->next->index = current->index+1;
				current->next->next = NULL;
				current = current->next;
			}
		}
	VIS_LeaveCriticalSection(file->shared->lock);
	if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
	{
		VIS_FREE(search_offsets, "Get DString@File, search offsets");
		VIS_FREE(search_starts, "Get DString@File, search starts");
		VIS_FREE(search_start_offsets, "Get DString@File, search start offsets");
	}
	if(found)
	{
		DEBUGPUTS("Found a delimeter");
		if(inputlist[1]->company->type_id == BUILTIN_TYPE_LIST)
		{
			inputlist[2] = add_ref(list->entries[found_entry]);
			release_ref(inputlist[1]);
		}
		else
			inputlist[2] = inputlist[1];
		inputlist[3] = NULL;
	}
	else
	{
		DEBUGPUTS("Didn't find a delimeter");
		release_ref(inputlist[1]);
		inputlist[2] = NULL;
		inputlist[3] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
		datum_set_yesno(inputlist[3], 0);
	}
	//Does this need to be here still or was it just working around another bug?
	if(search_start_offset < 0)
		search_start_offset = 0;
	if(!found) {
		search_start = current;
		search_start_offset = i;
	}
	if(found)
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_STRING, 1, FILE_SEARCH_BUFFER_SIZE * current->index + search_start_offset+1, worker_entry->instance->def->program);
		//file->offset += FILE_SEARCH_BUFFER_SIZE * current->index + search_start_offset + search_offset;
		file->offset += FILE_SEARCH_BUFFER_SIZE * search_start->index + search_start_offset + search_offset;
	}
	else
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_STRING, 1, FILE_SEARCH_BUFFER_SIZE * current->index + read_bytes+1, worker_entry->instance->def->program);
		file->offset += FILE_SEARCH_BUFFER_SIZE * current->index + read_bytes;
	}
	temp = &buffers;
	string_offset = 0;
	while(temp)
	{
		DEBUGPRINTF("Copying from index %d to offset %X\n", temp->index, string_offset);
		if(temp == search_start)
		{
			//if(found)
			//{
				temp->buffer[search_start_offset] = '\0';
				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, search_start_offset);
				string_offset += search_start_offset;
			/*}
			else
			{
				memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, i);
				string_offset += i;
			}*/
			break;
		}
		else
		{
			memcpy(((char *)inputlist[1]->c.generic.data)+string_offset, temp->buffer, FILE_SEARCH_BUFFER_SIZE);
			string_offset += FILE_SEARCH_BUFFER_SIZE;
		}
		if(temp != &buffers)
		{
			temp2 = temp->next;
			VIS_FREE(temp, "Get DString@File, buffer node");
			temp = temp2;
		}
		else
			temp = temp->next;
	}
	while(temp)
	{
		if(temp != &buffers)
		{
			temp2 = temp->next;
			DEBUGPRINTF("Freeing %X\n", temp);
			VIS_FREE(temp, "Get DString@File, buffer node");
			temp = temp2;
		}
		else
			temp = temp->next;
	}
	((char *)inputlist[1]->c.generic.data)[string_offset] = '\0';
	DEBUGPRINTF("Output string: %s\n", inputlist[1]->c.generic.data);
	return 0;
}

int vis_file_get_byte(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	BOOL eof;
	char num;
	
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = (file_data *)inputlist[0]->c.generic.data;
	VIS_EnterCriticalSection(file->shared->lock);
		if(!(eof = (file->offset >= file->shared->size)))
		{
			vis_file_read_open_check(file);
			fread(&num,sizeof(char),1, file->shared->file);
		}
	VIS_LeaveCriticalSection(file->shared->lock);
	if(eof)
	{
		release_ref(inputlist[0]);
		inputlist[0] = inputlist[1] = NULL;
		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
		datum_set_yesno(inputlist[2], 1);
	}
	else
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
		inputlist[1]->c.integers.num_a = num;
		inputlist[2] = NULL;
		file->offset += sizeof(char);
	}
	return 0;
}

int vis_file_get_word(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	BOOL eof;
	short num;

	inputlist[0] = copy_datum(inputlist[0], 0);
	file = (file_data *)inputlist[0]->c.generic.data;
	VIS_EnterCriticalSection(file->shared->lock);
		if(!(eof = (file->offset >= file->shared->size)))
		{
			vis_file_read_open_check(file);
			fread(&num,sizeof(short),1, file->shared->file);
		}
	VIS_LeaveCriticalSection(file->shared->lock);
	if(eof)
	{
		release_ref(inputlist[0]);
		inputlist[0] = inputlist[1] = NULL;
		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
		datum_set_yesno(inputlist[2], 1);
	}
	else
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
		inputlist[1]->c.integers.num_a = num;
		inputlist[2] = NULL;
		file->offset += sizeof(short);
	}
	return 0;
}

int vis_file_get_long(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	BOOL eof;
	long num;
	
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = (file_data *)inputlist[0]->c.generic.data;
	VIS_EnterCriticalSection(file->shared->lock);
		if(!(eof = (file->offset >= file->shared->size)))
		{
			vis_file_read_open_check(file);
			fread(&num,sizeof(long),1, file->shared->file);
		}
	VIS_LeaveCriticalSection(file->shared->lock);
	if(eof)
	{
		release_ref(inputlist[0]);
		inputlist[0] = inputlist[1] = NULL;
		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
		datum_set_yesno(inputlist[2], 1);
	}
	else
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
		inputlist[1]->c.integers.num_a = num;
		inputlist[2] = NULL;
		file->offset += sizeof(long);
	}
	return 0;
}

int vis_file_get_double(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	BOOL eof;
	double num;
	
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = (file_data *)inputlist[0]->c.generic.data;
	VIS_EnterCriticalSection(file->shared->lock);
		if(!(eof = (file->offset >= file->shared->size)))
		{
			vis_file_read_open_check(file);
			fread(&num,sizeof(num),1, file->shared->file);
		}
	VIS_LeaveCriticalSection(file->shared->lock);
	if(eof)
	{
		release_ref(inputlist[0]);
		inputlist[0] = inputlist[1] = NULL;
		inputlist[2] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
		datum_set_yesno(inputlist[2], 1);
	}
	else
	{
		inputlist[1] = new_datum(BUILTIN_TYPE_REAL, 3, 0, worker_entry->instance->def->program);
		inputlist[1]->c.real = num;
		inputlist[2] = NULL;
		file->offset += sizeof(num);
	}
	return 0;
}

void vis_file_write_open_check(file_data * file)
{
	switch(file->shared->status)
	{
		case FILE_READ:
			fclose(file->shared->file);
		case FILE_NOSIZE:
		case FILE_CLOSED:
			DEBUGPUTS("File is closed, opening...\n");
			DEBUGPRINTF("File name: %s\n", file->shared->name);
			file->shared->file = fopen(file->shared->name, "r+b");
			if(!file->shared->file)
				file->shared->file = fopen(file->shared->name,"w+b");
			if(!file->shared->file)
			{
				file->shared->status = FILE_CANT_OPEN;
				file->shared->size = 0;
				break;
			}
			if(file->shared->status == FILE_NOSIZE)
			{
				DEBUGPUTS("Getting file size.\n");
				fseek(file->shared->file, 0, SEEK_END);
				file->shared->size = ftell(file->shared->file);
				DEBUGPRINTF("File size: %d.\n", file->shared->size);
			}
				
			file->shared->status = FILE_WRITE;
			break;
		default://file is already open
			break;
	}
	DEBUGPRINTF("Seeking to %d\n", file->offset);
	if(file->shared->file)
		fseek(file->shared->file, file->offset, SEEK_SET);
	DEBUGPUTS("Done.\n");
}

int vis_file_put_string(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	int written;
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = ((file_data *)inputlist[0]->c.generic.data);
	VIS_EnterCriticalSection(file->shared->lock);
		vis_file_write_open_check(file);
		written = fwrite(inputlist[1]->c.generic.data,1,inputlist[1]->c.generic.len-1,file->shared->file);
		file->offset += written;
		if(file->offset > file->shared->size)
			file->shared->size = file->offset;
	VIS_LeaveCriticalSection(file->shared->lock);
	release_ref(inputlist[1]);
	return 0;
}

int vis_file_length(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	int written;
	int size;
	file = ((file_data *)inputlist[0]->c.generic.data);
	VIS_EnterCriticalSection(file->shared->lock);
		vis_file_read_open_check(file);
		size = file->shared->size;
	VIS_LeaveCriticalSection(file->shared->lock);
	release_ref(inputlist[0]);
	inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
	inputlist[0]->c.integers.num_a = size;
	return 0;
}

int vis_file_truncate(datum ** inputlist, queue_entry * worker_entry)
{
	file_data * file;
	inputlist[0] = copy_datum(inputlist[0], 0);
	file = inputlist[0]->c.generic.data;
	VIS_EnterCriticalSection(file->shared->lock);
		switch(file->shared->status)
		{
			case FILE_READ:
			case FILE_WRITE:
				fclose(file->shared->file);
			default:
				break;
		}
		file->shared->file = fopen(file->shared->name,"wb");
		file->shared->size = 0;
		file->shared->status = FILE_WRITE;
	VIS_LeaveCriticalSection(file->shared->lock);
	file->offset = 0;
	return 0;
}