Mercurial > emacs
comparison src/mktime.c @ 26088:b7aa6ac26872
Add support for large files, 64-bit Solaris, system locale codings.
* Makefile.in (emacs): Set the LC_ALL environment variable to "C"
when dumping, so that the dumped Emacs doesn't have stray locale info.
(dired.o): Depend on systime.h.
(editfns.o): Depend on coding.h.
* alloc.c, buffer.c, callproc.c, ccl.c, charset.c, coding.c, data.c,
dispnew.c, editfns.c, emacs.c, filelock.c, floatfns.c, hftctl.c,
keyboard.c, process.c, sysdep.c, unexelf.c, unexhp9k800.c,
unexsunos4.c, vmsfns.c, vmsgmalloc.c, w32faces.c, w32menu.c, w32term.c,
w32xfns.c, xfaces.c, xfns.c, xmenu.c, xterm.c:
Include <config.h> before any system include files.
* alloc.c, buffer.c, ccl.c, data.c, editfns.c, emacs.c, eval.c,
fileio.c, filelock.c, frame.c, insdel.c, keymap.c, lread.c,
m/alpha.h, print.c, search.c, sysdep.c, xdisp.c, xfaces.c, xfns.c,
xmenu.c, xterm.c:
Do not include <stdlib.h>, as <config.h> does this now.
* callproc.c (Fcall_process):
Synchronize messages locale before invoking strerror.
Decode resulting string with locale-coding-system.
* coding.c (Vlocale_coding_system): New var.
(syms_of_coding): Adjust to above change.
(emacs_strerror): New function.
* coding.h (emacs_strerror, Vlocale_coding_system): New decls.
* config.in (HAVE_STDIO_EXT_H, HAVE_TM_GMTOFF, HAVE___FPENDING,
HAVE_FTELLO, HAVE_GETLOADAVG, HAVE_MBLEN, HAVE_MBRLEN,
HAVE_STRSIGNAL): New macros.
(BITS_PER_LONG): Default to 64 if _LP64 is defined.
<stdlib.h>: Include if HAVE_STDLIB_H is defined and NOT_C_CODE isn't.
* dired.c: Include "systime.h".
(Ffile_attributes): Do not cast s.st_size to int; this loses
information if int is 32 bits but st_size and EMACS_INT are larger.
Treat large device numbers like large inode numbers.
* dispnew.c (PENDING_OUTPUT_COUNT): Use __fpending if available.
* editfns.c: Include coding.h.
(emacs_strftime): Remove decl.
(emacs_strftimeu): New decl.
(emacs_memftimeu): Renamed from emacs_memftime; new arg UT.
Use emacs_strftimeu instead of emacs_strftime.
(Fformat_time_string): Convert format string using
Vlocale_coding_system, and convert result back. Synchronize time
locale before invoking lower level function. Invoke
emacs_memftimeu, passing ut, instead of emacs_memftime.
* emacs.c: Include <locale.h> if HAVE_SETLOCALE is defined.
(Vmessages_locale, Vprevious_messages_locale, Vtime_locale,
Vprevious_time_locale): New variables.
(main): Invoke setlocale early, so that initial error messages are
localized properly. But skip locale-setting if LC_ALL is "C".
Fix up locale when it's safe to do so.
(fixup_locale): Moved here from xterm.c.
(synchronize_locale, synchronize_time_locale,
synchronize_messages_locale): New functions.
(syms_of_emacs): Accommodate above changes.
* fileio.c (report_file_error): Convert strerror output according
to Vlocale_coding_system.
(Finsert_file_contents): Check for arithmetic overflow in
computations that depend on file size. Report IO errors
with emacs_strerror, not strerror.
* fns.c (Fgethash): Declare dflt parameter.
* gmalloc.c: Do not define const to nothing if HAVE_CONFIG_H
is defined; that's config.h's job.
* lisp.h (EMACS_INT, BITS_PER_EMACS_INT, EMACS_UINT): If _LP64,
default these values to long, BITS_PER_LONG, and unsigned long.
(VALBITS, MARKBIT, XINT): Do not assume 32-bit EMACS_INT.
(PNTR_COMPARISON_TYPE): Default to EMACS_UINT, not to unsigned int.
(code_convert_string_norecord, fixup_locale,
synchronize_messages_locale, synchronize_time_locale,
emacs_open, emacs_close, emacs_read, emacs_write): New decls.
All Emacs callers of open, close, read, write changed to use
emacs_open, emacs_close, emacs_read, emacs_write.
* lread.c (file_offset, file_tell): New macros. All uses of ftell
changed to file_tell.
(saved_doc_string_position, prev_saved_doc_string_position): Now
of type file_offset.
(init_lread): Do not fix locale here; fixup_locale now does this.
* m/amdahl.h, s/usg5-4.h:
(NSIG): Remove.
(NSIG_MINIMUM): New macro.
* m/cydra5.h, m/dpx2.h, m/mips.h, m/pfa50.h, m/sps7.h, m/stride.h,
m/ustation.h, s/gnu-linux.h, s/hpux.h, s/iris3-5.h, s/iris3-6.h,
s/umips.h, s/usg5-4.h:
(SIGIO): Do not undef.
(BROKEN_SIGIO): New macro.
* m/ustation.h:
(SIGTSTP): Do not undef.
(BROKEN_SIGTSTP): New macro.
* s/gnu-linux.h:
(SIGPOLL, SIGURG): Do not undef.
(BROKEN_SIGPOLL, BROKEN_SIGURG): New macros.
* s/ptx4.h:
(SIGINFO): Do not undef.
(BROKEN_SIGINFO): New macros.
* m/delta.h, s/ptx.h, s/template.h: Doc fix.
* mktime.c, strftime.c: Update to glibc 2.1.2 version, with
some Emacs-related changes merged.
* print.c (float_to_string): Prepend "-" to representation of a
NaN if the NaN is negative.
* process.c (sys_siglist): Omit if HAVE_STRSIGNAL.
(wait_reading_process_input): Use emacs_strerror, not strerror.
* process.c (status_message, sigchld_handler): Synchronize locale,
then use strsignal istead of sys_siglist.
* w32proc.c (sys_wait): Likewise.
* s/aix3-1.h, s/bsd4-1.h, s/dgux.h, s/gnu-linux.h, s/hiuxmpp.h,
s/hpux.h, s/iris3-5.h, s/iris3-6.h, s/irix3-3.h, s/osf1.h, s/rtu.h,
s/sunos4-1.h, s/unipl5-0.h, s/unipl5-2.h, s/usg5-0.h, s/usg5-2-2.h,
s/usg5-2.h, s/usg5-3.h, s/xenix.h:
(open, close, read, write, INTERRUPTIBLE_OPEN,
INTERRUPTIBLE_CLOSE, INTERRUPTIBLE_IO): Remove.
* s/sol2-5.h (_LARGEFILE_SOURCE, _FILE_OFFSET_BITS): New macros.
* sysdep.c (sys_read, sys_write, read, write, sys_close, close,
sys_open, open): Remove.
(emacs_open, emacs_close, emacs_read, emacs_write): Always define;
the old INTERRUPTIBLE_OPEN, INTERRUPTIBLE_CLOSE, and INTERRUPTIBLE_IO
macros are no longer used.
(emacs_open): Renamed from sys_open. Merge BSD4_1 version.
(emacs_close): Renamed from sys_close.
(emacs_read): Renamed from sys_read.
(emacs_write): Renamed from sys_write.
(sys_siglist): Do not declare if HAVE_STRSIGNAL.
(dup2): Do not print error on failure; the real dup2 doesn't.
(strsignal): New function, defined if !HAVE_STRSIGNAL.
* syssignal.h (SIGINFO): Undef if defined and if BROKEN_SIGINFO
is defined.
(SIGIO, SIGPOLL, SIGTSTP, SIGURG): Likewise.
(NSIG): If less than NSIG_MINIMUM, define to NSIG_MINIMUM.
(strsignal): Declare if !HAVE_STRSIGNAL.
* unexelf.c (ElfBitsW, ELFSIZE, ElfExpandBitsW): New macros.
(ElfW): Define in terms of ElfExpandBitsW.
* w32proc.c (sys_siglist): Remove decl.
* xdisp.c (decode_mode_spec): 3rd arg is int, not char, to comply
with ANSI C.
(display_string): Declare face_string_pos arg.
* xfns.c (Fx_show_tip): Declare timeout param.
* xterm.c: No need to include locale.h.
(x_alloc_lighter_color, x_setup_relief_color):
Pass arg as double, not float, for compatibility with ANSI C.
(fixup_locale): Move to emacs.c.
(x_term_init): Do not setlocale or fixup locale; the main program
does this now.
author | Paul Eggert <eggert@twinsun.com> |
---|---|
date | Tue, 19 Oct 1999 07:25:11 +0000 |
parents | c8c409640bf3 |
children | 7568310ea7d6 |
comparison
equal
deleted
inserted
replaced
26087:e0d966fb548f | 26088:b7aa6ac26872 |
---|---|
1 /* Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc. | 1 /* Convert a `struct tm' to a time_t value. |
2 Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. | |
2 Contributed by Paul Eggert (eggert@twinsun.com). | 3 Contributed by Paul Eggert (eggert@twinsun.com). |
3 | 4 |
4 NOTE: The canonical source of this file is maintained with the GNU C Library. | 5 NOTE: The canonical source of this file is maintained with the GNU C Library. |
5 Bugs can be reported to bug-glibc@gnu.org. | 6 Bugs can be reported to bug-glibc@gnu.org. |
6 | 7 |
25 | 26 |
26 #ifdef HAVE_CONFIG_H | 27 #ifdef HAVE_CONFIG_H |
27 # include <config.h> | 28 # include <config.h> |
28 #endif | 29 #endif |
29 | 30 |
30 /* Some systems need this in order to declare localtime_r properly. */ | |
31 #ifndef _REENTRANT | |
32 # define _REENTRANT 1 | |
33 #endif | |
34 | |
35 #ifdef _LIBC | 31 #ifdef _LIBC |
36 # define HAVE_LIMITS_H 1 | 32 # define HAVE_LIMITS_H 1 |
37 # define HAVE_LOCALTIME_R 1 | |
38 # define STDC_HEADERS 1 | 33 # define STDC_HEADERS 1 |
39 #endif | 34 #endif |
40 | 35 |
41 /* Assume that leap seconds are possible, unless told otherwise. | 36 /* Assume that leap seconds are possible, unless told otherwise. |
42 If the host has a `zic' command with a `-L leapsecondfilename' option, | 37 If the host has a `zic' command with a `-L leapsecondfilename' option, |
60 /* Make it work even if the system's libc has its own mktime routine. */ | 55 /* Make it work even if the system's libc has its own mktime routine. */ |
61 # define mktime my_mktime | 56 # define mktime my_mktime |
62 #endif /* DEBUG */ | 57 #endif /* DEBUG */ |
63 | 58 |
64 #ifndef __P | 59 #ifndef __P |
65 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__) | 60 # if defined __GNUC__ || (defined __STDC__ && __STDC__) |
66 # define __P(args) args | 61 # define __P(args) args |
67 # else | 62 # else |
68 # define __P(args) () | 63 # define __P(args) () |
69 # endif /* GCC. */ | 64 # endif /* GCC. */ |
70 #endif /* Not __P. */ | 65 #endif /* Not __P. */ |
112 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | 107 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, |
113 /* Leap years. */ | 108 /* Leap years. */ |
114 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | 109 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } |
115 }; | 110 }; |
116 | 111 |
117 static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *, | |
118 struct tm *)), | |
119 time_t *, struct tm *)); | |
120 static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *)); | |
121 time_t __mktime_internal __P ((struct tm *, | |
122 struct tm *(*) (const time_t *, struct tm *), | |
123 time_t *)); | |
124 | |
125 | 112 |
126 #ifdef _LIBC | 113 #ifdef _LIBC |
127 # define localtime_r __localtime_r | 114 # define my_mktime_localtime_r __localtime_r |
128 #else | 115 #else |
129 # if ! HAVE_LOCALTIME_R && ! defined localtime_r | 116 /* If we're a mktime substitute in a GNU program, then prefer |
130 /* Approximate localtime_r as best we can in its absence. */ | 117 localtime to localtime_r, since many localtime_r implementations |
131 # define localtime_r my_mktime_localtime_r | 118 are buggy. */ |
132 static struct tm *localtime_r __P ((const time_t *, struct tm *)); | |
133 static struct tm * | 119 static struct tm * |
134 localtime_r (t, tp) | 120 my_mktime_localtime_r (const time_t *t, struct tm *tp) |
135 const time_t *t; | |
136 struct tm *tp; | |
137 { | 121 { |
138 struct tm *l = localtime (t); | 122 struct tm *l = localtime (t); |
139 if (! l) | 123 if (! l) |
140 return 0; | 124 return 0; |
141 *tp = *l; | 125 *tp = *l; |
142 return tp; | 126 return tp; |
143 } | 127 } |
144 # endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ | |
145 #endif /* ! _LIBC */ | 128 #endif /* ! _LIBC */ |
146 | 129 |
147 | 130 |
148 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP), | 131 /* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP), |
149 measured in seconds, ignoring leap seconds. | 132 measured in seconds, ignoring leap seconds. |
150 YEAR uses the same numbering as TM->tm_year. | 133 YEAR uses the same numbering as TM->tm_year. |
151 All values are in range, except possibly YEAR. | 134 All values are in range, except possibly YEAR. |
152 If TP is null, return a nonzero value. | 135 If TP is null, return a nonzero value. |
153 If overflow occurs, yield the low order bits of the correct answer. */ | 136 If overflow occurs, yield the low order bits of the correct answer. */ |
154 static time_t | 137 static time_t |
155 ydhms_tm_diff (year, yday, hour, min, sec, tp) | 138 ydhms_tm_diff (int year, int yday, int hour, int min, int sec, |
156 int year, yday, hour, min, sec; | 139 const struct tm *tp) |
157 const struct tm *tp; | |
158 { | 140 { |
159 if (!tp) | 141 if (!tp) |
160 return 1; | 142 return 1; |
161 else | 143 else |
162 { | 144 { |
179 + (min - tp->tm_min)) | 161 + (min - tp->tm_min)) |
180 + (sec - tp->tm_sec)); | 162 + (sec - tp->tm_sec)); |
181 } | 163 } |
182 } | 164 } |
183 | 165 |
184 | |
185 static time_t localtime_offset; | |
186 | |
187 /* Convert *TP to a time_t value. */ | |
188 time_t | |
189 mktime (tp) | |
190 struct tm *tp; | |
191 { | |
192 #ifdef _LIBC | |
193 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the | |
194 time zone names contained in the external variable `tzname' shall | |
195 be set as if the tzset() function had been called. */ | |
196 __tzset (); | |
197 #endif | |
198 | |
199 return __mktime_internal (tp, localtime_r, &localtime_offset); | |
200 } | |
201 | |
202 /* Use CONVERT to convert *T to a broken down time in *TP. | 166 /* Use CONVERT to convert *T to a broken down time in *TP. |
203 If *T is out of range for conversion, adjust it so that | 167 If *T is out of range for conversion, adjust it so that |
204 it is the nearest in-range value and then convert that. */ | 168 it is the nearest in-range value and then convert that. */ |
205 static struct tm * | 169 static struct tm * |
206 ranged_convert (convert, t, tp) | 170 ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), |
207 struct tm *(*convert) __P ((const time_t *, struct tm *)); | 171 time_t *t, struct tm *tp) |
208 time_t *t; | |
209 struct tm *tp; | |
210 { | 172 { |
211 struct tm *r; | 173 struct tm *r; |
212 | 174 |
213 if (! (r = (*convert) (t, tp)) && *t) | 175 if (! (r = (*convert) (t, tp)) && *t) |
214 { | 176 { |
251 the monotonic and mostly-unit-linear conversion function CONVERT. | 213 the monotonic and mostly-unit-linear conversion function CONVERT. |
252 Use *OFFSET to keep track of a guess at the offset of the result, | 214 Use *OFFSET to keep track of a guess at the offset of the result, |
253 compared to what the result would be for UTC without leap seconds. | 215 compared to what the result would be for UTC without leap seconds. |
254 If *OFFSET's guess is correct, only one CONVERT call is needed. */ | 216 If *OFFSET's guess is correct, only one CONVERT call is needed. */ |
255 time_t | 217 time_t |
256 __mktime_internal (tp, convert, offset) | 218 __mktime_internal (struct tm *tp, |
257 struct tm *tp; | 219 struct tm *(*convert) (const time_t *, struct tm *), |
258 struct tm *(*convert) __P ((const time_t *, struct tm *)); | 220 time_t *offset) |
259 time_t *offset; | 221 { |
260 { | 222 time_t t, dt, t0, t1, t2; |
261 time_t t, dt, t0; | |
262 struct tm tm; | 223 struct tm tm; |
263 | 224 |
264 /* The maximum number of probes (calls to CONVERT) should be enough | 225 /* The maximum number of probes (calls to CONVERT) should be enough |
265 to handle any combinations of time zone rule changes, solar time, | 226 to handle any combinations of time zone rule changes, solar time, |
266 and leap seconds. POSIX.1 prohibits leap seconds, but some hosts | 227 leap seconds, and oscillations around a spring-forward gap. |
267 have them anyway. */ | 228 POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ |
268 int remaining_probes = 4; | 229 int remaining_probes = 6; |
269 | 230 |
270 /* Time requested. Copy it in case CONVERT modifies *TP; this can | 231 /* Time requested. Copy it in case CONVERT modifies *TP; this can |
271 occur if TP is localtime's returned value and CONVERT is localtime. */ | 232 occur if TP is localtime's returned value and CONVERT is localtime. */ |
272 int sec = tp->tm_sec; | 233 int sec = tp->tm_sec; |
273 int min = tp->tm_min; | 234 int min = tp->tm_min; |
309 | 270 |
310 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE; | 271 tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE; |
311 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | 272 tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0; |
312 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); | 273 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); |
313 | 274 |
314 for (t = t0 + *offset; | 275 for (t = t1 = t2 = t0 + *offset; |
315 (dt = ydhms_tm_diff (year, yday, hour, min, sec, | 276 (dt = ydhms_tm_diff (year, yday, hour, min, sec, |
316 ranged_convert (convert, &t, &tm))); | 277 ranged_convert (convert, &t, &tm))); |
317 t += dt) | 278 t1 = t2, t2 = t, t += dt) |
318 if (--remaining_probes == 0) | 279 if (t == t1 && t != t2 |
280 && (isdst < 0 || tm.tm_isdst < 0 | |
281 || (isdst != 0) != (tm.tm_isdst != 0))) | |
282 /* We can't possibly find a match, as we are oscillating | |
283 between two values. The requested time probably falls | |
284 within a spring-forward gap of size DT. Follow the common | |
285 practice in this case, which is to return a time that is DT | |
286 away from the requested time, preferring a time whose | |
287 tm_isdst differs from the requested value. In practice, | |
288 this is more useful than returning -1. */ | |
289 break; | |
290 else if (--remaining_probes == 0) | |
319 return -1; | 291 return -1; |
320 | 292 |
321 /* Check whether tm.tm_isdst has the requested value, if any. */ | 293 /* If we have a match, check whether tm.tm_isdst has the requested |
322 if (0 <= isdst && 0 <= tm.tm_isdst) | 294 value, if any. */ |
323 { | 295 if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst) |
324 int dst_diff = (isdst != 0) - (tm.tm_isdst != 0); | 296 { |
325 if (dst_diff) | 297 /* tm.tm_isdst has the wrong value. Look for a neighboring |
298 time with the right value, and use its UTC offset. | |
299 Heuristic: probe the previous three calendar quarters (approximately), | |
300 looking for the desired isdst. This isn't perfect, | |
301 but it's good enough in practice. */ | |
302 int quarter = 7889238; /* seconds per average 1/4 Gregorian year */ | |
303 int i; | |
304 | |
305 /* If we're too close to the time_t limit, look in future quarters. */ | |
306 if (t < TIME_T_MIN + 3 * quarter) | |
307 quarter = -quarter; | |
308 | |
309 for (i = 1; i <= 3; i++) | |
326 { | 310 { |
327 /* Move two hours in the direction indicated by the disagreement, | 311 time_t ot = t - i * quarter; |
328 probe some more, and switch to a new time if found. | 312 struct tm otm; |
329 The largest known fallback due to daylight savings is two hours: | 313 ranged_convert (convert, &ot, &otm); |
330 once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */ | 314 if (otm.tm_isdst == isdst) |
331 time_t ot = t - 2 * 60 * 60 * dst_diff; | |
332 while (--remaining_probes != 0) | |
333 { | 315 { |
334 struct tm otm; | 316 /* We found the desired tm_isdst. |
335 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec, | 317 Extrapolate back to the desired time. */ |
336 ranged_convert (convert, &ot, &otm)))) | 318 t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm); |
337 { | 319 ranged_convert (convert, &t, &tm); |
338 t = ot; | 320 break; |
339 tm = otm; | |
340 break; | |
341 } | |
342 if ((ot += dt) == t) | |
343 break; /* Avoid a redundant probe. */ | |
344 } | 321 } |
345 } | 322 } |
346 } | 323 } |
347 | 324 |
348 *offset = t - t0; | 325 *offset = t - t0; |
382 return -1; | 359 return -1; |
383 } | 360 } |
384 | 361 |
385 *tp = tm; | 362 *tp = tm; |
386 return t; | 363 return t; |
364 } | |
365 | |
366 | |
367 static time_t localtime_offset; | |
368 | |
369 /* Convert *TP to a time_t value. */ | |
370 time_t | |
371 mktime (tp) | |
372 struct tm *tp; | |
373 { | |
374 #ifdef _LIBC | |
375 /* POSIX.1 8.1.1 requires that whenever mktime() is called, the | |
376 time zone names contained in the external variable `tzname' shall | |
377 be set as if the tzset() function had been called. */ | |
378 __tzset (); | |
379 #endif | |
380 | |
381 return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset); | |
387 } | 382 } |
388 | 383 |
389 #ifdef weak_alias | 384 #ifdef weak_alias |
390 weak_alias (mktime, timelocal) | 385 weak_alias (mktime, timelocal) |
391 #endif | 386 #endif |
528 | 523 |
529 #endif /* DEBUG */ | 524 #endif /* DEBUG */ |
530 | 525 |
531 /* | 526 /* |
532 Local Variables: | 527 Local Variables: |
533 compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime" | 528 compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime" |
534 End: | 529 End: |
535 */ | 530 */ |