/* <qdiprint.c> 8may04 */

/*
** Program to print data from "pt" and "ph" entries in <qdinfo.dat> file.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#define TIME_OFS 946684800U		/* Linux epoch is 1970, FAH (Cosm) is 2000 */

#ifndef TZONE
# define TZONE (0 * 3600)	/* Our own time printer needs the time zone */
#endif
char mtab[] = "Jan\037Feb\035Mar\037Apr\036May\037Jun\036\
Jul\037Aug\037Sep\036Oct\037Nov\036Dec\037";

int flags;			/* Various flag bits */
#define F_ZONE 0x0001	/* Time zone specified (don't use "ctime") */
#define F_PVER 0x0002	/* Just print version information and stop */

char wbuf[500];
char nbuf[100];

typedef int bool;
typedef unsigned short u16;
typedef unsigned int u32;

#ifndef FALSE
# define FALSE		0
# define TRUE		1
#endif

struct ptent
{	u16			proj;			/* Project number */
	u16			points;			/* Points */
	u32			until;			/* Time points may have changed */
} pbuf[10000];				/* Working point table */

struct pnent
{	u16			min;			/* Minimum project number */
	u16			max;			/* Maximum project number */
} mbuf[200];				/* Matching project number table */

FILE *fpi;
struct pnent *pnp;	/* Pointer to next free mbuf entry */
char *nfil;			/* Name of qd info file (default "qdinfo.dat") */
int tzone;			/* Time zone (default TZONE) */

void prtime(char *, unsigned int);

/*
** Sort function (called inside of "qsort")
**  Put all entries into project order with most recent first.
*/

int cfunc(const void *a, const void *b)
{
#define A ((struct ptent *) a)
#define B ((struct ptent *) b)
	if (A->proj < B->proj) return (-1);
	if (A->proj > B->proj) return (1);
	if (A->until < B->until) return (1);
	if (A->until > B->until) return (-1);
	return (0);
#undef A
#undef B
}

/* Project number match lookup */

bool pnmatch(u16 pn)
{
struct pnent *p;

	for (p = mbuf; p < pnp; ++p)
		if ((pn >= p->min) && (pn <= p->max))
			return (TRUE);
	return (pnp == mbuf);
}

/* And the main program... */

int main(int argc, char *argv[])		/* qdiprint */
{
char *argv0;
char *s1;
int i;
u32 until;
char *q;
struct ptent *pb;
unsigned int proj, points;
int za, zb;
char zc;
char dbuf[40];

	argv0 = argv[0];
	nfil = "qdinfo.dat";
	pnp = mbuf;				/* Default is to print all projects */
	tzone = TZONE;

	/* Parse arguments */

	while (--argc > 0)
	{	++argv;
		if (*argv[0] == '-')
		{	s1 = *argv;
			while (*++s1 != '\0')
				switch (*s1)
				{
				default:
us:					fprintf(stderr, "\n\
Usage: %.200s [<flags> <flag args>]* [<project number or range>]*\n", argv0);
					fprintf(stderr,"\
 -u      Print this usage message (and exit)\n\
 -n file Explicitly specify qd info file\n\
 -t zone Override time zone (+HHMM or -HHMM)\n\
 -z      Force UTC (same as -t +0000)\n\
 -v      Print info version, stop if no project specified\n");
					exit(1);

				case 'n':		/* Explicitly specify qd info file */
					if (--argc <= 0)
					{	q = "Missing qd info file name argument";
						goto pe;
					}
					nfil = *++argv;
					break;
				case 't':		/* Override time zone (needs argument) */
					if (--argc <= 0)
					{	q = "Missing time zone argument";
						goto pe;
					}
					q = *++argv;
					if	(	(strlen(q) != 5)
						||	((q[0] != '+') && (q[0] != '-'))
						||	(sscanf(&q[1], "%4d%c", &za, &zc) != 1)
						||	(za < 0)
						||	((za % 100) >= 60)
						||	(za >= 2400)
						)
					{	q = "Bad time zone argument";
						goto pe;
					}
					tzone = za * 36 + (za % 100) * 24;
					if (q[0] == '-')
						tzone = -tzone;
					goto tz;
				case 'z':		/* Force UTC */
					tzone = 0;
tz:					flags |= F_ZONE;	/* Suppress use of "ctime" */
					break;
				case 'v':		/* Print version information */
					flags |= F_PVER;
					break;
				}
			continue;
		}
		if	(	(sscanf(*argv, "%d%c", &za, &zc) == 1)
			&&	(za > 0)
			) zb = za;
		else if	(	(sscanf(*argv, "%d-%d%c", &za, &zb, &zc) != 2)
				||	(za <= 0)
				||	(zb < za)
				)
		{	q = "Bad project number argument";
pe:			fprintf(stderr,"\n%.200s: %.200s\n", argv0, q);
			goto us;
		}
		pnp->min = za;
		pnp->max = zb;
		++pnp;
	}


	if ((fpi = fopen(nfil, "r")) == NULL)
	{	printf("can't open <%s>\n", nfil);
		exit(1);
	}

	memset(pbuf, 0, sizeof(pbuf));

	while (fgets(wbuf, sizeof(wbuf), fpi) != NULL)
	{	nbuf[0] = '\0';
		sscanf(wbuf, "%20s%n", nbuf, &za);
		q = wbuf + za;
		if (strcmp(nbuf, "da") == 0)
		{	if ((pnp == mbuf) || ((flags & F_PVER) != 0))
			{	while ((*q == ' ') || (*q == '\t')) ++q;
				for	(	s1 = q + strlen(q) - 1
					;	(	(*s1 == 0x0A)
						||	(*s1 == 0x0D)
						||	(*s1 == ' ')
						||	(*s1 == '\t')
						)
					;	--s1
					) ;
				if (s1 > q)
				{	*++s1 = '\0';
					printf("qd info %.50s\n", q);
				}
			}
		}
		else if (strcmp(nbuf, "pt") == 0)
			while (sscanf(q, "%u%u%n", &proj, &points, &za) >= 2)
			{	q += za;
				for (pb = pbuf; pb->proj != 0; ++pb)
				{	if ((pb->proj != proj) || (pb->until != 0xFFFFFFFF)) continue;
					if (pb->points != points)
						printf("#- conflicting \"pt\" entry, project %u, points %u/%u\n",
								pb->proj, pb->points, points);
					break;
				}
				pb->proj = proj;
				pb->points = points;
				pb->until = 0xFFFFFFFF;
			}
		else if (strcmp(nbuf, "ph") == 0)
			while (sscanf(q, "%u%u%x%n", &proj, &points, &until, &za) >= 3)
			{	q += za;
				for (pb = pbuf; pb->proj != 0; ++pb)
				{	if ((pb->proj != proj) || (pb->until != until)) continue;
					if (pb->points != points)
						printf("#- conflicting \"ph\" entry, project %u, points %u/%u\n",
								pb->proj, pb->points, points);
					break;
				}
				pb->proj = proj;
				pb->points = points;
				pb->until = until;
			}
	}
	fclose(fpi);

	for (pb = pbuf; pb->proj != 0; ++pb) ;
	qsort(pbuf, pb - pbuf, sizeof(struct ptent), &cfunc);
	if ((pnp == mbuf) || ((flags & F_PVER) != 0))
		printf("%d records in <%s>\n", (int) (pb - pbuf), nfil);
	if ((pnp == mbuf) && ((flags & F_PVER) != 0))
		exit(0);
	printf("\n");

	i = -1;
	for (pb = pbuf; pb->proj != 0; ++pb)
	{	if (!pnmatch(pb->proj))
			continue;
		if (pb->until == 0xFFFFFFFF)
			printf("Project %d, %d.%.02d points\n", pb->proj, pb->points / 100, pb->points % 100);
		else
		{	if (i != pb->proj)
				printf("Project %d, ** no current information **\n", pb->proj);
			prtime(dbuf, pb->until);
			printf("  %d.%.02d points until %s\n", pb->points / 100, pb->points % 100, dbuf);
		}
		i = pb->proj;
	}
	if (i == -1)
	{	if ((pnp == &mbuf[1]) && (mbuf[0].min == mbuf[0].max))
			printf(" ** no information for project %d\n", mbuf[0].min);
		else
			printf(" ** no information for any of requested projects\n");
	}
	printf("\n");
	exit(0);
}

/* Print time and date, epoch 0000 1 January 2000 */

void prtime(char *p, unsigned int t)
{
int d, i, y;
char *q, *w;
#if !NO_CTIME
time_t a;
#endif

	if (t == 0)
		strcpy(p, "ZERO");		/* ?? */
#if !NO_CTIME
	else if ((flags & F_ZONE) == 0)
	{	a = t + TIME_OFS;	/* Adjust epoch, "ctime" does local time zone */
		if ((q = ctime(&a)) == NULL) q = "BAD DATE";	/* ?? */
		else q[strlen(q) - 1] = '\0';	/* Get rid of the newline */
		strcpy(p, q);
	}
#endif
	else
	{	t += tzone;
		i = 1401 + t / 86400;
		w = &"FriSatSunMonTueWedThu"[3 * (i % 7)];
		d = i % 1461;
		d += 60 + d / 365;
		if (d == 1524) --d;
		y = 1996 + ((i / 1461) << 2) + d / 366;
		d %= 366;
		for (q = mtab; (i = d - (int) q[3]) >= 0; q += 4) d = i;
		i = t % 86400;
		sprintf(p, "%3.3s%4.3s%3d %02d:%02d:%02d %d",
				w, q, d + 1, i / 3600, (i % 3600) / 60, i % 60, y);
	}
	return;
}
