/*	-*- mode: c; mode: fold -*-	*/
# include	"config.h"
# include	<stdio.h>
# include	<stdlib.h>
# include	<stdarg.h>
# include	<ctype.h>
# include	<string.h>
# include	<time.h>
# include	"pager.h"

/*{{{	utility functions */
char *
skip (char *str)
{
	while (*str && (! isspace (*str)))
		++str;
	if (*str) {
		*str++ = '\0';
		while (isspace (*str))
			++str;
	}
	return str;
}

char *
skipch (char *str, char ch)
{
	while (*str && (*str != ch))
		++str;
	if (*str) {
		*str++ = '\0';
		while (isspace (*str))
			++str;
	}
	return str;
}

char *
getline (FILE *fp, Bool cont)
{
	char	*buf;
	int	size;
	char	*ret;
	int	len;
	char	*ptr;

	size = 256;
	if (! (buf = malloc (size + 2)))
		return NULL;
	len = 0;
	while (ret = fgets (buf + len, size - len - 2, fp)) {
		if (ptr = strchr (buf + len, '\n')) {
			*ptr = '\0';
			len += strlen (buf + len);
			if (! cont)
				break;
			if (len && (buf[len - 1] == '\\')) {
				--len;
				buf[len] = '\0';
			} else
				break;
		} else
			len += strlen (buf + len);
		if (len + 64 >= size) {
			size += size;
			if (! (buf = Realloc (buf, size + 2)))
				break;
		}
	}
	if ((! ret) && buf) {
		free (buf);
		buf = NULL;
	}
	return len || ret ? buf : NULL;
}

int
verbose_out (char *fmt, ...)
{
	va_list	par;
	
	va_start (par, fmt);
	vfprintf (stdout, fmt, par);
	va_end (par);
	return 0;
}
/*}}}*/
/*{{{	string_t handling */
string_t *
snewc (char *str)
{
	string_t	*s;
	
	if (s = (string_t *) malloc (sizeof (string_t))) {
		s -> str = NULL;
		if (str) {
			s -> len = strlen (str);
			s -> size = s -> len + 1;
			if (s -> str = (char_t *) malloc (sizeof (char_t) * s -> size))
				memcpy (s -> str, str, s -> len);
			else {
				free (s);
				s = NULL;
			}
		} else {
			s -> len = 0;
			s -> size = 0;
		}
	}
	return s;
}

string_t *
snew (char_t *str, int len)
{
	string_t	*s;
	
	if (s = (string_t *) malloc (sizeof (string_t))) {
		s -> str = NULL;
		s -> len = 0;
		s -> size = 0;
		if (len > 0)
			if (s -> str = (char_t *) malloc (sizeof (char_t) * (len + 1))) {
				s -> size = len + 1;
				if (str) {
					s -> len = len;
					memcpy (s -> str, str, len);
				} else
					s -> len = 0;
			} else {
				free (s);
				s = NULL;
			}
	}
	return s;
}

Bool
sexpand (string_t *s, int nsize)
{
	if (s && (nsize + 2 > s -> size)) {
		s -> size = nsize + 2;
		if (! (s -> str = (char_t *) Realloc (s -> str, sizeof (char_t) * s -> size))) {
			s -> size = 0;
			s -> len = 0;
			return False;
		}
	}
	return True;
}

Bool
scopy (string_t *dst, string_t *src)
{
	if (dst && src && sexpand (dst, src -> len + 1)) {
		if (src -> str) {
			memcpy (dst -> str, src -> str, src -> len);
			dst -> len = src -> len;
		} else
			dst -> len = 0;
		return True;
	}
	return False;
}

Bool
scat (string_t *dst, string_t *src)
{
	if (dst && src && sexpand (dst, dst -> len + src -> len + 1)) {
		if (src -> str) {
			memcpy (dst -> str + dst -> len, src -> str, src -> len);
			dst -> len += src -> len;
		}
		return True;
	}
	return False;
}

static Bool
dostr (string_t *dst, char *src, Bool (*func) (string_t *, string_t *))
{
	Bool		ret;
	string_t	*rsrc;
			
	ret = False;
	if (dst)
		if (src) {
			if (rsrc = snewc (src)) {
				ret = (*func) (dst, rsrc);
				sfree (rsrc);
			}
		} else
			ret = True;
	return ret;
}

Bool
scopyc (string_t *dst, char *src)
{
	return dostr (dst, src, scopy);
}

Bool
scatc (string_t *dst, char *src)
{
	return dostr (dst, src, scat);
}

string_t *
scut (string_t *str, int start, int len)
{
	string_t	*res;

	if (len < 0)
		len = str ? str -> len - start : 0;
	if (res = snew (NULL, len + 1)) {
		if (str -> len > start) {
			if (str -> len - start < len)
				len = str -> len - start;
		} else
			len = 0;
		if (len > 0)
			memcpy (res -> str, str -> str + start, len);
		res -> len = len;
	}
	return res;
}

void
sdel (string_t *str, int start, int len)
{
	int	size;
	
	if (str -> len > start) {
		if (str -> len - start < len)
			len = str -> len - start;
	} else
		len = 0;
	if (len > 0) {
		size = str -> len - (start + len);
		if (size > 0)
			memcpy (str -> str + start, str -> str + start + len, str -> len - (start + len));
		str -> len -= len;
	}
}

Bool
sput (string_t *str, string_t *ins, int pos, int len)
{
	if ((len < 0) || (len > ins -> len))
		len = ins -> len;
	if (len + pos >= str -> size)
		if (! sexpand (str, len + pos + 1))
			return False;
	memcpy (str -> str + pos, ins -> str, len);
	if (str -> len < len + pos)
		str -> len = len + pos;
	return True;
}
	
Bool
sputc (string_t *str, char *ins, int pos, int len)
{
	Bool		ret;
	string_t	*rins;
			
	ret = False;
	if (str && ins && (rins = snewc (ins))) {
		ret = sput (str, rins, pos, len);
		sfree (rins);
	}
	return ret;
}

char *
sextract (string_t *s)
{
	char	*ret;
	
	ret = NULL;
	if (s)
		if (ret = malloc (s -> len + 1))
			if (s -> str) {
				memcpy (ret, s -> str, s -> len);
				ret[s -> len] = '\0';
			} else
				ret[0] = '\0';
	return ret;
}

char *
schar (string_t *s)
{
	if (s) {
		if (s -> len + 1>= s -> size)
			sexpand (s, s -> len + 2);
		if (s -> len + 1 < s -> size) {
			s -> str[s -> len] = '\0';
			return (char *) s -> str;
		}
	}
	return NULL;
}

void *
sfree (string_t *s)
{
	if (s) {
		if (s -> str)
			free (s -> str);
		free (s);
	}
	return NULL;
}

void
srelease (string_t *s)
{
	if (s -> size + 1 > s -> len) {
		s -> size = s -> len + 1;
		if (! (s -> str = (char_t *) Realloc (s -> str, sizeof (char_t) * (s -> size + 2)))) {
			s -> size = 0;
			s -> len = 0;
		}
	}
}

Bool
siscntrl (string_t *s, int pos)
{
	return (s && (pos >= 0) && (pos < s -> len) && iscntrl (s -> str[pos])) ? True : False;
}

Bool
sisspace (string_t *s, int pos)
{
	return (s && (pos >= 0) && (pos < s -> len) && isspace (s -> str[pos])) ? True : False;
}

Bool
sisdigit (string_t *s, int pos)
{
	return (s && (pos >= 0) && (pos < s -> len) && isdigit (s -> str[pos])) ? True : False;
}

int
stoi (string_t *s)
{
	int	ret;
	
	ret = 0;
	if (s && s -> str) {
		s -> str[s -> len] = '\0';
		ret = atoi ((char *) s -> str);
	}
	return ret;
}
/*}}}*/
/*{{{	date_t handling */
# if		! HAVE_MEMSET && ! HAVE_BZERO
static void
dozero (void *p, int len)
{
	unsigned char	*ptr = (char *) p;
	
	while (len-- > 0)
		*ptr++ = 0;
}
# endif		/* ! HAVE_MEMSET && ! HAVE_BZERO */

date_t *
dat_free (date_t *d)
{
	if (d)
		free (d);
	return NULL;
}

date_t *
dat_parse (char *str)
{
	date_t		*d;
	time_t		tim;
	struct tm	*tt;
	struct tm	tm;
	Bool		add;
	char		*ptr, *sav;
	char		*p1, *p2;
	int		mode;
	int		n, val;
	char		sep;
	date_t		tmp;

	d = NULL;
	if ((! str) || (str = strdup (str))) {
		if (d = (date_t *) malloc (sizeof (date_t))) {
			time (& tim);
			if (tt = localtime (& tim)) {
				d -> day = tt -> tm_mday;
				d -> mon = tt -> tm_mon + 1;
				d -> year = tt -> tm_year + 1900;
				d -> hour = tt -> tm_hour;
				d -> min = tt -> tm_min;
				d -> sec = tt -> tm_sec;
			} else {
				d -> day = 1;
				d -> mon = 1;
				d -> year = 1970;
				d -> hour = 0;
				d -> min = 0;
				d -> sec = 0;
			}
			if (str && strcmp (str, "now")) {
				if (*str == '+') {
					add = True;
					ptr = str + 1;
				} else {
					add = False;
					ptr = str;
				}
				tmp.day = -1;
				tmp.mon = -1;
				tmp.year = -1;
				tmp.hour = -1;
				tmp.min = -1;
				tmp.sec = -1;
				while (*ptr) {
					sav = ptr;
					ptr = skip (ptr);
					if (strchr (sav, '.')) {
						sep = '.';
						mode = 1;
					} else if (strchr (sav, '/')) {
						sep = '/';
						mode = 2;
					} else if (strchr (sav, ':')) {
						sep = ':';
						mode = 3;
					} else {
						sep = '\0';
						mode = 0;
					}
					for (p1 = sav, n = 0; *p1; ++n) {
						p2 = p1;
						p1 = skipch (p1, sep);
						val = atoi (p2);
						switch (mode) {
						case 0:
							tmp.sec = 0;
							if (val < 30) {
								tmp.hour = val;
								tmp.min = 0;
							} else {
								tmp.hour = val / 60;
								tmp.min = val % 60;
							}
							break;
						case 1:
							if (n == 0)
								tmp.day = val;
							else if (n == 1)
								tmp.mon = val;
							else if (n == 2) {
								if ((! add) && (val < 1900))
									val += 1900;
								tmp.year = val;
							}
							break;
						case 2:
							if (n == 0)
								tmp.mon = val;
							else if (n == 1)
								tmp.day = val;
							else if (n == 2) {
								if ((! add) && (val < 1900))
									val += 1900;
								tmp.year = val;
							}
							break;
						case 3:
							if (n == 0) {
								tmp.hour = val;
								tmp.min = 0;
								tmp.sec = 0;
							} else if (n == 1)
								tmp.min = val;
							else if (n == 2)
								tmp.sec = val;
							break;
						}
					}
				}
				if (add) {
					if (tmp.day != -1)
						d -> day += tmp.day;
					if (tmp.mon != -1)
						d -> mon += tmp.mon;
					if (tmp.year != -1)
						d -> year += tmp.year;
					if (tmp.hour != -1)
						d -> hour += tmp.hour;
					if (tmp.min != -1)
						d -> min += tmp.min;
					if (tmp.sec != -1)
						d -> sec += tmp.sec;
				} else {
					if (tmp.day != -1)
						d -> day = tmp.day;
					if (tmp.mon != -1)
						d -> mon = tmp.mon;
					if (tmp.year != -1)
						d -> year = tmp.year;
					if (tmp.hour != -1)
						d -> hour = tmp.hour;
					if (tmp.min != -1)
						d -> min = tmp.min;
					if (tmp.sec != -1)
						d -> sec = tmp.sec;
				}
# if		HAVE_MEMSET
				memset (& tm, 0, sizeof (tm));
# elif		HAVE_BZERO				
				bzero (& tm, sizeof (tm));
# else
				dozero (& tm, sizeof (tm));
# endif		/* ! HAVE_MEMSET && ! HAVE_BZERO */
				tm.tm_mday = d -> day;
				tm.tm_mon = d -> mon - 1;
				tm.tm_year = d -> year - 1900;
				tm.tm_hour = d -> hour;
				tm.tm_min = d -> min;
				tm.tm_sec = d -> sec;
				tm.tm_isdst = tt -> tm_isdst;
				if (mktime (& tm) == (time_t) -1) 
					d = dat_free (d);
				else {
					d -> day = tm.tm_mday;
					d -> mon = tm.tm_mon + 1;
					d -> year = tm.tm_year + 1900;
					d -> hour = tm.tm_hour;
					d -> min = tm.tm_min;
					d -> sec = tm.tm_sec;
				}
			}
		}
		if (str)
			free (str);
	}
	return d;
}

int
dat_diff (date_t *d1, date_t *d2)
{
	int	v1, v2;
	
	if (d1)
		v1 = (((((d1 -> year * 12 + d1 -> mon) * 31 + d1 -> day) * 24 + d1 -> hour) * 60 + d1 -> min) * 60 + d1 -> sec);
	else
		v1 = 0;
	if (d2)
		v2 = (((((d2 -> year * 12 + d2 -> mon) * 31 + d2 -> day) * 24 + d2 -> hour) * 60 + d2 -> min) * 60 + d2 -> sec);
	else
		v2 = 0;
	return v2 - v1;
}

void
dat_clear (date_t *d)
{
	d -> day = 0;
	d -> mon = 0;
	d -> year = 0;
	d -> hour = 0;
	d -> min = 0;
	d -> sec = 0;
}

void
dat_localtime (date_t *d)
{
	time_t		tim;
	struct tm	*tt;
	
	time (& tim);
	if (tt = localtime (& tim)) {
		d -> day = tt -> tm_mday;
		d -> mon = tt -> tm_mon + 1;
		d -> year = tt -> tm_year + 1900;
		d -> hour = tt -> tm_hour;
		d -> min = tt -> tm_min;
		d -> sec = tt -> tm_sec;
	} else
		dat_clear (d);
}
/*}}}*/

