/*
 * Copyright 2002 Silicon Graphics, Inc. All rights reserved.
 */
#include <kl_lib.h>

/*
 * kl_shift_value()
 */
int
kl_shift_value(uint64_t value)
{
	int i;

	if (value == 0) {
		return(-1);
	}

	for (i = 0; i < 64; i++) {
		if (value & (((uint64_t)1) << i)) {
			break;
		}
	}
	return(i);
}

/*
 * kl_get_bit_value()
 *
 * x = byte_size, y = bit_size, z = bit_offset
 */
uint64_t
kl_get_bit_value(void *ptr, int x, int y, int z)
{
	uint64_t value, mask;
	int right_shift;

	right_shift = ((x * 8) - (y + z)) + ((8 - x) * 8);

	if (y >= 32) {
		int upper_bits = y - 32;
		mask = ((1 << upper_bits) - 1);
		mask = (mask << 32) | 0xffffffff;
	}
	else {
		mask = ((1 << y) - 1);
	}
	bcopy(ptr, &value, x);
	value = value >> right_shift;
	return (value & mask);
}

/*
 * kl_string_compare()
 */
int
kl_string_compare(char *s1, char *s2)
{
	int len_1 = strlen(s1);
	int len_2 = strlen(s2);

	if (len_1 > len_2) {
		return(1);
	}
	else if (len_2 > len_1) {
		return(-1);
	}
	return(strcmp(s1, s2));
}

/*
 * kl_string_match()
 */
int
kl_string_match(char *s1, char *s2)
{
	if (s1) {
		if (!s2) {
			return(0);
		}
		else if (strcmp(s1, s2)) {
			return(0);
		}
	}
	else if (s2) {
		return(0);
	}
	return(1);
}

#define SECONDS_IN_DAY 86400
#define SECONDS_IN_HOUR 3600
#define SECONDS_IN_MINUTE 60
/*
 * kl_str_to_ctime()
 */
time_t
kl_str_to_ctime(char *timestr)
{
	int i, offset;
	int days, months, years;
	int minutes, hours, seconds;
	int year_len;
	char *str, *c, *day, *month, *year, *tval = (char *)NULL;
	char *hour, *minute, *second;
	time_t ctime = 0;
	struct tm ltime, gmtime;

	/* Make a copy of the original string since we
	 * will be modifying it.
	 */
	str = strdup(timestr);

	/* Get the month
	 */
	month = str;
	c = strchr(month, '/');
	*c = 0;

	/* Get the day
	 */
	day =  (c + 1);
	c = strchr(day, '/');
	*c = 0;

	/* Get the year. It will eather be at the end of the string or
	 * we will set the NULL terminating byte when we capture a
	 * pointer to the time string.
	 */
	year = (c + 1);

	/* If there is a time value in the time string then parse
	 * it too.
	 */
	if ((c = strchr(year, ' '))) {
		*c = 0;
		tval = (c + 1);
		if ((c = strchr(tval, '\n'))) {
			*c = 0;
		}
	}

	years = atoi(year);
	year_len = strlen(year);
	if (year_len == 2) {
		if (years > 70) {
			years += 1900;
		} else {
			years += 2000;
		}
	} else if (year_len != 4) {
		return(0);
	}
	for (i = 1970; i < years; i++) {
		if (i % 4) {
			ctime += 365 * SECONDS_IN_DAY;
		} else {
			ctime += 366 * SECONDS_IN_DAY;
		}
	}
	months = atoi(month);
	for (i = 1; i < months; i++) {
		switch (i) {

			case 2:
				if (years % 4) {
					ctime += 28 *
						SECONDS_IN_DAY;
				} else {
					ctime += 29 *
						SECONDS_IN_DAY;
				}
				break;

			case 4:
			case 6:
			case 9:
			case 11:
				ctime += 30 * SECONDS_IN_DAY;
				break;

			case 1:
			case 3:
			case 5:
			case 7:
			case 8:
			case 10:
				ctime += 31 * SECONDS_IN_DAY;
				break;

		}
	}

	/* Add the seconds for all full days in the month
	 */
	days = atoi(day);
	ctime += (days - 1) * SECONDS_IN_DAY;

	/* Add the time for the hours, minutes, and seconds
	 */
	if (tval) {
		hour = tval;
		c = strchr(tval, ':');
		*c = 0;
		hours = atoi(hour);

		minute = (c + 1);
		c = strchr(minute, ':');
		*c = 0;
		minutes = atoi(minute);

		second = (c + 1);
		c = strchr(second, ' ');
		*c = 0;
		seconds = atoi(second);

		c++;
		if (!strncmp(c, "PM", 2)) {
			hours += 12;
		}
		ctime += (hours * SECONDS_IN_HOUR);
		ctime += (minutes * SECONDS_IN_MINUTE);
		ctime += seconds;
	}

	/* Adjust for local time and daylight savings time.
	 * We have to make sure that we watch for the case
	 * where we are at the start of a month or year...
	 */
	localtime_r(&ctime, &ltime);
	gmtime_r(&ctime, &gmtime);

	/* Determine the offset between local time and GMT
	 */
	if (ltime.tm_yday == gmtime.tm_yday) {
		offset = (gmtime.tm_hour - ltime.tm_hour);
	} else if ((ltime.tm_year < gmtime.tm_year) ||
			(ltime.tm_yday < gmtime.tm_yday)) {
		offset = (24 + gmtime.tm_hour) - ltime.tm_hour;
	} else {
		offset = (24 + ltime.tm_hour) - gmtime.tm_hour;
	}
	ctime += (offset * SECONDS_IN_HOUR);
	return(ctime);
}
