/***   [bufmgr.c]
*
*	テキストデータ構造 関連		(C)ささがわ
*
*	For GNU C Compiler (GCC)   Version 1.39
*
***/

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jctype.h>
#include "bufmgr.h"

static unsigned char	*Buf_head;
static size_t	Buf_size;
static int		Buf_ptr;

static unsigned short	mgetc(void);
static void	ctype_sub(int, int, int, int, unsigned char *, int *, int *, int, int *, unsigned short *);
static int	BMGR_change_sub(int, int, struct filestore_t *, int *, int);

int BMGR_set(const char *file, int keta, int tab, register struct filestore_t *fl) {
	FILE    *fp;
	int     i, dum = -1;
	
	if ((fp = fopen(file, "rt")) == NULL) {
		return -2;
	} else if ((fl->size = (size_t)filelength(fileno(fp))) < 0) {
		fclose(fp);
		return -2;
	} else if ((fl->buf1 = malloc(fl->size)) == NULL) {
		fclose(fp);
		return -1;
	}
	
	fl->size = fread(fl->buf1, 1, fl->size, fp);
	if (ferror(fp)) {
		fclose(fp);
		free(fl->buf1);
		return -2;
	}
	fclose(fp);
	if ((fl->buf1 = realloc(fl->buf1, fl->size)) == NULL)
		return -1;
	
	for (i = 0; i < fl->size; i++) {	/* Clean Up */
		if (iskanji(fl->buf1[i])) {
			i++;
			if (i < fl->size) {
				if (!iskanji2(fl->buf1[i])) {
					fl->buf1[i - 1] = 0x81;
					fl->buf1[i] = 0x40;
				}
			} else {
				fl->buf1[i - 1] = ' ';
			}
		} else if (fl->buf1[i] == '\0') {
			fl->buf1[i] = ' ';
		}
	}
	fl->buf2 = NULL;
	if (BMGR_change(keta, tab, fl, &dum)) {
		free(fl->buf1);
		return -1;
	}
	
	return 0;
}

int BMGR_change(int keta, int tab, struct filestore_t *fl, int *line) {
	int		a = 0, r, bsz, adb;
	
	if (*line >= 0)
		a = fl->buf2[*line];
	
	adb = fl->size / 20;
	if (adb < 10)	adb = 10;
	bsz = adb;
	while ((r = BMGR_change_sub(keta, tab, fl, &bsz, adb)) == -2);
	
	if (*line >= 0)
		for (*line = 0; a >= fl->buf2[*line + 1]; (*line)++);
	
	return r;
}

static int BMGR_change_sub(int keta, int tab, struct filestore_t *fl, int *bsz, int adb) {
	if (free(fl->buf2), (fl->buf2 = malloc(*bsz * sizeof(size_t))) == NULL)
		return -1;
	
	Buf_head = fl->buf1;
	Buf_size = fl->size;
	Buf_ptr = 0;
	fl->buf2[fl->line = 0] = 0;
	while (fl->buf2[fl->line] < fl->size) {
		register int	k = 0, n = 0;
		
		Buf_ptr = fl->buf2[fl->line];
		while (n < keta) {
			register unsigned short	c;
			
			k++;
			if ((c = mgetc()) == 0xffff) {
				k--;
				break;
			} else if (c == '\t') {
				n = ((n / tab) + 1) * tab;
			} else if (c == '\n') {
				break;
			} else if (c > 0xff) {
				if (n + 1 >= keta) {
					k--;
					break;
				}
				k++;
				n += 2;
			} else {
				n++;
			}
		}
		if (fl->line + 1 >= *bsz) {
			size_t	*p;
			
			p = fl->buf2;
			if ((fl->buf2 = malloc((*bsz + adb) * sizeof(size_t))) == NULL) {
				fl->buf2 = p;
				*bsz += adb;
				
				return -2;
			} else {
				memcpy(fl->buf2, p, *bsz * sizeof(size_t));
				free(p);
				*bsz += adb;
			}
		}
		fl->buf2[fl->line + 1] = fl->buf2[fl->line] + k;
		fl->line++;
	}
	if (fl->line + 1 < *bsz && (fl->buf2 = realloc(fl->buf2, (fl->line + 1) * sizeof(size_t))) == NULL)
		return -1;
	
	return 0;
}

static unsigned short mgetc(void) {
	unsigned short  ret;
	
	if (Buf_ptr >= Buf_size) {
		ret = 0xffff;
	} else {
		if (iskanji(Buf_head[Buf_ptr]))
			ret = (Buf_head[Buf_ptr++] << 8) + Buf_head[Buf_ptr++];
		else
			ret = Buf_head[Buf_ptr++];
	}
	
	return ret;
}

#define TAB	(par->tab)
#define L	(par->l)
#define R	(par->r)
void BMGR_String(struct bmgr_t *par, unsigned char *buf) {
	register int	n, k = 0, ack = 0;
	unsigned char	*str, *p;
	
	n = par->fs->buf2[par->line + 1] - par->fs->buf2[par->line];
	str = par->fs->buf1 + par->fs->buf2[par->line];
	
	for (; k < n && ack < L; k++) {
		if (str[k] == '\t') {
			if ((ack += TAB - ack % TAB) >= L)
				strncpy((char *)buf, "          ", ack - L);
		} else if (iskanji(str[k])) {
			if ((ack += 2) > L)
				*buf = ' ';
			k++;
		} else {
			ack++;
		}
	}
	
	p = buf - L;
	for (; k < n && ack <= R; k++) {
		if (str[k] == '\n') {
			p[ack++] = par->crm ? 0x1f : ' ';
		} else if (str[k] == '\t') {
			int		c;
			
			c = TAB - ack % TAB;
			strncpy((char *)(&p[ack]), "          ", c);
			p[ack] = par->tabm ? 0x1c : ' ';
			ack += c;
			if (ack > R + 1)
				ack = R + 1;
		} else if (iskanji(str[k])) {
			p[ack++] = str[k++];
			p[ack++] = str[k];
			if (ack > R + 1) {
				ack = R + 1;
				p[ack - 1] = ' ';
			}
		} else {
			p[ack++] = str[k];
		}
	}
	
	buf[ack - L < 0 ? 0 : ack - L] = '\0';
}
#undef TAB
#undef L
#undef R

void BMGR_ctype(struct bmgr_t *par, struct bmgrctype_t *ct) {
	int		n, k = 0, ack = 0;
	unsigned char	*str;
	
	n = par->fs->buf2[par->line + 1] - par->fs->buf2[par->line];
	str = par->fs->buf1 + par->fs->buf2[par->line];
	
	ctype_sub(par->tabm, par->crm, par->tab, n, str, &k, &ack, par->l, &ct->l, &ct->lcode);
	ctype_sub(par->tabm, par->crm, par->tab, n, str, &k, &ack, par->r, &ct->r, &ct->rcode);
}

static void ctype_sub(int tabm, int crm, int tab, int n, register unsigned char *str, int *k, int *ack, int target, int *type, unsigned short *code) {
	*type = 0;
	for (; *k < n && *ack <= target; (*k)++) {
		if (str[*k] == '\n') {
			if (*ack == target) {
				*type = 1;
				*code = crm ? 0x1f : ' ';
			}
			(*ack)++;
		} else if (str[*k] == '\t') {
			if (*ack == target) {
				*type = 1;
				*code = tabm ? 0x1c : ' ';
			} else if (*ack < target && target <= *ack + tab - *ack % tab) {
				*type = 1;
				*code = ' ';
			}
			*ack += tab - *ack % tab;
		} else if (iskanji(str[*k])) {
			if (*ack + 1 == target) {
				*type = 3;
				*code = (str[*k] << 8) + str[*k + 1];
			} else if (*ack == target) {
				*type = 2;
				*code = (str[*k] << 8) + str[*k + 1];
			}
			*ack += 2;
			(*k)++;
		} else {
			if (*ack == target) {
				*type = 1;
				*code = str[*k];
			}
			(*ack)++;
		}
	}
}
