view file.c @ 168:d2b941f82d74

Fix type of list constants in inference pass and return type of some Array related workers
author Mike Pavone <pavone@retrodev.com>
date Sun, 01 May 2011 18:41:17 -0700
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;
}