1
0
Files
irix-657m-src/eoe/cmd/bru/date.c
2022-09-29 17:59:04 +03:00

348 lines
7.9 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/************************************************************************
* *
* Copyright (c) 1984, Fred Fish *
* All Rights Reserved *
* *
* This software and/or documentation is protected by U.S. *
* Copyright Law (Title 17 United States Code). Unauthorized *
* reproduction and/or sales may result in imprisonment of up *
* to 1 year and fines of up to $10,000 (17 USC 506). *
* Copyright infringers may also be subject to civil liability. *
* *
************************************************************************
*/
/*
* FILE
*
* date.c routines to do date conversion
*
* SCCS
*
* @(#)date.c 9.11 5/11/88
*
* DESCRIPTION
*
* Routines to convert an ascii date string to an internal
* time. The date may be given in one of the forms:
*
* DD-MMM-YY[,HH:MM:SS]
* MM/DD/YY[,HH:MM:SS]
* MMDDHHMM[YY]
*
*/
#include "autoconfig.h"
#include <stdio.h>
#if unix || xenix
# include <sys/types.h>
# if BSD4_2
# include <sys/time.h>
# else
# include <time.h>
# endif
#else
# include "sys.h" /* Fake for non-unix hosts */
#endif
#include <ctype.h>
#include "typedefs.h" /* Locally defined types */
#include "dbug.h"
#include "manifest.h" /* Manifest constants */
#include "errors.h" /* Error codes */
#include "macros.h" /* Useful macros */
extern VOID bru_error (); /* Report an error to user */
extern char *s_strchr (); /* Find character (forward) */
extern int s_tolower (); /* Convert character to lower case */
extern long s_timezone (); /* Return correction factor for timezone */
#define FEBRUARY 1 /* February is a special month */
#define LEAPSIZE 29 /* February has 29 days in leap years */
#define HOURS_PER_DAY 24 /* Maybe this will be bigger some day! */
#define MIN_PER_HOUR 60 /* Minutes per hour */
#define SEC_PER_MIN 60 /* Seconds per minute */
#define DAYS_IN_YEAR(year) (((year) % 4) ? 365 : 366)
static char *mtable[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
static int month_size[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static BOOLEAN time_sane (); /* Test time for sanity */
/*
* FUNCTION
*
* date convert ascii date string to internal time format
*
* SYNOPSIS
*
* time_t date (cp)
* char *cp;
*
* DESCRIPTION
*
* Given pointer to an ascii date string (cp), converts the
* string to an internal time and returns that value.
*
*/
/*
* PSEUDO CODE
*
* Begin date
* Default time is 1-Jan-70,00:00:00
* Initialize the time structure
* If the string contains a '-' character then
* Clear the month string
* Convert string of first form
* Convert the month
* Else if string contains a "/" character then
* Convert string of second form
* Adjust month
* Else
* Convert a string of the third form
* Adjust month
* End if
* If the time does not pass sanity checks then
* Tell user about conversion error
* Else
* Convert the time
* End if
* Return time
* End date
*
*/
time_t date (cp)
char *cp;
{
time_t mytime; /* Time as converted */
auto char mstr[16]; /* Month in string form */
auto struct tm t; /* Components of time */
int nmatch;
DBUG_ENTER ("date");
DBUG_PRINT ("date", ("convert '%s'", cp));
mytime = 0;
memset((void*)&t, 0, sizeof(t));
if (s_strchr (cp, '-')) {
mstr[0] = EOS;
nmatch = sscanf (cp, "%2d-%3s-%4d", &t.tm_mday, mstr, &t.tm_year);
if(nmatch == 3) /* get rest, if first part present */
(void) sscanf (cp, ",%2d:%2d:%2d", &t.tm_hour, &t.tm_min, &t.tm_sec);
t.tm_mon = conv_month (mstr);
} else if (s_strchr (cp, '/')) {
nmatch = sscanf (cp, "%2d/%2d/%4d", &t.tm_mon, &t.tm_mday, &t.tm_year);
if(nmatch == 3) /* get rest, if first part present */
(void)sscanf (cp, ",%2d:%2d:%2d", &t.tm_hour, &t.tm_min, &t.tm_sec);
t.tm_mon--;
} else {
sscanf (cp, "%2d%2d%2d%2d%4d", &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min, &t.tm_year);
t.tm_mon--;
}
if (!time_sane (&t))
bru_error (ERR_NTIME, cp);
else
mytime = mktime (&t);
DBUG_RETURN (mytime);
}
/*
* FUNCTION
*
* time_sane perform sanity check on time components
*
* SYNOPSIS
*
* static BOOLEAN time_sane (tp)
* register struct tm *tp;
*
* DESCRIPTION
*
* Performs some boundry condition checks on the time to catch
* obvious errors.
*
* Returns TRUE if things look ok, FALSE otherwise.
*
* Note that leap days on the wrong year will NOT be caught.
*
*/
/*
* PSEUDO CODE
*
* Begin time_sane
* Test seconds for sanity
* Test minutes for sanity
* Test hours for sanity
* Test month for sanity
* Test day of month lower bound
* If sane so far then
* If month is FEBRUARY then
* Test upper bound day of february
* Else
* Test upper bound day of other month
* End if
* End if
* Test year for sanity
* Return results of test
* End time_sane
*
*/
static BOOLEAN time_sane (tp)
register struct tm *tp;
{
register BOOLEAN sanity;
DBUG_ENTER ("time_sane");
DBUG_PRINT ("date", ("seconds = %d", tp -> tm_sec));
DBUG_PRINT ("date", ("minutes = %d", tp -> tm_min));
DBUG_PRINT ("date", ("hours = %d", tp -> tm_hour));
DBUG_PRINT ("date", ("mon = %d", tp -> tm_mon));
DBUG_PRINT ("date", ("monthday = %d", tp -> tm_mday));
DBUG_PRINT ("date", ("year = %d", tp -> tm_year));
sanity = (0 <= tp -> tm_sec && tp -> tm_sec < 60);
sanity &= (0 <= tp -> tm_min && tp -> tm_min < 60);
sanity &= (0 <= tp -> tm_hour && tp -> tm_hour < 24);
sanity &= (0 <= tp -> tm_mon && tp -> tm_mon < 12);
sanity &= (0 < tp -> tm_mday);
if (sanity) {
if (tp -> tm_mon == FEBRUARY) {
sanity &= (tp -> tm_mday <= LEAPSIZE);
} else {
sanity &= (tp -> tm_mday <= month_size[tp -> tm_mon]);
}
}
/* put date in 1900 - 2038 (0-138) range; assume if < 39, that
* we must have crossed over into the 2000's; want it to work
* with mktime() */
if(tp->tm_year <= 39) tp->tm_year += 100;
if(tp->tm_year >= 1900) tp->tm_year -= 1900;
sanity &= (70 <= tp -> tm_year && tp -> tm_year < 139);
DBUG_RETURN (sanity);
}
/*
* FUNCTION
*
* conv_month convert string month to integer month
*
* SYNOPSIS
*
* static int conv_month (mstr)
* char *mstr;
*
* DESCRIPTION
*
* Converts string pointed to by "mstr" to an integer month
* by comparing with internal table. Note that comparison
* is case independent but there must be exactly 3 characters.
* This could be fixed with a small amount of effort.
*
* Note that the month is zero-based, to match the form in
* the "tm" structure.
*
*/
/*
* PSEUDO CODE
*
* Begin conv_month
* Set default to illegal month
* For each month in the month table
* If the name matches month string then
* Remember numeric month
* Break month scan loop
* End if
* End for
* Return month
* End conv_month
*
*/
static int conv_month (mstr)
char *mstr;
{
register int i;
register int month;
DBUG_ENTER ("conv_month");
month = -1;
for (i = 0; i < 12; i++) {
if (match (mtable[i], mstr)) {
month = i;
break;
}
}
DBUG_RETURN (month);
}
/*
* FUNCTION
*
* match case independent match test
*
* SYNOPSIS
*
* static BOOLEAN match (cp1, cp2)
* register char *cp1;
* register char *cp2;
*
* DESCRIPTION
*
* Perform case independent match test on two strings. Returns
* TRUE if match found, FALSE otherwise.
*
*/
/*
* PSEUDO CODE
*
* Begin match
* Scan for end of either string or mismatch
* Result is TRUE only if end of both strings
* Return result
* End match
*
*/
static BOOLEAN match (cp1, cp2)
register char *cp1;
register char *cp2;
{
register BOOLEAN result;
DBUG_ENTER ("match");
if (cp1 == NULL || cp2 == NULL) {
bru_error (ERR_BUG, "match");
result = FALSE;
} else {
result = TRUE;
while (*cp1 != EOS && *cp2 != EOS && result) {
result = (s_tolower (*cp1++) == s_tolower (*cp2++));
}
}
DBUG_RETURN (result);
}