joe-3.1jupp31.tgz (die zweite Klappe…)
[alioth/jupp.git] / compat.c
1 /* $MirOS: contrib/code/jupp/compat.c,v 1.4 2012/06/08 16:48:58 tg Exp $ */
2
3 /*-
4  * Copyright © 2004, 2005, 2006, 2007, 2011, 2012
5  *      Thorsten “mirabilos” Glaser <tg@mirbsd.org>
6  *
7  * Provided that these terms and disclaimer and all copyright notices
8  * are retained or reproduced in an accompanying document, permission
9  * is granted to deal in this work without restriction, including un‐
10  * limited rights to use, publicly perform, distribute, sell, modify,
11  * merge, give away, or sublicence.
12  *
13  * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14  * the utmost extent permitted by applicable law, neither express nor
15  * implied; without malicious intent or gross negligence. In no event
16  * may a licensor, author or contributor be held liable for indirect,
17  * direct, other damage, loss, or other issues arising in any way out
18  * of dealing in the work, even if advised of the possibility of such
19  * damage or existence of a defect, except proven that it results out
20  * of said person’s immediate fault when using the work as intended.
21  *-
22  * Compatibility functions for jupp.
23  *
24  * – ctime: based on mirtime from MirBSD libc; not leap second capable
25  *   src/kern/include/mirtime.h,v 1.2 2011/11/20 23:40:11 tg Exp
26  *   src/kern/c/mirtime.c,v 1.3 2011/11/20 23:40:10 tg Exp
27  * – strlcpy, strlcat: pulled in via "strlfun.inc"
28  * – popen, pclose: pulled in via "popen.inc"
29  */
30
31 #include "config.h"
32 #include "types.h"
33
34 #undef __RCSID
35 #define __RCSID(x)      /* nothing, in jupp */
36
37 #undef L_strlcat
38 #undef L_strlcpy
39 #ifndef HAVE_STRLCAT
40 #define L_strlcat
41 #endif
42 #ifndef HAVE_STRLCPY
43 #define L_strlcpy
44 #endif
45 #if defined(L_strlcat) || defined(L_strlcpy)
46 #define OUTSIDE_OF_LIBKERN
47 #include "strlfun.inc"
48 #endif
49
50 #ifndef HAVE_CTIME
51 #ifdef TIME_WITH_SYS_TIME
52 # include <sys/time.h>
53 # include <time.h>
54 #else
55 # ifdef HAVE_SYS_TIME_H
56 #  include <sys/time.h>
57 # else
58 #  include <time.h>
59 # endif
60 #endif
61
62 #include <limits.h>
63 #include <stdio.h>
64
65 typedef struct {
66         int tm_sec;             /* seconds [0-60] */
67         int tm_min;             /* minutes [0-59] */
68         int tm_hour;            /* hours [0-23] */
69         int tm_mday;            /* day of month [1-31] */
70         int tm_mon;             /* month of year - 1 [0-11] */
71         int tm_year;            /* year - 1900 */
72         int tm_wday;            /* day of week (0 = sunday) */
73 } joe_tm;
74
75 static void joe_timet2tm(joe_tm *, const time_t *);
76
77 #if !HAVE_DECL_CTIME
78 char *ctime(const time_t *);
79 #endif
80
81 /* 302 / 1000 is log10(2.0) rounded up */
82 #define T_SIGNED(t)     (((t)-1) < 0)
83 #define T_MAXLEN(t)     ((sizeof(t) * CHAR_BIT - T_SIGNED(t)) * 302 / 1000 + \
84                             /* div.trunc. */ 1 + /* minus sign */ T_SIGNED(t))
85
86 static const char joe_days[7][4] = {
87         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
88 };
89
90 static const char joe_months[12][4] = {
91         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
92         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
93 };
94
95 /*-
96  * Dimensions for the buffer, example formats:
97  * "Sun Jan  1 12:34:56 1234\n"
98  * "Sat Dec 31 12:34:56     12345\n"
99  *  <- 24 -----------------> + max.length of a year + NL + NUL
100  */
101 static char joe_ctime_buf[24 + T_MAXLEN(time_t) + 2];
102
103 char *
104 ctime(const time_t *tp)
105 {
106         int year;
107         joe_tm tm;
108
109         joe_timet2tm(&tm, tp);
110         year = (int)(tm.tm_year + 1900);
111         joe_snprintf_7(joe_ctime_buf, sizeof(joe_ctime_buf),
112             (year >= -999 && year <= 9999) ?
113             "%s %s %2d %02d:%02d:%02d %04d\n" :
114             "%s %s %2d %02d:%02d:%02d     %d\n",
115             joe_days[tm.tm_wday], joe_months[tm.tm_mon],
116             tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, year);
117         return (joe_ctime_buf);
118 }
119
120 static void
121 joe_timet2tm(joe_tm *tm, const time_t *tp)
122 {
123         int sec, day, mon;
124         time_t y;
125
126         /* convert to MJD */
127         y = *tp;
128         sec = (int)(y % 86400);
129         y /= 86400;
130         y += 40587;
131         while (sec < 0) {
132                 --y;
133                 sec += 86400;
134         }
135
136         /* calculate 400-year cycle (y) and offset in it (day) */
137         day = (int)(y % 146097);
138         y /= 146097;
139
140         /* add bias: 678881 = days between "convenient origin" and MJD 0 */
141         /* convenient origin is Wed(3) 1 March 0(fictional)/-1(real) */
142         day += 678881;
143         /* recalculate offset in cycle (Gregorian Period) */
144         y += day / 146097;
145         day %= 146097;
146
147         /* days in 400 years are cyclic, they have 20871 weeks */
148         tm->tm_wday = (day + 3) % 7;
149
150         /* calculate year from period, taking leap years into account */
151         y *= 4;
152         /* a long (Julian) century is at the end of each Gregorian Period */
153         if (day == 146096) {
154                 y += 3;
155                 day = 36524;
156         } else {
157                 y += day / 36524;
158                 day %= 36524;
159         }
160         y *= 25;
161         y += day / 1461;
162         day %= 1461;
163         y *= 4;
164
165         /* March to December, or January/February? */
166         /* a leap year is at the end of each olympiad */
167         if (day == 1460) {
168                 y += 3;
169                 day = 365;
170         } else {
171                 y += day / 365;
172                 day %= 365;
173         }
174
175         /* count days and months from 1st March using fixed-point */
176         day *= 10;
177         mon = (day + 5) / 306;
178         day = (day + 5) % 306;
179         day /= 10;
180         /* adjust for Jan/Feb offset */
181         if (mon >= 10) {
182                 mon -= 10;
183                 ++y;
184         } else {
185                 mon += 2;
186         }
187
188         /* adjust for year 0(fictional) which did not exist */
189         if (y < 1)
190                 --y;
191
192         /* fill in the values still missing */
193         tm->tm_sec = sec % 60;
194         sec /= 60;
195         tm->tm_min = sec % 60;
196         tm->tm_hour = sec / 60;
197         tm->tm_mday = day + 1;
198         tm->tm_mon = mon;
199         /*XXX truncate, for joe_snprintf doesn't know %lld portably */
200         tm->tm_year = (int)(y - 1900);
201 }
202 #endif /* ndef HAVE_CTIME */
203
204 #ifndef HAVE_POPEN
205 #include "popen.inc"
206 #endif