/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1997 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#endif
#include <ctype.h>
#include <locale.h>
#include <time.h>
static char *strmatch(/*char *cp, char *string*/);
static char *yearmatch(/*char *cp, char *format, struct tm *tm,
int *hadyearp*/);
static char *cvtnum(/*char *cp, int *nump*/);
static char *skipnws(/*char *format*/);
extern char *getlocale_time();
#define NULL 0
char *
char *buf;
char *format;
{
register char *cp, *p;
register int c, ch;
register int i;
int hadyear;
(void) getlocale_time();
while ((c = *format++) != '\0') {
if (c == '%') {
switch (*format++) {
case '%': /* Percent sign */
if (*cp++ != '%')
return (NULL);
break;
case 'a': /* Abbreviated weekday name */
case 'A': /* Weekday name */
for (i = 0; i < 7; i++) {
dtcp->weekday_names[i],
dtcp->abbrev_weekday_names[i],
goto match_wday;
}
return (NULL); /* no match */
cp = p;
break;
case 'h':
case 'b': /* Abbreviated month name */
case 'B': /* Month name */
for (i = 0; i < 12; i++) {
dtcp->month_names[i],
dtcp->abbrev_month_names[i],
goto match_month;
}
return (NULL); /* no match */
cp = p;
break;
case 'c': /* date and time representation */
return (NULL);
break;
case 'C': /* long date and time representation */
return (NULL);
break;
case 'd': /* Day of month, with leading zero */
case 'e': /* Day of month without leading zero */
return (NULL); /* no digits */
return (NULL);
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'D': /* Shorthand for %m/%d/%y */
return (NULL);
break;
case 'H': /* Hour (24 hour version) */
case 'k': /* Hour (24 hour version) */
return (NULL); /* no digits */
return (NULL);
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'I': /* Hour (12 hour version) */
case 'l': /* Hour (12 hour version) */
return (NULL); /* no digits */
return (NULL);
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'j': /* Julian date */
return (NULL); /* no digits */
return (NULL);
break;
case 'm': /* Month number */
return (NULL); /* no digits */
return (NULL);
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'M': /* Minute */
/*
* This is optional; if we're at the end of the
* string, or the next character is white
* space, don't try to match it.
*/
if ((c = *cp) != '\0'
&& !isspace((unsigned char)c)) {
return (NULL); /* no digits */
return (NULL);
}
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'p': /* AM or PM */
/*
* AM.
*/
cp = p;
/*
* PM.
*/
return (NULL); /* error */
cp = p;
}
break;
case 'r': /* Shorthand for %I:%M:%S AM or PM */
return (NULL);
break;
case 'R': /* Time as %H:%M */
return (NULL);
break;
case 'S': /* Seconds */
/*
* This is optional; if we're at the end of the
* string, or the next character is white
* space, don't try to match it.
*/
if ((c = *cp) != '\0'
&& !isspace((unsigned char)c)) {
return (NULL); /* no digits */
return (NULL);
}
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
break;
case 'T': /* Shorthand for %H:%M:%S */
return (NULL);
break;
case 'x': /* Localized date format */
return (NULL);
break;
case 'X': /* Localized time format */
return (NULL);
break;
case 'y': /* Year in the form yy */
return (NULL);
if (hadyear) {
}
return (cp); /* match is complete */
case 'Y': /* Year in the form ccyy */
return (NULL);
if (hadyear) {
return (NULL);
}
return (cp); /* match is complete */
default:
return (NULL); /* unknown conversion */
}
} else {
if (isspace((unsigned char)c)) {
;
cp--;
} else {
if (*cp++ != c)
return (NULL);
}
}
}
return (cp);
}
/*
* Try to match the beginning of the string pointed to by "cp" with the string
* pointed to by "string". The match is independent of the case of either
* string.
*
* "termc" is the next character in the format string following the one for
* which this match is being done. If the match succeeds, make sure the next
* character after the match is either '\0', or that it would match "termc".
*
* If both matches succeed, return a pointer to the next character after the
* first match. Otherwise, return NULL.
*/
static char *
register char *cp;
register char *string;
char termc;
{
register unsigned char c, strc;
/*
* Match the beginning portion of "cp" with "string".
*/
c = *cp++;
if (isupper(c))
c = tolower(c);
if (c != strc)
return (NULL);
}
if ((c = *cp) != '\0') {
if (!isspace(c))
return (NULL);
} else {
if (c != (unsigned char)termc)
return (NULL);
}
}
return (cp);
}
/*
* Try to match a %y or %Y specification.
* If it matches, try matching the rest of the format. If it succeeds, just
* return. Otherwise, try backing the scan up, ignoring the %y/%Y and any
* following non-white-space string. If that succeeds, just return. (This
* permits a missing year to be detected if it's at the beginning of a date, as
* well as if it's at the end of a date, so that formats such as "%Y/%m/%d" can
* match "3/14" and default the year.)
*
* Set "*hadyearp" to indicate whether a year was specified or not.
*/
static char *
register char *cp;
char *format;
int *hadyearp;
{
register int c;
char *savecp;
int saveyear;
/*
* This is optional; if we're at the end of the
* string, or the next character is white
* space, don't try to match it.
*/
return (NULL); /* no digits */
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
/*
* Year can also be optional if it's at
* the *beginning* of a date. We check
* this by trying to parse the rest of
* the date here. If we succeed, OK;
* otherwise, we skip over the %y and
* try again.
*/
*hadyearp = 1;
else {
*hadyearp = 0;
}
} else {
*hadyearp = 0;
if ((c = *cp) == '\0'
|| isspace((unsigned char)c))
}
return (cp);
}
/*
* Try to match a (decimal) number in the string pointed to by "cp".
* If the match succeeds, store the result in the "int" pointed to by "nump"
* and return a pointer to the character following the number in the string.
* If it fails, return NULL.
*/
static char *
register char *cp;
int *nump;
{
register int c;
register int i;
c = (unsigned char)*cp++;
if (!isdigit(c))
return (NULL); /* no digits */
i = 0;
do {
i = i*10 + c - '0';
c = (unsigned char)*cp++;
} while (isdigit(c));
*nump = i;
return (cp - 1);
}
/*
* If a format item (such as %H, hours) is followed by a non-white-space
* character other than "%", and the part of the string that matched the format
* item is followed by white space, the string of non-white-space,
* non-format-item characters following that format item may be omitted.
*/
static char *
register char *format;
{
register char c;
/*
* Skip over non-white-space, non-digit characters. "%" is special.
*/
if (c == '%') {
/*
* This is a format item. If it's %%, skip it as
* that's a non-white space, non-digit character.
*/
format++; /* skip % */
else
break;
}
format++;
}
return (format);
}