home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / strftime / part01 < prev    next >
Encoding:
Text File  |  1993-01-16  |  23.3 KB  |  956 lines

  1. Newsgroups: comp.sources.unix
  2. From: arnold@skeeve.ATL.GA.US (Arnold Robbins)
  3. Subject: v26i085: strftime - convert date and time to string (includes "date"), Part01/01
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: arnold@skeeve.ATL.GA.US (Arnold Robbins)
  8. Posting-Number: Volume 26, Issue 85
  9. Archive-Name: strftime/part01
  10.  
  11. At the urging of Geoff Clare, I have made strftime posix compliant.  The new
  12. code can be ifdef'ed out if you know your application will never change the
  13. TZ environment variable.
  14.  
  15. I have also added range checking to everything, as a bit of bullet-proofing.
  16. Compiling this code with gcc gives smaller faster versions than plain old
  17. cc, but who's suprised by that? :-)
  18.  
  19. This can supersede the recent posting.
  20.  
  21. Arnold Robbins -- The Basement Computer        | Laundry increases
  22. Internet: arnold@skeeve.ATL.GA.US        | exponentially in the
  23. UUCP:    { gatech, emory }!skeeve!arnold        | number of children.
  24. Bitnet:    Forget it. Get on a real network.    |    -- Miriam Robbins
  25.  
  26. #! /bin/sh
  27. # This is a shell archive.  Remove anything before this line, then unpack
  28. # it by saving it into a file and typing "sh file".  To overwrite existing
  29. # files, type "sh file -c".  You can also feed this as standard input via
  30. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  31. # will see the following message at the end:
  32. #        "End of shell archive."
  33. # Contents:  README Makefile date.1 date.c strftime.3 strftime.c
  34. # Wrapped by vixie@cognition.pa.dec.com on Sun Jan 17 20:36:57 1993
  35. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  36. if test -f 'README' -a "${1}" != "-c" ; then 
  37.   echo shar: Will not clobber existing file \"'README'\"
  38. else
  39. echo shar: Extracting \"'README'\" \(457 characters\)
  40. sed "s/^X//" >'README' <<'END_OF_FILE'
  41. Mon Mar 23 12:00:31 EST 1992
  42. X
  43. This package implements the Posix 1003.2 Draft 11 date command, as a
  44. wrapper around an extended version of the ANSI strftime(3) library
  45. routine.  Everything in it is public domain.
  46. X
  47. Arnold Robbins -- The Basement Computer        | Laundry increases
  48. Internet: arnold@skeeve.ATL.GA.US        | exponentially in the
  49. UUCP:    { gatech, emory }!skeeve!arnold        | number of children.
  50. Bitnet:    Forget it. Get on a real network.    |    -- Miriam Robbins
  51. END_OF_FILE
  52. if test 457 -ne `wc -c <'README'`; then
  53.     echo shar: \"'README'\" unpacked with wrong size!
  54. fi
  55. # end of 'README'
  56. fi
  57. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  58.   echo shar: Will not clobber existing file \"'Makefile'\"
  59. else
  60. echo shar: Extracting \"'Makefile'\" \(195 characters\)
  61. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  62. X# Makefile for PD date and strftime
  63. X
  64. SRCS= date.c strftime.c
  65. OBJS= date.o strftime.o
  66. DOCS= date.1 strftime.3
  67. X
  68. date: $(OBJS)
  69. X    $(CC) $(CFLAGS) $(OBJS) -o $@
  70. X
  71. date.o: date.c
  72. X
  73. strftime.o: strftime.c
  74. END_OF_FILE
  75. if test 195 -ne `wc -c <'Makefile'`; then
  76.     echo shar: \"'Makefile'\" unpacked with wrong size!
  77. fi
  78. # end of 'Makefile'
  79. fi
  80. if test -f 'date.1' -a "${1}" != "-c" ; then 
  81.   echo shar: Will not clobber existing file \"'date.1'\"
  82. else
  83. echo shar: Extracting \"'date.1'\" \(1342 characters\)
  84. sed "s/^X//" >'date.1' <<'END_OF_FILE'
  85. X.TH DATE 1
  86. X.SH NAME
  87. date \- write the date and time
  88. X.SH SYNOPSIS
  89. X.B date
  90. X[
  91. X.B \-u
  92. X] [
  93. X.RI + format
  94. X]
  95. X.SH DESCRIPTION
  96. X.I Date
  97. writes the current date and time to the standard output.
  98. It is intended to be compliant with draft 11 of the Posix
  99. X1003.2 Command Language and Utilities standard.
  100. Therefore, it is purposely
  101. X.I not
  102. usable by the super-user for setting the system time.
  103. X.LP
  104. X.I Date
  105. accepts one option:
  106. X.TP
  107. X.B \-u
  108. Perform operations as if the
  109. X.B TZ
  110. environment variable was set to
  111. X.BR GMT0 .
  112. X.LP
  113. If an argument to 
  114. X.I date
  115. is given that begins with a ``+'',
  116. then the output is controlled by the contents of the rest of
  117. the string.  Normal text is output unmodified, while field descriptors
  118. in the format string are substituted for.
  119. X.LP
  120. The
  121. X.I date
  122. program is essentially a wrapper around
  123. X.IR strftime (3);
  124. see there for a description of the available formatting options.
  125. X.LP
  126. If no format string is given, or if it does not begin with a ``+'',
  127. then the default format of \fB"%a %b %e %H:%M:%S %Z %Y"\fR will
  128. be used.  This produces the traditional style of output, such as
  129. X``Sun Mar 17 10:32:47 EST 1991''.
  130. X.SH SEE ALSO
  131. time(2), strftime(3), localtime(3)
  132. X.SH BUGS
  133. This version only works for the POSIX locale.
  134. X.SH AUTHOR
  135. X.nf
  136. Arnold Robbins
  137. X.sp
  138. INTERNET: arnold@skeeve.atl.ga.us
  139. UUCP:     emory!skeeve!arnold
  140. Phone:    +1 404 248 9324
  141. X.fi
  142. END_OF_FILE
  143. if test 1342 -ne `wc -c <'date.1'`; then
  144.     echo shar: \"'date.1'\" unpacked with wrong size!
  145. fi
  146. # end of 'date.1'
  147. fi
  148. if test -f 'date.c' -a "${1}" != "-c" ; then 
  149.   echo shar: Will not clobber existing file \"'date.c'\"
  150. else
  151. echo shar: Extracting \"'date.c'\" \(1044 characters\)
  152. sed "s/^X//" >'date.c' <<'END_OF_FILE'
  153. X/*
  154. X * date.c
  155. X *
  156. X * Public domain implementation of Posix 1003.2 Draft 11
  157. X * date command.  Lets strftime() do the dirty work.
  158. X */
  159. X
  160. X#include <stdio.h>
  161. X#include <sys/types.h>
  162. X#include <time.h>
  163. X
  164. extern char *malloc();
  165. extern size_t strftime();
  166. extern int getopt();
  167. extern int optind;
  168. X
  169. int
  170. main(argc, argv)
  171. int argc;
  172. char **argv;
  173. X{
  174. X    time_t clock;
  175. X    struct tm *now;
  176. X    int c, size, ret;
  177. X    char *defhow = "%a %b %e %H:%M:%S %Z %Y";
  178. X    char *howto = defhow;
  179. X    char *buf;
  180. X
  181. X    while ((c = getopt(argc, argv, "u")) != -1)
  182. X        switch (c) {
  183. X        case 'u':
  184. X            putenv("TZ=GMT0");
  185. X            break;
  186. X        default:
  187. X            fprintf(stderr, "usage: %s [-u] [+format_str]\n",
  188. X                argv[0]);
  189. X            exit(1);
  190. X        }
  191. X
  192. X    time(& clock);
  193. X    now = localtime(& clock);
  194. X
  195. X    if (optind < argc && argv[optind][0] == '+')
  196. X        howto = & argv[optind][1];
  197. X
  198. X    size = strlen(howto) * 10;
  199. X    if ((buf = malloc(size)) == NULL) {
  200. X        perror("not enough memory");
  201. X        exit(1);
  202. X    }
  203. X
  204. X    ret = strftime(buf, size, howto, now);
  205. X    if (ret != 0)
  206. X        printf("%s\n", buf);
  207. X    else {
  208. X        fprintf(stderr, "conversion failed\n");
  209. X        exit(1);
  210. X    }
  211. X    
  212. X    exit(0);
  213. X}
  214. END_OF_FILE
  215. if test 1044 -ne `wc -c <'date.c'`; then
  216.     echo shar: \"'date.c'\" unpacked with wrong size!
  217. fi
  218. # end of 'date.c'
  219. fi
  220. if test -f 'strftime.3' -a "${1}" != "-c" ; then 
  221.   echo shar: Will not clobber existing file \"'strftime.3'\"
  222. else
  223. echo shar: Extracting \"'strftime.3'\" \(6033 characters\)
  224. sed "s/^X//" >'strftime.3' <<'END_OF_FILE'
  225. X.TH STRFTIME 3
  226. X.SH NAME
  227. strftime \- generate formatted time information
  228. X.SH SYNOPSIS
  229. X.ft B
  230. X.nf
  231. X#include <sys/types.h>
  232. X#include <time.h>
  233. X.sp
  234. size_t strftime(char *s, size_t maxsize, const char *format,
  235. X    const struct tm *timeptr);
  236. X.SH DESCRIPTION
  237. The following description is transcribed verbatim from the December 7, 1988
  238. draft standard for ANSI C.
  239. This draft is essentially identical in technical content
  240. to the final version of the standard.
  241. X.LP
  242. The
  243. X.B strftime
  244. function places characters into the array pointed to by
  245. X.B s
  246. as controlled by the string pointed to by
  247. X.BR format .
  248. The format shall be a multibyte character sequence, beginning and ending in
  249. its initial shift state.
  250. The
  251. X.B format
  252. string consists of zero or more conversion specifiers and ordinary
  253. multibyte characters.  A conversion specifier consists of a
  254. X.B %
  255. character followed by a character that determines the behavior of the
  256. conversion specifier.
  257. All ordinary multibyte characters (including the terminating null
  258. character) are copied unchanged into the array.
  259. If copying takes place between objects that overlap the behavior is undefined.
  260. No more than
  261. X.B maxsize
  262. characters are placed into the array.
  263. XEach conversion specifier is replaced by appropriate characters as described
  264. in the following list.
  265. The appropriate characters are determined by the
  266. X.B LC_TIME
  267. category of the current locale and by the values contained in the
  268. structure pointed to by
  269. X.BR timeptr .
  270. X.TP
  271. X.B %a
  272. is replaced by the locale's abbreviated weekday name.
  273. X.TP
  274. X.B %A
  275. is replaced by the locale's full weekday name.
  276. X.TP
  277. X.B %b
  278. is replaced by the locale's abbreviated month name.
  279. X.TP
  280. X.B %B
  281. is replaced by the locale's full month name.
  282. X.TP
  283. X.B %c
  284. is replaced by the locale's appropriate date and time representation.
  285. X.TP
  286. X.B %d
  287. is replaced by the day of the month as a decimal number
  288. X.RB ( 01 - 31 ).
  289. X.TP
  290. X.B %H
  291. is replaced by the hour (24-hour clock) as a decimal number
  292. X.RB ( 00 - 23 ).
  293. X.TP
  294. X.B %I
  295. is replaced by the hour (12-hour clock) as a decimal number
  296. X.RB ( 01 - 12 ).
  297. X.TP
  298. X.B %j
  299. is replaced by the day of the year as a decimal number
  300. X.RB ( 001 - 366 ).
  301. X.TP
  302. X.B %m
  303. is replaced by the month as a decimal number
  304. X.RB ( 01 - 12 ).
  305. X.TP
  306. X.B %M
  307. is replaced by the minute as a decimal number
  308. X.RB ( 00 - 59 ).
  309. X.TP
  310. X.B %p
  311. is replaced by the locale's equivalent of the AM/PM designations associated
  312. with a 12-hour clock.
  313. X.TP
  314. X.B %S
  315. is replaced by the second as a decimal number
  316. X.RB ( 00 - 61 ).
  317. X.TP
  318. X.B %U
  319. is replaced by the week number of the year (the first Sunday as the first
  320. day of week 1) as a decimal number
  321. X.RB ( 00 - 53 ).
  322. X.TP
  323. X.B %w
  324. is replaced by the weekday as a decimal number
  325. X.RB [ "0 " (Sunday)- 6 ].
  326. X.TP
  327. X.B %W
  328. is replaced by the week number of the year (the first Monday as the first
  329. day of week 1) as a decimal number
  330. X.RB ( 00 - 53 ).
  331. X.TP
  332. X.B %x
  333. is replaced by the locale's appropriate date representation.
  334. X.TP
  335. X.B %X
  336. is replaced by the locale's appropriate time representation.
  337. X.TP
  338. X.B %y
  339. is replaced by the year without century as a decimal number
  340. X.RB ( 00 - 99 ).
  341. X.TP
  342. X.B %Y
  343. is replaced by the year with century as a decimal number.
  344. X.TP
  345. X.B %Z
  346. is replaced by the time zone name or abbreviation, or by no characters if
  347. no time zone is determinable.
  348. X.TP
  349. X.B %%
  350. is replaced by
  351. X.BR % .
  352. X.LP
  353. If a conversion specifier is not one of the above, the behavior is
  354. undefined.
  355. X.SH RETURNS
  356. If the total number of resulting characters including the terminating null
  357. character is not more than
  358. X.BR maxsize ,
  359. the
  360. X.B strftime
  361. function returns the number of characters placed into the array pointed to
  362. by
  363. X.B s
  364. not including the terminating null character.
  365. Otherwise, zero is returned and the contents of the array are indeterminate.
  366. X.SH NON-ANSI EXTENSIONS
  367. If
  368. X.B SYSV_EXT
  369. is defined when the routine is compiled, then the following additional
  370. conversions will be available.
  371. These are borrowed from the System V
  372. X.IR cftime (3)
  373. and
  374. X.IR ascftime (3)
  375. routines.
  376. X.TP
  377. X.B %D
  378. is equivalent to specifying
  379. X.BR %m/%d/%y .
  380. X.TP
  381. X.B %e
  382. is replaced by the day of the month,
  383. padded with a blank if it is only one digit.
  384. X.TP
  385. X.B %h
  386. is equivalent to
  387. X.BR %b ,
  388. above.
  389. X.TP
  390. X.B %n
  391. is replaced with a newline character (\s-1ASCII LF\s+1).
  392. X.TP
  393. X.B %r
  394. is equivalent to specifying
  395. X.BR "%I:%M:%S %p" .
  396. X.TP
  397. X.B %R
  398. is equivalent to specifying
  399. X.BR %H:%M .
  400. X.TP
  401. X.B %T
  402. is equivalent to specifying
  403. X.BR %H:%M:%S .
  404. X.TP
  405. X.B %t
  406. is replaced with a \s-1TAB\s+1 character.
  407. X.SH POSIX 1003.2 EXTENSIONS
  408. If
  409. X.B POSIX2_DATE
  410. is defined, then all of the conversions available with
  411. X.B SYSV_EXT
  412. are available, as well as the
  413. following additional conversions:
  414. X.TP
  415. X.B %C
  416. The century, as a number between 00 and 99.
  417. X.LP
  418. In additon, the alternate representations
  419. X.BR %Ec ,
  420. X.BR %EC ,
  421. X.BR %Ex ,
  422. X.BR %Ey ,
  423. X.BR %EY ,
  424. X.BR %Od ,
  425. X.BR %Oe ,
  426. X.BR %OH ,
  427. X.BR %OI ,
  428. X.BR %Om ,
  429. X.BR %OM ,
  430. X.BR %OS ,
  431. X.BR %OU ,
  432. X.BR %Ow ,
  433. X.BR %OW ,
  434. and
  435. X.B %Oy
  436. are recognized, but their normal representations are used.
  437. X.SH VMS EXTENSIONS
  438. If
  439. X.B VMS_EXT
  440. is defined, then the following additional conversion is available:
  441. X.TP
  442. X.B %V
  443. The date in VMS format (e.g. 20-JUN-1991).
  444. X.SH SEE ALSO
  445. time(2), ctime(3), localtime(3)
  446. X.SH BUGS
  447. This version does not handle multibyte characters or pay attention to the
  448. setting of the
  449. X.B LC_TIME
  450. environment variable.
  451. X.LP
  452. It is not clear what is ``appropriate'' for the C locale; the values
  453. returned are a best guess on the author's part.
  454. X.SH CAVEATS
  455. This implementation calls
  456. X.IR tzset (3)
  457. exactly once.  If the
  458. X.B TZ
  459. environment variable is changed after
  460. X.B strftime
  461. has been called, then
  462. X.IR tzset (3)
  463. must be called again, explicitly, in order for the
  464. correct timezone information to be available.
  465. This behavior is not POSIX-conformant.  To force POSIX semantics,
  466. define
  467. X.B POSIX_SEMANTICS
  468. when compiling.
  469. X.SH AUTHOR
  470. X.nf
  471. Arnold Robbins
  472. X.sp
  473. INTERNET: arnold@skeeve.atl.ga.us
  474. UUCP:     emory!skeeve!arnold
  475. Phone:    +1 404 248 9324
  476. X.fi
  477. X.SH ACKNOWLEDGEMENTS
  478. Thanks to Geoff Clare <gwc@root.co.uk> for helping debug earlier
  479. versions of this routine, and for advice about POSIX semantics.
  480. Additional thanks to Arthur David Olsen <ado@elsie.nci.nih.gov>
  481. for some code improvements.
  482. END_OF_FILE
  483. if test 6033 -ne `wc -c <'strftime.3'`; then
  484.     echo shar: \"'strftime.3'\" unpacked with wrong size!
  485. fi
  486. # end of 'strftime.3'
  487. fi
  488. if test -f 'strftime.c' -a "${1}" != "-c" ; then 
  489.   echo shar: Will not clobber existing file \"'strftime.c'\"
  490. else
  491. echo shar: Extracting \"'strftime.c'\" \(10430 characters\)
  492. sed "s/^X//" >'strftime.c' <<'END_OF_FILE'
  493. X/*
  494. X * strftime.c
  495. X *
  496. X * Public-domain relatively quick-and-dirty implemenation of
  497. X * ANSI library routine for System V Unix systems.
  498. X *
  499. X * It's written in old-style C for maximal portability.
  500. X * However, since I'm used to prototypes, I've included them too.
  501. X *
  502. X * If you want stuff in the System V ascftime routine, add the SYSV_EXT define.
  503. X * For stuff needed to implement the P1003.2 date command, add POSIX2_DATE.
  504. X * For complete POSIX semantics, add POSIX_SEMANTICS.
  505. X *
  506. X * The code for %c, %x, and %X is my best guess as to what's "appropriate".
  507. X * This version ignores LOCALE information.
  508. X * It also doesn't worry about multi-byte characters.
  509. X * So there.
  510. X *
  511. X * Arnold Robbins
  512. X * January, February, March, 1991
  513. X * Updated March 1992
  514. X *
  515. X * Fixes from ado@elsie.nci.nih.gov
  516. X * February 1991
  517. X */
  518. X
  519. X#include <stdio.h>
  520. X#include <ctype.h>
  521. X#include <string.h>
  522. X#include <time.h>
  523. X#include <sys/types.h>
  524. X
  525. X#ifndef __STDC__
  526. X#define const    /**/
  527. X
  528. extern void *malloc();
  529. extern void *realloc();
  530. extern void tzset();
  531. extern char *strchr();
  532. extern char *getenv();
  533. static int weeknumber();
  534. X#else
  535. extern void *malloc(unsigned count);
  536. extern void *realloc(void *ptr, unsigned count);
  537. extern void tzset(void);
  538. extern char *strchr(const char *str, int ch);
  539. extern char *getenv(const char *v);
  540. static int weeknumber(const struct tm *timeptr, int firstweekday);
  541. X#endif
  542. X
  543. X#ifdef __GNUC__
  544. X#define inline    __inline__
  545. X#else
  546. X#define inline    /**/
  547. X#endif
  548. X
  549. X#define range(low, item, hi)    max(low, min(item, hi))
  550. X
  551. extern char *tzname[2];
  552. extern int daylight;
  553. X
  554. X#define SYSV_EXT    1    /* stuff in System V ascftime routine */
  555. X#define POSIX2_DATE    1    /* stuff in Posix 1003.2 date command */
  556. X#define VMS_EXT        1    /* include %V for VMS date format */
  557. X#define POSIX_SEMANTICS 1    /* call tzset() if TZ changes */
  558. X
  559. X#if defined(POSIX2_DATE) && ! defined(SYSV_EXT)
  560. X#define SYSV_EXT    1
  561. X#endif
  562. X
  563. X/* min --- return minimum of two numbers */
  564. X
  565. X#ifndef __STDC__
  566. static inline int
  567. min(a, b)
  568. int a, b;
  569. X#else
  570. static inline int
  571. min(int a, int b)
  572. X#endif
  573. X{
  574. X    return (a < b ? a : b);
  575. X}
  576. X
  577. X/* max --- return maximum of two numbers */
  578. X
  579. X#ifndef __STDC__
  580. static inline int
  581. max(a, b)
  582. int a, b;
  583. X#else
  584. static inline int
  585. max(int a, int b)
  586. X#endif
  587. X{
  588. X    return (a > b ? a : b);
  589. X}
  590. X
  591. X/* strftime --- produce formatted time */
  592. X
  593. X#ifndef __STDC__
  594. size_t
  595. strftime(s, maxsize, format, timeptr)
  596. char *s;
  597. size_t maxsize;
  598. const char *format;
  599. const struct tm *timeptr;
  600. X#else
  601. size_t
  602. strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
  603. X#endif
  604. X{
  605. X    char *endp = s + maxsize;
  606. X    char *start = s;
  607. X    char tbuf[100];
  608. X    int i;
  609. X    static short first = 1;
  610. X    static char *savetz = NULL, *oldtz = NULL;
  611. X    static int savetzlen = 0;
  612. X    char *tz;
  613. X    int tzlen;
  614. X
  615. X    /* various tables, useful in North America */
  616. X    static char *days_a[] = {
  617. X        "Sun", "Mon", "Tue", "Wed",
  618. X        "Thu", "Fri", "Sat",
  619. X    };
  620. X    static char *days_l[] = {
  621. X        "Sunday", "Monday", "Tuesday", "Wednesday",
  622. X        "Thursday", "Friday", "Saturday",
  623. X    };
  624. X    static char *months_a[] = {
  625. X        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  626. X        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  627. X    };
  628. X    static char *months_l[] = {
  629. X        "January", "February", "March", "April",
  630. X        "May", "June", "July", "August", "September",
  631. X        "October", "November", "December",
  632. X    };
  633. X    static char *ampm[] = { "AM", "PM", };
  634. X
  635. X    if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
  636. X        return 0;
  637. X
  638. X    if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize)
  639. X        return 0;
  640. X
  641. X#ifndef POSIX_SEMANTICS
  642. X    if (first) {
  643. X        tzset();
  644. X        first = 0;
  645. X    }
  646. X#else    /* POSIX_SEMANTICS */
  647. X    tz = getenv("TZ");
  648. X    tzlen = strlen(tz);
  649. X    if (first) {
  650. X        if (tz != NULL) {
  651. X            savetz = (char *) malloc(tzlen + 1);
  652. X            if (savetz != NULL) {
  653. X                savetzlen = tzlen + 1;
  654. X                strcpy(savetz, tz);
  655. X            }
  656. X        }
  657. X        tzset();
  658. X        first = 0;
  659. X    }
  660. X    /* if we have a saved TZ, and it is different, recapture and reset */
  661. X    if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) {
  662. X        i = strlen(tz) + 1;
  663. X        if (i > savetzlen) {
  664. X            savetz = (char *) realloc(savetz, i);
  665. X            if (savetz) {
  666. X                savetzlen = i;
  667. X                strcpy(savetz, tz);
  668. X            }
  669. X        } else
  670. X            strcpy(savetz, tz);
  671. X        tzset();
  672. X    }
  673. X#endif /* POSIX_SEMANTICS */
  674. X
  675. X    for (; *format && s < endp - 1; format++) {
  676. X        tbuf[0] = '\0';
  677. X        if (*format != '%') {
  678. X            *s++ = *format;
  679. X            continue;
  680. X        }
  681. X    again:
  682. X        switch (*++format) {
  683. X        case '\0':
  684. X            *s++ = '%';
  685. X            goto out;
  686. X
  687. X        case '%':
  688. X            *s++ = '%';
  689. X            continue;
  690. X
  691. X        case 'a':    /* abbreviated weekday name */
  692. X            if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
  693. X                strcpy(tbuf, "?");
  694. X            else
  695. X                strcpy(tbuf, days_a[timeptr->tm_wday]);
  696. X            break;
  697. X
  698. X        case 'A':    /* full weekday name */
  699. X            if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
  700. X                strcpy(tbuf, "?");
  701. X            else
  702. X                strcpy(tbuf, days_l[timeptr->tm_wday]);
  703. X            break;
  704. X
  705. X#ifdef SYSV_EXT
  706. X        case 'h':    /* abbreviated month name */
  707. X#endif
  708. X        case 'b':    /* abbreviated month name */
  709. X            if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
  710. X                strcpy(tbuf, "?");
  711. X            else
  712. X                strcpy(tbuf, months_a[timeptr->tm_mon]);
  713. X            break;
  714. X
  715. X        case 'B':    /* full month name */
  716. X            if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
  717. X                strcpy(tbuf, "?");
  718. X            else
  719. X                strcpy(tbuf, months_l[timeptr->tm_mon]);
  720. X            break;
  721. X
  722. X        case 'c':    /* appropriate date and time representation */
  723. X            sprintf(tbuf, "%s %s %2d %02d:%02d:%02d %d",
  724. X                days_a[range(0, timeptr->tm_wday, 6)],
  725. X                months_a[range(0, timeptr->tm_mon, 11)],
  726. X                range(1, timeptr->tm_mday, 31),
  727. X                range(0, timeptr->tm_hour, 23),
  728. X                range(0, timeptr->tm_min, 59),
  729. X                range(0, timeptr->tm_sec, 61),
  730. X                timeptr->tm_year + 1900);
  731. X            break;
  732. X
  733. X        case 'd':    /* day of the month, 01 - 31 */
  734. X            i = range(1, timeptr->tm_mday, 31);
  735. X            sprintf(tbuf, "%02d", i);
  736. X            break;
  737. X
  738. X        case 'H':    /* hour, 24-hour clock, 00 - 23 */
  739. X            i = range(0, timeptr->tm_hour, 23);
  740. X            sprintf(tbuf, "%02d", i);
  741. X            break;
  742. X
  743. X        case 'I':    /* hour, 12-hour clock, 01 - 12 */
  744. X            i = range(0, timeptr->tm_hour, 23);
  745. X            if (i == 0)
  746. X                i = 12;
  747. X            else if (i > 12)
  748. X                i -= 12;
  749. X            sprintf(tbuf, "%02d", i);
  750. X            break;
  751. X
  752. X        case 'j':    /* day of the year, 001 - 366 */
  753. X            sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
  754. X            break;
  755. X
  756. X        case 'm':    /* month, 01 - 12 */
  757. X            i = range(0, timeptr->tm_mon, 11);
  758. X            sprintf(tbuf, "%02d", i + 1);
  759. X            break;
  760. X
  761. X        case 'M':    /* minute, 00 - 59 */
  762. X            i = range(0, timeptr->tm_min, 59);
  763. X            sprintf(tbuf, "%02d", i);
  764. X            break;
  765. X
  766. X        case 'p':    /* am or pm based on 12-hour clock */
  767. X            i = range(0, timeptr->tm_hour, 23);
  768. X            if (i < 12)
  769. X                strcpy(tbuf, ampm[0]);
  770. X            else
  771. X                strcpy(tbuf, ampm[1]);
  772. X            break;
  773. X
  774. X        case 'S':    /* second, 00 - 61 */
  775. X            i = range(0, timeptr->tm_sec, 61);
  776. X            sprintf(tbuf, "%02d", i);
  777. X            break;
  778. X
  779. X        case 'U':    /* week of year, Sunday is first day of week */
  780. X            sprintf(tbuf, "%d", weeknumber(timeptr, 0));
  781. X            break;
  782. X
  783. X        case 'w':    /* weekday, Sunday == 0, 0 - 6 */
  784. X            i = range(0, timeptr->tm_wday, 6);
  785. X            sprintf(tbuf, "%d", i);
  786. X            break;
  787. X
  788. X        case 'W':    /* week of year, Monday is first day of week */
  789. X            sprintf(tbuf, "%d", weeknumber(timeptr, 1));
  790. X            break;
  791. X
  792. X        case 'x':    /* appropriate date representation */
  793. X            sprintf(tbuf, "%s %s %2d %d",
  794. X                days_a[range(0, timeptr->tm_wday, 6)],
  795. X                months_a[range(0, timeptr->tm_mon, 11)],
  796. X                range(1, timeptr->tm_mday, 31),
  797. X                timeptr->tm_year + 1900);
  798. X            break;
  799. X
  800. X        case 'X':    /* appropriate time representation */
  801. X            sprintf(tbuf, "%02d:%02d:%02d",
  802. X                range(0, timeptr->tm_hour, 23),
  803. X                range(0, timeptr->tm_min, 59),
  804. X                range(0, timeptr->tm_sec, 61));
  805. X            break;
  806. X
  807. X        case 'y':    /* year without a century, 00 - 99 */
  808. X            i = timeptr->tm_year % 100;
  809. X            sprintf(tbuf, "%d", i);
  810. X            break;
  811. X
  812. X        case 'Y':    /* year with century */
  813. X            sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
  814. X            break;
  815. X
  816. X        case 'Z':    /* time zone name or abbrevation */
  817. X            i = 0;
  818. X            if (daylight && timeptr->tm_isdst)
  819. X                i = 1;
  820. X            strcpy(tbuf, tzname[i]);
  821. X            break;
  822. X
  823. X#ifdef SYSV_EXT
  824. X        case 'n':    /* same as \n */
  825. X            tbuf[0] = '\n';
  826. X            tbuf[1] = '\0';
  827. X            break;
  828. X
  829. X        case 't':    /* same as \t */
  830. X            tbuf[0] = '\t';
  831. X            tbuf[1] = '\0';
  832. X            break;
  833. X
  834. X        case 'D':    /* date as %m/%d/%y */
  835. X            strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
  836. X            break;
  837. X
  838. X        case 'e':    /* day of month, blank padded */
  839. X            sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
  840. X            break;
  841. X
  842. X        case 'r':    /* time as %I:%M:%S %p */
  843. X            strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
  844. X            break;
  845. X
  846. X        case 'R':    /* time as %H:%M */
  847. X            strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
  848. X            break;
  849. X
  850. X        case 'T':    /* time as %H:%M:%S */
  851. X            strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
  852. X            break;
  853. X#endif
  854. X
  855. X
  856. X#ifdef VMS_EXT
  857. X        case 'V':    /* date as dd-bbb-YYYY */
  858. X            sprintf(tbuf, "%2d-%3.3s-%4d",
  859. X                range(1, timeptr->tm_mday, 31),
  860. X                months_a[range(0, timeptr->tm_mon, 11)],
  861. X                timeptr->tm_year + 1900);
  862. X            for (i = 3; i < 6; i++)
  863. X                if (islower(tbuf[i]))
  864. X                    tbuf[i] = toupper(tbuf[i]);
  865. X            break;
  866. X#endif
  867. X
  868. X
  869. X#ifdef POSIX2_DATE
  870. X        case 'C':
  871. X            sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
  872. X            break;
  873. X
  874. X
  875. X        case 'E':
  876. X        case 'O':
  877. X            /* POSIX locale extensions, ignored for now */
  878. X            goto again;
  879. X#endif
  880. X        default:
  881. X            tbuf[0] = '%';
  882. X            tbuf[1] = *format;
  883. X            tbuf[2] = '\0';
  884. X            break;
  885. X        }
  886. X        i = strlen(tbuf);
  887. X        if (i)
  888. X            if (s + i < endp - 1) {
  889. X                strcpy(s, tbuf);
  890. X                s += i;
  891. X            } else
  892. X                return 0;
  893. X    }
  894. out:
  895. X    if (s < endp && *format == '\0') {
  896. X        *s = '\0';
  897. X        return (s - start);
  898. X    } else
  899. X        return 0;
  900. X}
  901. X
  902. X/* weeknumber --- figure how many weeks into the year */
  903. X
  904. X/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
  905. X
  906. X#ifndef __STDC__
  907. static int
  908. weeknumber(timeptr, firstweekday)
  909. const struct tm *timeptr;
  910. int firstweekday;
  911. X#else
  912. static int
  913. weeknumber(const struct tm *timeptr, int firstweekday)
  914. X#endif
  915. X{
  916. X    if (firstweekday == 0)
  917. X        return (timeptr->tm_yday + 7 - timeptr->tm_wday) / 7;
  918. X    else
  919. X        return (timeptr->tm_yday + 7 -
  920. X            (timeptr->tm_wday ? (timeptr->tm_wday - 1) : 6)) / 7;
  921. X}
  922. X
  923. X#if 0
  924. X/* ADR --- I'm loathe to mess with ado's code ... */
  925. X
  926. Date:         Wed, 24 Apr 91 20:54:08 MDT
  927. XFrom: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
  928. To: arnold@audiofax.com
  929. X
  930. Hi Arnold,
  931. in a process of fixing of strftime() in libraries on Atari ST I grabbed
  932. some pieces of code from your own strftime.  When doing that it came
  933. to mind that your weeknumber() function compiles a little bit nicer
  934. in the following form:
  935. X/*
  936. X * firstweekday is 0 if starting in Sunday, non-zero if in Monday
  937. X */
  938. X{
  939. X    return (timeptr->tm_yday - timeptr->tm_wday +
  940. X        (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
  941. X}
  942. How nicer it depends on a compiler, of course, but always a tiny bit.
  943. X
  944. X   Cheers,
  945. X   Michal
  946. X   ntomczak@vm.ucs.ualberta.ca
  947. X#endif
  948. END_OF_FILE
  949. if test 10430 -ne `wc -c <'strftime.c'`; then
  950.     echo shar: \"'strftime.c'\" unpacked with wrong size!
  951. fi
  952. # end of 'strftime.c'
  953. fi
  954. echo shar: End of shell archive.
  955. exit 0
  956.