[net.sources] PPERT part 2: the d2d routine

jchvr@ihlpg.UUCP (VanRietschote) (04/29/86)

# cut here file=d2d1.c
/*
 *          D2D
 *
 * APT date to date converter
 *
 */
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <string.h>

#undef	NULL;
#define NULL	0
#define EOS	0
#define FALSE	0
#define TRUE	1
#define DECENIUM 1980
#define MONDAY	0
#define TUESDAY	1
#define WEDNESDAY 2
#define THURSDAY 3
#define FRIDAY	4
#define SATURDAY 5
#define SUNDAY 6

int	ERROR ;	/* global error number */
		/* 0=okay	*/
		/* 1=err in inf */
		/* 2=err in in  */
		/* 3=err in outf*/

int day_month[] = {
	0,31,28,31,30,31,30,31,31,30,31,30,31
};

static	char	*monthnames[] = {
	"??",
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec",
	"???",
};

static	char	*daynames[] = {
	"Mon",
	"Tue",
	"Wed",
	"Thu",
	"Fri",
	"Sat",
	"Sun",
	"???",
};

char	*INFORMAT = "-%y%m%d";
char	*OUTFORMAT = "+%a %h %d 19%y%n";

int	year;
int	month;
int	day;
int	week;
int	weekday;

char	line[100];
char	word[10];
char	*valptr;
char	*informat;
char	*outformat;
char	*formptr;
char	*OUT;
char	TEMP[512];

/*
 * dotextline processes the inputstring

 *
 */
dotextline(text)
char	*text;
{
	valptr = text;
	formptr = informat + 1;
	year = month = day = week = weekday = -1;
	while ((*valptr != '\0') && (*formptr != '\0')) {
		while ((*valptr == *formptr) && (*formptr !='%')) {
			valptr++;
			formptr++;
		}
		if (*formptr == '%') {
			if ((do_in_command())) {
				print_inform_error(text);
				return(TRUE);
			}
		}
		else {
			print_inform_error(text);
			return(TRUE);
		}
	}
	if ((*valptr != '\0') || (*formptr != '\0')) {
		print_inform_error(text);
		return(TRUE);
	}
	print_date();
	return(FALSE);
}

/*
 *
 * error during input processing
 *
 */
print_inform_error(text)
char	*text;
{
	ERROR=1; /* bad inf */
	*valptr = '\0';
	return(1);
}

/*
 *
 * do all input % commands
 *
 */
do_in_command()
{
	int	length;
	int	status;

	formptr++;
	length = (is_digit(*formptr)) ? (*formptr++ - '0') : -1;
	switch (*formptr++)  {
	case 'd' :
		status = getval(&day,0,31,rlength(2,length));
		break;
	case 'm' :
		status = getval(&month,1,12,rlength(2,length));
		break;
	case 'h' :
		status = getmonthname(rlength(3,length));
		break;
	case 'y' :
		status = getval(&year,00,99,rlength(2,length));
		year += 1900;
		break;
	case 'j' :
		status = getval(&week,001,953,rlength(3,length));
		break;
	case 'w' :
		status = getval(&weekday,0,6,rlength(1,length));
		break;
	case 'a' :
		status = getweekdayname(rlength(3,length));
		break;
	case '.' : 
		valptr++;
		status = 0;
		break;
	case '*' :
		while (*valptr && (*formptr != *valptr++))
			status = 0;
		formptr++;
		break;
	case '%' : 
		status = (*valptr++ == *formptr++) ? FALSE : TRUE;
		break;
	default  :
		status = TRUE;
	}
	return (status);
}

/*
 * Get current date from UNIX
 *
 */
do_date()
{
	int	tvec[2];
	struct	tm	*localtime();
	struct	tm	*p;

	time(tvec);
	p = localtime(tvec);
	year = p -> tm_year + 1900;
	month = p -> tm_mon + 1;
	day = p -> tm_mday;
}

/*
 * output processing of the date
 *
 */
print_date()
{
	if ((year == -1) && (month == -1) && (day == -1) &&
	    (week != -1) && (weekday != -1)) {
		weekday = (weekday == 0) ? 6 : weekday-1;
		proces_week(week,weekday);
	}
	else {
		if ((year != -1) && (month != -1) && (day != -1)) {
			proces_date(year,month,day);
		}
		else {  ERROR=2; /* bad in */
			return(TRUE);
		}
	}
	formptr = outformat + 1;
	while (*formptr != '\0') {
		if (*formptr == '%') {
			if (do_out_command()) {
				ERROR=3; /* bad outf */
				return(TRUE);
			}
		}
		else {  sprintf(TEMP,"%c",*formptr++);
			strcat(OUT,TEMP);
		}
	}
}

do_out_command()
{
	int	length;
	int	status;

	formptr++;
	status = 0;
	length = (is_digit(*formptr)) ? (*formptr++ -'0') : -1;
	switch(*formptr++) {
	case 'd' :
		status = putval(day,rlength(2,length));
		break;
	case 'm' :
		status = putval(month,rlength(2,length));
		break;
	case 'h' :
		status = putstr(monthnames[month],
		    rlength(3,length));
		break;
	case 'y' :
		year = year - ((year / 100) * 100 );
		status = putval(year,rlength(2,length));
		break;
	case 'j' :
		status = putval(week,rlength(2,length));
		break;
	case 'w' :
		status = putval(weekday,rlength(2,length));
		break;
	case 'a' :
		status = putstr(daynames[weekday],
		    rlength(3,length));
		break;
	case 'n' :
		strcat(OUT,"\n");
		break;
	case 't' :
		strcat(OUT,"\t");
		break;
	case '%' :
		strcat(OUT,"%");
		break;
	default :
		status = TRUE;
	}
	return(status);
}

/*
 * determine the weeknumber and weekday
 * for the given year,month and day
 *
 */
proces_date(year,month,day)
int	year;
int	month;
int	day;
{
	int	temp;
	int	week_no;

	week_no = get_weeknumber(year,month,day);
	temp = (year - (10 * (year / 10)));
	if ((month == 1) && ((day == 1) || (day == 2))) {
		if ((day == 2) && (dayofweek(year,month,day) == SUNDAY)) {
			year += -1;
			week_no = get_weeknumber(year,12,31);
			temp += -1;
		}
		else {
			if ((day == 1) &&
			    ((dayofweek(year,month,day) == SATURDAY) ||
			    (dayofweek(year,month,day) == SUNDAY))) {
				year += -1;
				week_no = get_weeknumber(year,12,31);
				temp += -1;
			}
		}
	}
	if ((week_no >= 53) && (dayofweek(year,12,31) < FRIDAY)) {
		temp++;
		week_no = 1;
	}
	week = temp * 100 + week_no;
	weekday = dayofweek(year,month,day);
}

/*
 *
 * determine the weeknumber without under- &
 *     overflow detection
 */
get_weeknumber(year,month,day)
int	year;
int	month;
int	day;
{
	int	i;
	int	week_no;
	int	no_days;
	int	leapyear;
	int	rest;

	leapyear = ((year%4) == 0) && (((year%400) == 0) || (year%100 != 0));
	no_days = 0;
	for (i=1; i < month; i++) {
		no_days += ((i == 2 && leapyear) ? 29 : day_month[i]);
	}
	no_days += (day - 1);
	week_no = (no_days / 7);
	rest = no_days - (week_no * 7);
	week_no += 1;
	if (dayofweek(year,1,1) > FRIDAY) week_no += -1;
	if ((dayofweek(year,month,day) -rest) <= MONDAY) week_no +=1;
	return(week_no);
}
/*
 *
 * determine the date (year,month and day)
 * from a given weeknumver and weekday
 *
 */
proces_week(week,weekday)
int	week;
int	weekday;
{
	int	leapyear;
	int	mark;

	year = DECENIUM + (week / 100);
	week = week - (week / 100) * 100;
	leapyear = ((year %4 == 0) && (((year %400) == 0) || (year%100 != 0)));
	day = (week - 1) * 7 + weekday - dayofweek(year,1,1);
	if (day < 0) {
		month = 12;
		year--;
		day = day + 32;
	}
	else
	{
		for (month = 1; day > 0; month++) {
			day -= ((month == 2 && leapyear) ? 29 :
			    day_month[month]);
		}
		month--;
		day += day_month[month] +1;
		month = (month == 0) ? 1 : month;
	}

	mark = FALSE;
	if (day > day_month[month]) {
		day -= day_month[month++];
		if (month > 12) {
			month = 1;
			year++;
			mark = TRUE;
		}
	}
	if ((mark == TRUE) && (month == 1) &&
	    (dayofweek(year,month,day) <= FRIDAY)) {
		return(TRUE);
	}
	return(FALSE);
}
/*
 * determine the weekday from a given date
 * day of the week : Sunday = 6, Monday = 0
 *
 */
dayofweek(year,month,day)
int	year;
int	month;
int	day;
{
	register int yearfactor;
	int	dow;

	yearfactor = year + (month - 14)/12;
	dow = (( (13 * (month + 10 - (month + 10)/13*12) -1)/5
	    + day + 77 + 5 * (yearfactor % 100)/4
	    + yearfactor / 400
	    - yearfactor / 100 * 2) % 7);
	return ( (dow == 0) ? 6 : --dow);
}

/*
 *
 * read the monthname from input
 *
 */
getmonthname(length)
int	length;
{
	int l;

	getstr(length);
	for (month=1; month<13; month++) {
		for (l=0; ((l<length) && 
		    (word[l] == monthnames[month][l])); l++);
		if (l == length) break;
	}
	return ((month == 13) ? TRUE : FALSE);
}

/*
 *
 * read the weekday from input
 *
 */
getweekdayname(length)
int	length;
{
	int l;

	getstr(length);
	for (weekday = 0; (weekday <=7); weekday++) {
		for (l = 0; ((l<length) && 
		    (word[l] == daynames[weekday][l])); l++);
		if (l == length) break;
	}
	if (weekday == 8) return(TRUE);
	weekday = ++weekday%7;
	return (FALSE);
}

/*
 * return 1e param value if 2nd = -1
 * else 2nd param.
 *
 */
rlength(p1,p2)
int	p1;
int	p2;
{
	return( (p2 == -1) ? p1 : p2);
}

/*
 *
 * Read text to global line[].
 *
 */
getline()
{
	register	char *t;
	return (gets(line) == NULL);
}

/*
 *
 * read a value from the inputstring
 * given a low and high bound
 * given a max. length of the number
 * given a following delimite
 *
 */
getval(value,low,high,length)
int	*value;
int	low;
int	high;
int	length;
{
	register int	i;
	register int	temp;

	if (*valptr == '\0') return(TRUE);
	while (*valptr && (*valptr == ' ')) *valptr++;

	for (*value = i = 0;((i < length) && (is_digit(*valptr))); i++) {
		temp = *valptr++ - '0';
		if (temp < 0 || temp > 9) return(TRUE);
		*value = (*value * 10) + temp;
	}
	return((*value >= low && *value <= high) ? FALSE : TRUE);
}

/*
 * read a string of a given length
 *
 */
getstr(length)
int	length;
{
	int	i;

	for (i=0; i < length ; i++) {
		word[i] = *valptr++;
	}
	word[i]='\0';
}

putval(value,length)
int	value;
int	length;
{
	char *form = "%02d";

	form[2] = length + '0';
	sprintf(TEMP,form,value);
	strcat(OUT,TEMP);
	return(0);
}

putstr(string,length)
char	*string;
int	length;
{
	char *form = "%3s";

	form[1] = length + '0';
	sprintf(TEMP,form,string);
	strcat(OUT,TEMP);
	return(0);
}

is_digit(digit)
char	digit;
{
	return (((digit < '0') || (digit > '9')) ? FALSE : digit);
}


/* ETERNAL CALLABLE ROUTINES */

int d2d(inf,in,outf,out)
char	*inf;	/* informat must start with - */
char	*in;	/* instring with format as in inf */
char	*outf;	/* outformat must start with +*/
char	*out;	/* will hold output must be large enough */
		/* return ERROR = 0 if all ok 
		/* 	  ERROR = 1 if error in inf
		/*	  ERROR = 2 if error in in
		/*	  ERROR = 3 if error in outf */
{
	ERROR = 0;
	OUT = out;	/* initialize out */
	strcpy(OUT,"");
	informat = inf;
	outformat = outf;
	dotextline(in);
	return(ERROR);
}