home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / strftm20 / part01 < prev    next >
Encoding:
Text File  |  1993-04-09  |  27.8 KB  |  1,137 lines

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