/*
 * Refer to file UPDNODES.H for copyright and version information
 */

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

#ifndef MSDOS
#ifndef	oldcc
static void strip(char * s);
int16u wrotl(int16u num, int16u rot);
#else
static void strip();
int16u wrotl();
#endif	/* oldcc */
#endif	/* MSDOS */

#ifndef	oldcc
void validate_checksum(NODE_ENTRY * maj, char * desc, int16u * tot)
#else
void validate_checksum(maj, desc, tot)
NODE_ENTRY * maj;
char * desc;
int16u * tot;
#endif	/* oldcc */
{
    int16u cur_cks;
    TAG_ENTRY * min;
    int i;
    static char t[255];

    if (!maj)				return;
    maj->have_checksum = FALSE;

    *tot = chksum(maj->name, *tot);
    cur_cks = chksum(maj->name, 0);

    for (min = maj->tags, i = maj->num_tags; i && min->name[0]; min++, i--) {
	if (!strcmp(min->name, "cks")) {
	    if (!maj->have_checksum && strcmp(min->value, "NOCKS")) {
		maj->checksum = atoi(min->value);
		maj->have_checksum = TRUE;
	    }
	} else if (!min->value[0]) {
	    continue;			/* Don't do blank values */
	} else if (strcmp(min->name, "totcks")) {
	    t[0] = ':';
	    strcpy(t+1, min->name);
	    strcat(t, ".");
	    strcat(t, min->value);
	    cur_cks = chksum(t, cur_cks);
	}
    }

    if (maj->have_checksum && maj->checksum != cur_cks) {
	error("Checksum for entry %s invalid %s.\n", maj->name, desc);
	error("Verification: %u/%x, Calculated: %u/%x\n", maj->checksum,
		maj->checksum, cur_cks, cur_cks);
	maj->checksum = cur_cks;
    }
}

#ifndef	oldcc
int estrcmp(const char * s1, const char * s2)
#else
int estrcmp(s1, s2)
const char * s1;
const char * s2;
#endif	/* oldcc */
{
    static unsigned char t1[255];
    static unsigned char t2[255];
#ifndef	MSDOS
    unsigned char * p;
    unsigned char * q;
#endif	/* MSDOS */

    atoe((unsigned char *) strcpy((char *) t1, s1));
    atoe((unsigned char *) strcpy((char *) t2, s2));
#ifdef	MSDOS
    return (strcmp(t1, t2));
#else
    for(p = t1, q = t2; *p && *q && *p == *q; p++, q++);
    return(*p - *q);
#endif	/* MSDOS */
}

#ifndef	MSDOS
#ifndef	oldcc
int16u chksum(char * in_string, int16u oldsum)
#else
int16u chksum(in_string, oldsum)
char * in_string;
int16u oldsum;
#endif	/* oldcc */
{
    static unsigned char s[255];
    unsigned char * p;
    int16u cksum;
    int16u cur;

    strip(strcpy((char *) s, in_string));
    if (!*s) {
	return (oldsum);
    }

    atoe(s);

    cksum = 0;
    p = s;
    do {
	cur = p[1] + ((int16u) *p << 8);
	cur = wrotl(cur, (cksum & 0x0f));
	cksum ^= cur;
	p += 2;
    } while (*p && *(p-1));

    cksum ^= oldsum;
    return (cksum);
}

#ifndef	oldcc
static void strip(char * s)
#else
static void strip(s)
char * s;
#endif	/* oldcc */
{
    char * p;
    int q;

    for (p = s; *p && *p == ' '; p++);
    strcpy(s, p);
    if (!*s)				return;

    for (q = strlen(s) - 1; q && s[q] == ' '; q--);
    s[++q] = '\0';
    return;
}

#ifndef	oldcc
static void atoe(unsigned char * s)
#else
static void atoe(s)
unsigned char * s;
#endif	/* oldcc */
{
    static unsigned char atoe_table[256] = {
	0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
	0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
	0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
	0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d,
	0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
	0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
	0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
	0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
	0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
	0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
	0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
	0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
	0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
	0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
	0x20, 0x21, 0x22, 0x23, 0x24, 0x2a, 0x06, 0x17,
	0x28, 0x29, 0x15, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
	0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08,
	0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
	0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
	0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
	0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
	0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
	0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d,
	0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
	0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xbb, 0xae, 0xaf,
	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
	0xb8, 0xb9, 0xba, 0x4a, 0xbc, 0xfc, 0xbe, 0xbf,
	0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
	0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed,
	0xee, 0xef, 0xfa, 0xfb, 0x6a, 0xfd, 0xfe, 0xff
    };

    unsigned char * p;

    for (p = s; *p; p++) {
	*p = atoe_table[*p];
    }
}

#ifndef	oldcc
int16u wrotl(int16u num, int16u rot)
#else
int16u wrotl(num, rot)
int16u num;
int16u rot;
#endif	/* oldcc */
{
#ifdef	SAMPLE

/*
 * This is the simplest case of the rotate algorithm. The default version (after
 * the else clause) is used to save CPU cycles, since this routine is the single
 * largest component of the execution time. You could do even better by building
 * an assembly-language version of this routine.
 */

    register union t {
	int16u u;
	struct {
#ifdef	WEIRD_BIT_ORDER
	    unsigned high:1;
	    unsigned filler:15;
#else
	    unsigned filler:15;
	    unsigned high:1;
#endif	/* WEIRD_BIT_ORDER */
	} b;
    } current;

    current.u = num;
    for (; rot; rot--) {		/* Default case */
	current.u = current.b.high + (current.u << 1);
    }
    return(current.u);
}
#else
    register union t {
	int16u u;
	struct {
#ifdef	WEIRD_BIT_ORDER
	    unsigned high:1;
	    unsigned filler:15;
#else
	    unsigned filler:15;
	    unsigned high:1;
#endif	/* WEIRD_BIT_ORDER */
	} b;
	struct {
#ifdef	WEIRD_BIT_ORDER
	    unsigned top_half:8;
	    unsigned bot_half:8;
#else
	    unsigned bot_half:8;
	    unsigned top_half:8;
#endif	/* WEIRD_BIT_ORDER */
        } c;
    } current;
    register int rotc = rot;		/* local copy for optimization */

    if (!rotc)				/* Rotate by 0 */
	return(num);

    current.u = num;

    if (rotc == 8)			/* Rotate by 8 (byte swap) */
	return((num << 8) + current.c.top_half);

    if (rotc > 8) {			/* Rotate the other way */
	rotc = 16 - rotc;
	for (; rotc; rotc--) {
	    current.u = ((current.u & 1) << 15) + (current.u >> 1);
	}
	return(current.u);
    }

    for (; rotc; rotc--) {		/* Default case */
	current.u = current.b.high + (current.u << 1);
    }
    return(current.u);
}
#endif	/* SAMPLE */
#endif	/* MSDOS */
