Mercurial > emacs
diff src/strftime.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 | 0800a4f84757 |
children | 0a4e16e5eb52 |
line wrap: on
line diff
--- a/src/strftime.c Tue Oct 19 07:21:16 1999 +0000 +++ b/src/strftime.c Tue Oct 19 07:25:11 1999 +0000 @@ -1,5 +1,4 @@ /* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc. - NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. @@ -14,19 +13,13 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif -/* Some hosts need this in order to declare localtime_r properly. */ -#ifndef _REENTRANT -# define _REENTRANT 1 -#endif - #ifdef _LIBC # define HAVE_LIMITS_H 1 # define HAVE_MBLEN 1 @@ -136,7 +129,7 @@ add one for integer division truncation; add one more for a minus sign if t is signed. */ #define INT_STRLEN_BOUND(t) \ - ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t)) + ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t)) #define TM_YEAR_BASE 1900 @@ -149,19 +142,20 @@ #ifdef _LIBC -# define gmtime_r __gmtime_r -# define localtime_r __localtime_r +# define my_strftime_gmtime_r __gmtime_r +# define my_strftime_localtime_r __localtime_r # define tzname __tzname # define tzset __tzset #else -# if ! HAVE_LOCALTIME_R -# if ! HAVE_TM_GMTOFF -/* Approximate gmtime_r as best we can in its absence. */ -# undef gmtime_r -# define gmtime_r my_gmtime_r -static struct tm *gmtime_r __P ((const time_t *, struct tm *)); + +/* If we're a strftime substitute in a GNU program, then prefer gmtime + to gmtime_r, since many gmtime_r implementations are buggy. + Similarly for localtime_r. */ + +# if ! HAVE_TM_GMTOFF +static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *)); static struct tm * -gmtime_r (t, tp) +my_strftime_gmtime_r (t, tp) const time_t *t; struct tm *tp; { @@ -171,14 +165,11 @@ *tp = *l; return tp; } -# endif /* ! HAVE_TM_GMTOFF */ +# endif /* ! HAVE_TM_GMTOFF */ -/* Approximate localtime_r as best we can in its absence. */ -# undef localtime_r -# define localtime_r my_ftime_localtime_r -static struct tm *localtime_r __P ((const time_t *, struct tm *)); +static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *)); static struct tm * -localtime_r (t, tp) +my_strftime_localtime_r (t, tp) const time_t *t; struct tm *tp; { @@ -188,7 +179,6 @@ *tp = *l; return tp; } -# endif /* ! HAVE_LOCALTIME_R */ #endif /* ! defined _LIBC */ @@ -376,30 +366,38 @@ #ifdef emacs -# define my_strftime emacs_strftime +# define my_strftime emacs_strftimeu +# define ut_argument , ut +# define ut_argument_spec int ut; +# define ut_argument_spec_iso , int ut #else # define my_strftime strftime +# define ut_argument +# define ut_argument_spec +# define ut_argument_spec_iso +/* We don't have this information in general. */ +# define ut 0 #endif #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime. Work around this bug by copying *tp before it might be munged. */ size_t _strftime_copytm __P ((char *, size_t, const char *, - const struct tm *)); + const struct tm * ut_argument_spec_iso)); size_t - my_strftime (s, maxsize, format, tp) + my_strftime (s, maxsize, format, tp ut_argument) char *s; size_t maxsize; const char *format; const struct tm *tp; + ut_argument_spec { struct tm tmcopy; tmcopy = *tp; - return _strftime_copytm (s, maxsize, format, &tmcopy); + return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument); } # undef my_strftime -# define my_strftime(S, Maxsize, Format, Tp) \ - _strftime_copytm (S, Maxsize, Format, Tp) +# define my_strftime _strftime_copytm #endif @@ -410,41 +408,44 @@ anywhere, so to determine how many characters would be written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */ size_t -my_strftime (s, maxsize, format, tp) +my_strftime (s, maxsize, format, tp ut_argument) char *s; size_t maxsize; const char *format; const struct tm *tp; + ut_argument_spec { int hour12 = tp->tm_hour; #ifdef _NL_CURRENT - const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday); - const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday); - const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon); - const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon); - const char *const ampm = _NL_CURRENT (LC_TIME, - hour12 > 11 ? PM_STR : AM_STR); - size_t aw_len = strlen (a_wkday); - size_t am_len = strlen (a_month); - size_t ap_len = strlen (ampm); + /* We cannot make the following values variables since we must delay + the evaluation of these values until really needed since some + expressions might not be valid in every situation. The `struct tm' + might be generated by a strptime() call that initialized + only a few elements. Dereference the pointers only if the format + requires this. Then it is ok to fail if the pointers are invalid. */ +# define a_wkday _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday) +# define f_wkday _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday) +# define a_month _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon) +# define f_month _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon) +# define ampm _NL_CURRENT (LC_TIME, tp->tm_hour > 11 ? PM_STR : AM_STR) + +# define aw_len strlen (a_wkday) +# define am_len strlen (a_month) +# define ap_len strlen (ampm) #else # if !HAVE_STRFTIME - const char *const f_wkday = weekday_name[tp->tm_wday]; - const char *const f_month = month_name[tp->tm_mon]; - const char *const a_wkday = f_wkday; - const char *const a_month = f_month; - const char *const ampm = "AMPM" + 2 * (hour12 > 11); +# define f_wkday (weekday_name[tp->tm_wday]) +# define f_month (month_name[tp->tm_mon]) +# define a_wkday f_wkday +# define a_month f_month +# define ampm ("AMPM" + 2 * (tp->tm_hour > 11)) + size_t aw_len = 3; size_t am_len = 3; size_t ap_len = 2; # endif #endif -#if defined _NL_CURRENT || !HAVE_STRFTIME - size_t wkday_len = strlen (f_wkday); - size_t month_len = strlen (f_month); -#endif const char *zone; - size_t zonelen; size_t i = 0; char *p = s; const char *f; @@ -460,25 +461,27 @@ zone = (const char *) tp->tm_zone; #endif #if HAVE_TZNAME - /* POSIX.1 8.1.1 requires that whenever strftime() is called, the - time zone names contained in the external variable `tzname' shall - be set as if the tzset() function had been called. */ + if (ut) + { + if (! (zone && *zone)) + zone = "GMT"; + } + else + { + /* POSIX.1 8.1.1 requires that whenever strftime() is called, the + time zone names contained in the external variable `tzname' shall + be set as if the tzset() function had been called. */ # if HAVE_TZSET - tzset (); + tzset (); # endif - - if (!(zone && *zone) && tp->tm_isdst >= 0) - zone = tzname[tp->tm_isdst]; + } #endif - if (! zone) - zone = ""; /* POSIX.2 requires the empty string here. */ - - zonelen = strlen (zone); if (hour12 > 12) hour12 -= 12; else - if (hour12 == 0) hour12 = 12; + if (hour12 == 0) + hour12 = 12; for (f = format; *f != '\0'; ++f) { @@ -544,7 +547,13 @@ if (bytes == 0) break; - if (bytes == (size_t) -2 || bytes == (size_t) -1) + if (bytes == (size_t) -2) + { + len += strlen (f + len); + break; + } + + if (bytes == (size_t) -1) { len++; break; @@ -555,6 +564,7 @@ while (! mbsinit (&mbstate)); cpy (len, f); + f += len - 1; continue; } } @@ -664,7 +674,7 @@ to_lowcase = 0; } #if defined _NL_CURRENT || !HAVE_STRFTIME - cpy (wkday_len, f_wkday); + cpy (strlen (f_wkday), f_wkday); break; #else goto underlying_strftime; @@ -690,7 +700,7 @@ to_lowcase = 0; } #if defined _NL_CURRENT || !HAVE_STRFTIME - cpy (month_len, f_month); + cpy (strlen (f_month), f_month); break; #else goto underlying_strftime; @@ -714,10 +724,9 @@ subformat: { char *old_start = p; - size_t len = my_strftime (NULL, maxsize - i, subfmt, tp); - if (len == 0 && *subfmt) - return 0; - add (len, my_strftime (p, maxsize - i, subfmt, tp)); + size_t len = my_strftime (NULL, (size_t) -1, subfmt, + tp ut_argument); + add (len, my_strftime (p, maxsize - i, subfmt, tp ut_argument)); if (to_uppcase) while (old_start < p) @@ -742,7 +751,6 @@ *u++ = modifier; *u++ = format_char; *u = '\0'; - ubuf[0] = '\1'; len = strftime (ubuf, sizeof ubuf, ufmt, tp); if (len == 0 && ubuf[0] != '\0') return 0; @@ -1033,7 +1041,6 @@ add (1, *p = '\t'); break; - case 'f': case 'u': /* POSIX.2 extension. */ DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1); @@ -1142,7 +1149,16 @@ to_uppcase = 0; to_lowcase = 1; } - cpy (zonelen, zone); + +#if HAVE_TZNAME + /* The tzset() call might have changed the value. */ + if (!(zone && *zone) && tp->tm_isdst >= 0) + zone = tzname[tp->tm_isdst]; +#endif + if (! zone) + zone = ""; /* POSIX.2 requires the empty string here. */ + + cpy (strlen (zone), zone); break; case 'z': /* GNU extension. */ @@ -1154,34 +1170,39 @@ #if HAVE_TM_GMTOFF diff = tp->tm_gmtoff; #else - struct tm gtm; - struct tm ltm; - time_t lt; - - ltm = *tp; - lt = mktime (<m); + if (ut) + diff = 0; + else + { + struct tm gtm; + struct tm ltm; + time_t lt; - if (lt == (time_t) -1) - { - /* mktime returns -1 for errors, but -1 is also a - valid time_t value. Check whether an error really - occurred. */ - struct tm tm; + ltm = *tp; + lt = mktime (<m); - if (! localtime_r (<, &tm) - || ((ltm.tm_sec ^ tm.tm_sec) - | (ltm.tm_min ^ tm.tm_min) - | (ltm.tm_hour ^ tm.tm_hour) - | (ltm.tm_mday ^ tm.tm_mday) - | (ltm.tm_mon ^ tm.tm_mon) - | (ltm.tm_year ^ tm.tm_year))) + if (lt == (time_t) -1) + { + /* mktime returns -1 for errors, but -1 is also a + valid time_t value. Check whether an error really + occurred. */ + struct tm tm; + + if (! my_strftime_localtime_r (<, &tm) + || ((ltm.tm_sec ^ tm.tm_sec) + | (ltm.tm_min ^ tm.tm_min) + | (ltm.tm_hour ^ tm.tm_hour) + | (ltm.tm_mday ^ tm.tm_mday) + | (ltm.tm_mon ^ tm.tm_mon) + | (ltm.tm_year ^ tm.tm_year))) + break; + } + + if (! my_strftime_gmtime_r (<, >m)) break; + + diff = tm_diff (<m, >m); } - - if (! gmtime_r (<, >m)) - break; - - diff = tm_diff (<m, >m); #endif if (diff < 0) @@ -1214,7 +1235,7 @@ } } - if (p) + if (p && maxsize != 0) *p = '\0'; return i; }