source: trunk/libs/newlib/src/newlib/libc/sys/linux/getdate.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.6 KB
Line 
1/* Convert a string representation of time to a time value.
2   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4   Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
5
6   The GNU C Library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either
9   version 2.1 of the License, or (at your option) any later version.
10
11   The GNU C Library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with the GNU C Library; if not, write to the Free
18   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19   02111-1307 USA.  */
20
21/*
22FUNCTION
23<<getdate>>,<<getdate_r>>---convert a string representation of time to a time value
24
25INDEX
26        getdate
27INDEX
28        getdate_r
29
30SYNOPSIS
31        #include <time.h>
32        struct tm *getdate(const char *<[string]>);
33        int getdate_r(const char *<[string]>, struct tm *<[res]>);
34
35DESCRIPTION
36<<getdate>> reads a file which is specified by the environment variable:
37DATEMSK.  This file contains a number of formats valid for input to the
38<<strptime>> function.  The input <[string]> is used as input to the format
39strings and the first valid match that occurs is used.  The resultant
40time struct is returned.  If an error occurs, the value <<getdate_err>> is
41set to one of the following values.
42
43     1  the DATEMSK environment variable is null or undefined,
44     2  the template file cannot be opened for reading,
45     3  failed to get file status information,
46     4  the template file is not a regular file,
47     5  an error is encountered while reading the template file,
48     6  memory allication failed (not enough memory available),
49     7  there is no line in the template that matches the input,
50     8  invalid input specification
51
52The <<getdate_r>> routine is similar, except that it returns the error
53code and has the <[res]> time struct pointer passed in.  <<getdate>> is
54non-reentrant.  Applications that wish to be reentrant should use
55<<getdate_r>> instead of <<getdate>>. 
56
57RETURNS
58<<getdate>> returns a pointer to the traditional time representation
59(<<struct tm>>).  <<getdate_r>> returns 0 if successful, otherwise it
60returns the error code.
61
62PORTABILITY
63<<getdate>> is defined by the Single Unix specification.
64<<getdate_r>> is a reentrant extension.
65
66<<getdate>> and <<getdate_r>> optionally require <<stat>> and <<access>>.
67*/
68
69
70/* Modified for newlib by Jeff Johnston, June 19/2002 */
71
72#include <limits.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <time.h>
77#include <unistd.h>
78#include <sys/stat.h>
79
80#if !defined(_ELIX_LEVEL) || _ELIX_LEVEL >= 2
81# define STAT stat64
82#else
83# define STAT stat
84#endif
85
86#define TM_YEAR_BASE 1900
87
88extern ssize_t __getline (char **, size_t *, FILE *);
89
90/* Prototypes for local functions.  */
91static int first_wday (int year, int mon, int wday);
92static int check_mday (int year, int mon, int mday);
93
94#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
95
96/* Error code is set to one of the following values to indicate an error.
97     1  the DATEMSK environment variable is null or undefined,
98     2  the template file cannot be opened for reading,
99     3  failed to get file status information,
100     4  the template file is not a regular file,
101     5  an error is encountered while reading the template file,
102     6  memory allication failed (not enough memory available),
103     7  there is no line in the template that matches the input,
104     8  invalid input specification Example: February 31 or a time is
105        specified that can not be represented in a time_t (representing
106        the time in seconds since 00:00:00 UTC, January 1, 1970) */
107
108/* Returns the first weekday WDAY of month MON in the year YEAR.  */
109static int
110first_wday (int year, int mon, int wday)
111{
112  struct tm tm;
113
114  if (wday == INT_MIN)
115    return 1;
116
117  memset (&tm, 0, sizeof (struct tm));
118  tm.tm_year = year;
119  tm.tm_mon = mon;
120  tm.tm_mday = 1;
121  mktime (&tm);
122
123  return (1 + (wday - tm.tm_wday + 7) % 7);
124}
125
126
127/* Returns 1 if MDAY is a valid day of the month in month MON of year
128   YEAR, and 0 if it is not.  */
129static int
130check_mday (int year, int mon, int mday)
131{
132  switch (mon)
133    {
134    case 0:
135    case 2:
136    case 4:
137    case 6:
138    case 7:
139    case 9:
140    case 11:
141      if (mday >= 1 && mday <= 31)
142        return 1;
143      break;
144    case 3:
145    case 5:
146    case 8:
147    case 10:
148      if (mday >= 1 && mday <= 30)
149        return 1;
150      break;
151    case 1:
152      if (mday >= 1 && mday <= (isleap (year) ? 29 : 28))
153        return 1;
154      break;
155    }
156
157  return 0;
158}
159
160
161int
162getdate_r (const char *string, struct tm *tp)
163{
164  FILE *fp;
165  char *line;
166  size_t len;
167  char *datemsk;
168  char *result = NULL;
169  time_t timer;
170  struct tm tm;
171  struct STAT st;
172  int mday_ok = 0;
173
174  datemsk = getenv ("DATEMSK");
175  if (datemsk == NULL || *datemsk == '\0')
176    return 1;
177
178  if (STAT (datemsk, &st) < 0)
179    return 3;
180
181  if (!S_ISREG (st.st_mode))
182    return 4;
183
184  if (access (datemsk, R_OK) < 0)
185    return 2;
186
187  /* Open the template file.  */
188  fp = fopen (datemsk, "r");
189  if (fp == NULL)
190    return 2;
191
192  line = NULL;
193  len = 0;
194  do
195    {
196      ssize_t n;
197
198      n = __getline (&line, &len, fp);
199      if (n < 0)
200        break;
201      if (line[n - 1] == '\n')
202        line[n - 1] = '\0';
203
204      /* Do the conversion.  */
205      tp->tm_year = tp->tm_mon = tp->tm_mday = tp->tm_wday = INT_MIN;
206      tp->tm_hour = tp->tm_sec = tp->tm_min = INT_MIN;
207      tp->tm_isdst = -1;
208      result = strptime (string, line, tp);
209      if (result && *result == '\0')
210        break;
211    }
212  while (!__sfeof (fp));
213
214  /* Free the buffer.  */
215  free (line);
216
217  /* Check for errors. */
218  if (__sferror (fp))
219    {
220      fclose (fp);
221      return 5;
222    }
223
224  /* Close template file.  */
225  fclose (fp);
226
227  if (result == NULL || *result != '\0')
228    return 7;
229
230  /* Get current time.  */
231  time (&timer);
232  localtime_r (&timer, &tm);
233
234  /* If only the weekday is given, today is assumed if the given day
235     is equal to the current day and next week if it is less.  */
236  if (tp->tm_wday >= 0 && tp->tm_wday <= 6 && tp->tm_year == INT_MIN
237      && tp->tm_mon == INT_MIN && tp->tm_mday == INT_MIN)
238    {
239      tp->tm_year = tm.tm_year;
240      tp->tm_mon = tm.tm_mon;
241      tp->tm_mday = tm.tm_mday + (tp->tm_wday - tm.tm_wday + 7) % 7;
242      mday_ok = 1;
243    }
244
245  /* If only the month is given, the current month is assumed if the
246     given month is equal to the current month and next year if it is
247     less and no year is given (the first day of month is assumed if
248     no day is given.  */
249  if (tp->tm_mon >= 0 && tp->tm_mon <= 11 && tp->tm_mday == INT_MIN)
250    {
251      if (tp->tm_year == INT_MIN)
252        tp->tm_year = tm.tm_year + (((tp->tm_mon - tm.tm_mon) < 0) ? 1 : 0);
253      tp->tm_mday = first_wday (tp->tm_year, tp->tm_mon, tp->tm_wday);
254      mday_ok = 1;
255    }
256
257  /* If no hour, minute and second are given the current hour, minute
258     and second are assumed.  */
259  if (tp->tm_hour == INT_MIN && tp->tm_min == INT_MIN && tp->tm_sec == INT_MIN)
260    {
261      tp->tm_hour = tm.tm_hour;
262      tp->tm_min = tm.tm_min;
263      tp->tm_sec = tm.tm_sec;
264    }
265
266  /* If no date is given, today is assumed if the given hour is
267     greater than the current hour and tomorrow is assumed if
268     it is less.  */
269  if (tp->tm_hour >= 0 && tp->tm_hour <= 23
270      && tp->tm_year == INT_MIN && tp->tm_mon == INT_MIN
271      && tp->tm_mday == INT_MIN && tp->tm_wday == INT_MIN)
272    {
273      tp->tm_year = tm.tm_year;
274      tp->tm_mon = tm.tm_mon;
275      tp->tm_mday = tm.tm_mday + ((tp->tm_hour - tm.tm_hour) < 0 ? 1 : 0);
276      mday_ok = 1;
277    }
278
279  /* Fill in the gaps.  */
280  if (tp->tm_year == INT_MIN)
281    tp->tm_year = tm.tm_year;
282  if (tp->tm_hour == INT_MIN)
283    tp->tm_hour = 0;
284  if (tp->tm_min == INT_MIN)
285    tp->tm_min = 0;
286  if (tp->tm_sec == INT_MIN)
287    tp->tm_sec = 0;
288
289  /* Check if the day of month is within range, and if the time can be
290     represented in a time_t.  We make use of the fact that the mktime
291     call normalizes the struct tm.  */
292  if ((!mday_ok && !check_mday (TM_YEAR_BASE + tp->tm_year, tp->tm_mon,
293                                tp->tm_mday))
294      || mktime (tp) == (time_t) -1)
295    return 8;
296
297  return 0;
298}
299
300#ifndef _REENT_ONLY
301struct tm *
302getdate (const char *string)
303{
304  /* Buffer returned by getdate.  */
305  static struct tm tmbuf;
306  int errval = getdate_r (string, &tmbuf);
307
308  if (errval != 0)
309    {
310      getdate_err = errval;
311      return NULL;
312    }
313
314  return &tmbuf;
315}
316#endif /* _REENT_ONLY */
Note: See TracBrowser for help on using the repository browser.