/*
 * Copyright (C) 1999-2000 Wojciech Purczynski <wp@elzabsoft.pl>
 *
 * THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
 * IT UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY
 * THE FREE SOFTWARE  FOUNDATION;  EITHER  VERSION 2 OF THE LICENSE, OR
 * (AT YOUR OPTION) ANY LATER VERSION.
 *
 * THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED  WARRANTY OF
 * MERCHANTABILITY OR FITNESS  FOR A PARTICULAR  PURPOSE.  SEE THE
 * GNU GENERAL PUBLIC LICENSE FOR MORE DETAILS.
 */

#define MAXLINE 1024

#ifndef __KERNEL__

#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>

#else /* __KERNEL__ */

#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>

#if CONFIG_MODVERSIONS
#include <linux/modversions.h>
#endif


#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <sys/syscall.h>
#include <linux/stddef.h>
#include <linux/ctype.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#define start_kernel_access() set_fs(get_ds())
#define end_kernel_access() set_fs(KERNEL_DS)
#define open(a,b,c) ((int (*)(const char*, int, int))sys_call_table[__NR_open])((a),(b),(c))
#define close(a) ((int (*)(unsigned int))sys_call_table[__NR_close])(a)
#define read(a,b,c) ((int (*)(int, void*, size_t))sys_call_table[__NR_read])((a),(b),(c))
extern void * sys_call_table[];

#endif /* __KERNEL__ */

char char_buf;
int is_char=0;
int fd=-1;
char line_bufor[MAXLINE+1];
int line_no=1;

/* Functions closes file */
int file_close(void)
{
	int error;
	
	if (fd<0) return 0;
	
	error=close(fd);
	if (error) return error;
	
	fd=-1;
	is_char=0;
	
	return 0;
}

/* Function opens file for read */
int file_open(const char * filename)
{
	int error;
	
	error=file_close();
	if (error) return error;

#ifdef __KERNEL__
	start_kernel_access();
#endif	
	fd=open(filename, O_RDONLY, 0);
#ifdef __KERNEL__
	end_kernel_access();
#endif	
	if (fd<0) return fd;
	
	return 0;
}

int file_get_char(void)
{
	unsigned char chr;
	static unsigned char last_chr;
	int error;
	
	if (fd<0) return -EBADF;
	
	if (is_char) {
		is_char=0;
		return char_buf;
	}
	
	error=read(fd, &chr, 1);

	if (error<0) return -error;
	
	if (chr==0xff) chr=0;
	if (error==0) return 0;
	
	if (last_chr==0x0a) line_no++; /* line counting */
	
	last_chr=chr;
	
	return (int)chr;
}

int file_put_char(char chr)
{
	if (is_char) return -EIO;
	
	char_buf=chr;
	is_char=1;
	
	return 0;
}

void file_skip_spaces(void)
{
	int chr;

	do chr=file_get_char();
	while (isspace(chr));

	file_put_char(chr);
}

/* Function reads characters until space */
char *file_read_word(void)
{
	int len=0;
	int chr;
	
	file_skip_spaces();
	
	for (;;) {
		if (len==sizeof(line_bufor)-1) break;
		
		chr=file_get_char();

		if (chr<=0) break;

		if (chr=='\\') { /* escaping */
			chr=file_get_char();
			if (chr<=0) break; 
		} else if ( isspace(chr) )
			break;
		
		line_bufor[len++]=(char)chr;
	}
	
	line_bufor[len]=0;
	
	if (chr<0) return NULL;
	if (len==0) return NULL;

	return line_bufor;
}

char *file_read_line(void)
{
	int len=0;
	int chr;
	
	file_skip_spaces();
	
	for (;;) {
		if (len==sizeof(line_bufor)-1) break;
		
		chr=file_get_char();

		if (chr<=0) break;
		if (chr==0xa) break;
		
		line_bufor[len++]=(char)chr;
	}
	
	if ( len>0 && line_bufor[len-1]=='\x0d' ) len--;
	line_bufor[len]=0;
	
	if (chr<0) return NULL;
	if (len==0) return NULL;
	
	return line_bufor;
}

int file_line_no(void)
{
	return line_no;
}
