/* <qbm.c> 25nov03
**
** Program to calculate benchmark from <queue.dat> file.
** This value will differ slightly from the "qd" benchmark value,
** because "qbm" doesn't take the current unit into account.
*/

/* Define SYSTYPE as needed...
** 0 - Linux
** 1 - Windows NT, 2K, ME, XP
*/

#define SYSTYPE 0

#define QF "queue.dat"		/* Use <queue.dat> in the current directory */
#define QI "qdinfo.dat"		/* qd info file (in the current directory) */

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

typedef int bool;
#ifndef FALSE
# define FALSE		0
# define TRUE		1
#endif

/* Structure of <queue.dat> file (simplified) */

typedef unsigned int u32;
typedef unsigned short u16;

struct qf
{	u32		version;		/* Console program version (2.17 and above) */
	u32		current;		/* Current index number */
	struct qs
	{	u32		stat;		/* 000 Status */
		char	z004[4];	/* 004 Pad for Windows, others as of v4.01 */
		u32		tdata[8];	/* 008 Time data (epoch 0000 1jan00 UTC) */
		char	z036[168];
		u16		proj;		/* 208 Project number */
		char	z206[494];
	}		entry[10];		/* Array of ten queue entries */
	char	z7048[24];
} buf;

/*
** NOTICE: After 1 May 2003 this table will be updated seldom if at all.
**
** The program will attempt to read current information from <qdinfo.dat>.
*/

u16 ptbl[] =		/* Points per WU (project, 100 * points) */
 {	  111,  500,  112,  500,  113,  500,  114,  500,  127,  200,
	  128,  200,  129,  200,  131,  140,  132,  280,  133,  350,
	  134,  190,  135,   70,  136,  130,  137,   60,  138,   60,
	  139,   60,  140,   60,  141,   60,  142,   60,  143,   60,
	  144,   60,  145,   60,  146,  600,  147,   60,  160,  200,
	  161,  200,  162,  200,  163,  200,  164,  200,  165,  200,
	  166,  200,  167,  200,  168,  200,  169,  200,  170,  200,
	  171,  200,  172,  200,  180,  560,  181,  800,  182,  560,
	  183,   70,  184,  900,  185,  900,  186,  640,  187,  640,
	  188,  640,  189,  640,  190,  640,  191, 1800,  192, 1000,
	  200,  200,  201,  760,  202,  760,  203,  760,  204,  760,
	  205,  760,  206,  760,  207,  760,  208,  760,  209,  760,
	  210,  760,  211,  640,  212,  640,  213,  640,  250, 5330,
	  251, 2281,  252, 2281,  253, 2281,  254, 5377,  255, 5377,
	  301,  200,  304,  200,  310,  200,  312,   50,  313,   50,
	  314,   50,  315,  200,  316,  200,  317,  200,  318,  420,
	  319,   50,  320, 5140,  321, 5140,  322, 5140,  323, 5140,
	  324, 5140,  325, 5140,  326, 5140,  327, 5140,  328, 5140,
	  329, 5140,  330, 5140,  332, 5140,  333, 5140,  334, 5140,
	  335, 5140,  336, 5140,  337, 5140,  338, 5140,  340, 5330,
	  341, 5330,  342, 5330,  343, 5330,  344, 5330,  345, 5330,
	  346, 5330,  347, 5330,  348, 5460,  349, 5460,  350, 5140,
	  351, 5140,  352, 5140,  353, 5140,  354, 5140,  355, 5140,
	  356, 5140,  357, 5140,  358, 5140,  359, 5140,  360, 5330,
	  361, 5330,  362, 5460,  363, 5460,  364, 2940,  365, 2940,
	  367, 5330,  368, 2940,  369, 2940,  372, 5330,  373, 5330,
	  374, 1530,  375, 1530,  376, 5330,  377, 5330,  378, 5330,
	  379, 5330,  380, 5330,  381, 5330,  382, 5330,  383, 5330,
	  384, 5330,  385, 5330,  386, 1530,  387, 1530,  388,  956,
	  389,  956,  391,  956,  392,  956,  393,  956,  394,  956,
	  395,  956,  396,  956,  397,  478,  411,   60,  412,   60,
	  434,   30,  435,   30,  437,   30,  439,   30,  441,   60,
	  442,   30,  443,   30,  447,   30,  448,   30,  451,   30,
	  452,   30,  457,   60,  458,   60,  459,   60,  464,   60,
	  465,   60,  466,   60,  468,   60,  469,   60,  472,   60,
	  477,   60,  482,   60,  487,   60,  488,   60,  489,   60,
	  494,   60,  499,   60,  501,  160,  502,  160,  504,  190,
	  505,  160,  506,  160,  507,  160,  508,  160,  509,  600,
	  511,  600,  513,  600,  514,  600,  515,  600,  516,  600,
	  530, 1000,  531,  700,  532, 2400,  533,  700,  534,  700,
	  535,  700,  536, 1000,  537, 1800,  538, 3600,  539, 3300,
	  540, 3300,  541, 3300,  542, 3300,  543, 3300,  544, 3300,
	  545, 3300,  546, 3300,  547, 1800,  548, 1800,  549, 3300,
	  553,  900,  554,   60,  555,  900,  556, 3300,  557,  900,
	  560,   60,  561,   60,  562,   60,  564,   60,  565,   60,
	  566, 3300,  567, 3300,  570, 3600,  571, 4700,  572, 4700,
	  599,  900,  601,   75,  602,   75,  603,  150,  604,  150,
	  605,  150,  606,  150,  607,  100,  608,  140,  609,  280,
	  610,  700,  611,  570,  612,  810,  613,  570,  614,  570,
	  615,  570,  616,  570,  617, 1360,  618, 1040,  619, 1360,
	  620, 1040,  621,  730,  622, 1970,  623, 1970,  624, 1970,
	  625, 1970,  626, 7300,  627, 7300,  628, 5550,  629, 5550,
	  630, 4700,  631, 4700,  632, 2360,  633, 2360,  634, 4830,
	  635, 5990,  636, 4830,  637, 5990,  638, 7090,  639, 7090,
	  640, 1970,  641, 1970,  642, 1970,  643, 1970,  644, 2360,
	  645, 2360,  646, 1970,  647, 1970,  648, 1970,  649, 1970,
	  650, 4060,  651, 4060,  652, 3060,  653, 3060,  654, 1720,
	  655, 1720,  656,14600,  657,14600,  658, 3730,  659, 3730,
	  660, 1970,  661, 1970,  662, 1970,  663, 1970,  664, 1970,
	  665, 1970,  666, 1970,  667, 1970,  668, 3060,  669, 3060,
	  670, 7300,  671, 7300,  672, 1970,  673, 1970,  674, 2360,
	  675, 4060,  676, 1970,  677, 1970,  678, 7090,  679, 2360,
	  680, 7090,  681, 3010,  682, 3010,  683, 6000,  684, 6000,
	  685, 7090,  686, 7090,  687, 7090,  688, 7090,  689, 7090,
	  690, 7090,  691, 7090,  692, 7090,  700,  250,  701,  250,
	  702,  250,  703,  250,  704,  250,  705,  250,  706,  250,
	  707,  250,  720, 1540,  721, 3900,  722, 5460,  723, 4900,
	  724, 4900,  800, 3200,  801, 3200,  802, 3200,  803, 3200,
	  804, 5450,  805, 5450,  806, 5450,  807, 5450,  808, 3200,
	  809, 5450,  810, 3200,  811, 3200,  812, 3200,  815, 3200,
	  816, 3200,  817, 3200,  818, 3200,  819, 3200,  820, 3250,
	  821, 3200,  822, 3200,  823, 3200,  824, 3200,  825, 3200,
	  826, 3200,  827, 3200,  828, 3200,  829, 3200,  830, 3200,
	  831, 3200,  832, 3200,  833, 3200,  834, 3200,  835, 3200,
	  836, 3200,  837, 3200,  838, 3200,  839, 4000,  840, 1150,
	  841, 3250,  842, 3200,  843, 3200,  844, 1150,  901,  320,
	  902,  500,  903,  620,  905, 1300,  906, 1300,  907, 1400,
	  908, 1300,  909, 3800,  910, 5700,  911, 6000,  912, 6000,
	  913, 6500,  997, 1000,  998, 1000, 1001, 4110, 1002, 4110,
	 1003, 4110, 1004, 4110, 1010, 3620, 1011, 3620, 1020, 5140,
	 1021, 5140, 1022, 5140, 1023, 5140, 1024, 5140, 1025, 5140,
	 1026, 5140, 1027, 5140, 1028, 5140, 1029, 5140, 1030, 5140,
	 1031, 5140, 1032, 5140, 1033, 5140, 1034, 5140, 1035, 5140,
	 1036, 5140, 1037, 5140, 1038, 5140, 1039, 5140, 1040, 5140,
	 1041, 5140,
	0
 };

int systype;		/* System type (from SYSTYPE) */
unsigned int qver;	/* Queue version number, from queue or best guess */
bool eswap;			/* Queue file with opposite endianness (default FALSE) */

char wbuf[300];
char nbuf[300];
u16 pbuf[10000];			/* Working point table */

u32 es32(u32);
void eswp(struct qf *);

int main()
{
int i, j, n;
bool f;
float bst, bsp;
int estat;
u16 *ss;
struct qf *bp;
struct qs *p;
u32 *tp;
FILE *fp;
char *q;
int za, zc;
unsigned int zb;

	systype = SYSTYPE;		/* Default is native queue type */
	eswap = FALSE;

	if	(	((fp = fopen(QF, "rb")) == NULL)
		||	((i = fread(&buf, 1, sizeof(struct qf), fp)) < 6844)
		)
	{	printf("Can't read <%s> file\n", QF);
		exit(1);
	}
	fclose(fp);

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

	if ((fp = fopen(QI, "rb")) != NULL)		/* Read qd info file */
	{	while (fgets(wbuf, sizeof(wbuf), fp) != NULL)
		{	nbuf[0] = '\0';
			sscanf(wbuf, "%20s%n", nbuf, &zc);
			q = wbuf + zc;
			if (strcmp(nbuf, "pt") == 0)
				while (sscanf(q, "%d%u%n", &za, &zb, &zc) >= 2)
				{	q += zc;
					for (ss = pbuf; (ss[0] != 0) && (ss[0] != za); ss += 2) ;
					ss[0] = za;
					ss[1] = zb;
				}
		}
		fclose(fp);
	}
	else printf("Warning: no <%s> file\n", QI);

	j = buf.version;
	f = ((j > 0xFFFF) && ((j > 0xFFFF) || (j == 0)));
	qver = 0;
	switch (i)		/* Determine system type, mainly from file length */
	{
	case 6884:		/* 2.15W - 2.17W */
		qver = 217;
		goto tw;
	case 6888:		/* 3.00W - 3.14W */
		qver = 314;
		goto tw;
	case 7048:		/* 3.24W earlier */
	case 7056:		/* 3.24W later */
		qver = 324;
tw:		systype = 1;		/* Windows */
		break;
	case 6848:		/* 2.19L (3.12M) - 3.14LM */
		qver = 314;
		goto tl;
	case 7008:		/* 3.24LM earlier */
	case 7016:		/* 3.24LM later */
	case 7032:		/* 4.00L */
		qver = 324;
tl:		if (f)			/* Wrong endianness */
#if (SYSTYPE == 2)
			systype = 0;	/* Linux */
#else
			systype = 2;	/* Mac */
		else
			systype = 0;	/* Linux */
#endif
		break;
	case 7072:		/* 4.00W, 4.01LWM */
		qver = 401;
		if (f)			/* Wrong endianness */
#if (SYSTYPE == 2)
			systype = 1;	/* Linux or Windows */
#else
			systype = 2;	/* Mac */
		else if (buf.version == 400)
			systype = 1;	/* Windows */
#endif
		break;
	}
#if (SYSTYPE == 2)
	if (systype != 2)
		eswap = TRUE;
#else
	if (systype == 2)
		eswap = TRUE;
#endif

	bst = 0.0;
	bsp = 0.0;

	if (eswap)
	{	j = es32(j);
		eswp(&buf);
	}
	if (j > 9)
	{	qver = j;
		bp = &buf;
	}
	else
		bp = (struct qf *) ((char *) &buf - 4);

	for (n = 10; --n >= 0; )
	{	p = &bp->entry[n];
		if (qver < 324)
			p = (struct qs *) ((char *) p - 16 * n);
		if ((qver < 401) && (systype != 1))
			p = (struct qs *) ((char *) p - 4 * n);
		estat = p->stat;
		if ((qver < 401) && (systype != 1))
			p = (struct qs *) ((char *) p - 4);
		tp = p->tdata;					/* Beginning and ending times */
		if ((qver <= 9) || (systype == 2))
			++tp;			/* Older versions and OS X are 4 bytes higher */
		if	(	(estat != 1)
			&&	(estat != 3)
			&&	(tp[0] != 0)
			&&	(tp[4] != 0)
			&&	((j = tp[4] - tp[0]) < 2592000)
			&&	(j >= 900)
			)
			for (ss = pbuf; ss[0] != 0; ss += 2)
				if (ss[0] == p->proj)
				{	bst += (float) j;
					bsp += (float) ss[1] / 100.0;
					break;
				}
	}
	if (bst != 0.0)
		printf("Annual score benchmark: %.0f\n", bsp * 31556736.0 / bst);
	exit(0);
}

u32 es32(u32 i)
{
	return ((i << 24) | ((i & 0xFF00) << 8)
			| ((i & 0xFF0000) >> 8) | ((i & 0xFF000000) >> 24));
}

void eswp(struct qf *bp)
{
int n;
struct qs *p;

	bp->version = es32(bp->version);
	bp->current = es32(bp->current);
	for (n = 10; --n >= 0; )
	{	p = &bp->entry[n];
		if (qver < 324)
			p = (struct qs *) ((char *) p - 16 * n);
		if ((qver < 401) && (systype != 1))
			p = (struct qs *) ((char *) p - 4 * n);
		p->stat = es32(p->stat);
		if ((qver < 401) && (systype != 1))
			p = (struct qs *) ((char *) p - 4);
		p->tdata[0] = es32(p->tdata[0]);
		p->tdata[1] = es32(p->tdata[1]);
		p->tdata[4] = es32(p->tdata[4]);
		p->tdata[5] = es32(p->tdata[5]);
	}
}
