
/*
	                      lbio.c -- line buffer I/O

	  This module provides you with the ability to access memory locations
	of character lines in a similar way as you can do with file functions
	of the standard C library.

          ___  _______
          /__)(_  /_       Genesis     : Sat Oct 12 22:48:22 1991
         / \____)(___      Last Change : Mon Jan 27 18:00:58 1992
        /                  Class       : ANSI C

      Copyright (c) Ralf S. Engelschall, All Rights Reserved.
																			*/


#include <stdio.hc>
#include <stdlib.hc>
#include <string.hc>

#include "defines.h"
#include "cus.h"
#include "lbio.h"



/*	Remember that a "line" here means a stream of chars _between_ SOF
    and the first NL char, _between_ two NL chars or _between_ the last
    NL char and the EOF.

	Be sure, that you actually give this functions a area with at least
	ONE line (at least one char)!!!
																			*/


static int linelen(char *cp, char *cpLast)
{
	int cnt;

	for (cnt = 0; (*cp != NL) && (cp <= cpLast); cp++, cnt++)
		; /* void */

	return cnt;
}


struct LineBuffer *lbopen(char *cpFirst, char *cpLast)
{
	LB *lb = NULL;
	char **lpa = NULL;
	char *cp;
	char *cpTmp;
	char **cpp;
	int cnt;
	LB *rc;

	if (cpFirst > cpLast)
		CU(NULL);

	if ((lb = (LB *)malloc(sizeof(LB))) == NULL)
		CU(NULL);

	lb->lb_cpFirst = cpFirst;
	lb->lb_cpLast = cpLast;

	for (cnt = 0, cp = cpFirst; cp <= cpLast; cp++)
		if (*cp == NL)
			cnt++;
	if (*(--cp) != NL)
		cnt++;
	lb->lb_nLnMax = cnt;

	if ((lpa = (char **)malloc(cnt * sizeof(char *))) == NULL) {
		free(lb);
		CU(NULL);
	}

	lb->lb_cppLnFirst = lpa;
	lb->lb_cppLnCur = lpa;
	lb->lb_cppLnLast = lpa + (cnt - 1);

	for (cpp = lpa, cp = cpTmp = cpFirst; cp <= cpLast; cp++)
		if (*cp == NL) {
			*cpp++ = cpTmp;
			cpTmp = cp + 1;
		}
	if (*(--cp) != NL)
		*cpp++ = cpTmp;

	lb->lb_nLnCur = 1;
	lb->lb_cpLnCur = cpFirst;
	lb->lb_wLnCur = linelen(cpFirst, cpLast);

	rc = lb;
	CUS:

	return rc;
}


void lbfree(struct LineBuffer *lb)
{
	free(lb->lb_cppLnFirst);
	free(lb);
}


int lbseek(struct LineBuffer *lb, signed long wOffs, short wMode)
{
	if (wMode == LBSEEK_SET) {
		if ((wOffs < 0) || (abs(wOffs + 1) > lb->lb_nLnMax))
			return FALSE;
		lb->lb_cppLnCur = lb->lb_cppLnFirst + wOffs;
		lb->lb_nLnCur = wOffs + 1;
		lb->lb_cpLnCur = *(lb->lb_cppLnCur);
		lb->lb_wLnCur = linelen(lb->lb_cpLnCur, lb->lb_cpLast);
		return TRUE;
	}

	if (wMode == LBSEEK_CUR) {
		if (   ((lb->lb_nLnCur + wOffs) > lb->lb_nLnMax)
			|| ((lb->lb_nLnCur + wOffs) <= 0)			)
			return FALSE;
		lb->lb_cppLnCur += wOffs;
		lb->lb_nLnCur += wOffs;
		lb->lb_cpLnCur = *(lb->lb_cppLnCur);
		lb->lb_wLnCur = linelen(lb->lb_cpLnCur, lb->lb_cpLast);
		return TRUE;
	}

	if (wMode == LBSEEK_END) {
		if ((wOffs > 0) || (abs(wOffs + 1) > lb->lb_nLnMax))
			return FALSE;
		lb->lb_cppLnCur = lb->lb_cppLnLast + wOffs;
		lb->lb_nLnCur = lb->lb_nLnMax + wOffs;
		lb->lb_cpLnCur = *(lb->lb_cppLnCur);
		lb->lb_wLnCur = linelen(lb->lb_cpLnCur, lb->lb_cpLast);
		return TRUE;
	}

	return FALSE;
}

