1*bc421551SDag-Erling Smørgrav /* Convert a broken-down timestamp to a string. */ 2*bc421551SDag-Erling Smørgrav 3*bc421551SDag-Erling Smørgrav /* Copyright 1989 The Regents of the University of California. 4*bc421551SDag-Erling Smørgrav All rights reserved. 5*bc421551SDag-Erling Smørgrav 6*bc421551SDag-Erling Smørgrav Redistribution and use in source and binary forms, with or without 7*bc421551SDag-Erling Smørgrav modification, are permitted provided that the following conditions 8*bc421551SDag-Erling Smørgrav are met: 9*bc421551SDag-Erling Smørgrav 1. Redistributions of source code must retain the above copyright 10*bc421551SDag-Erling Smørgrav notice, this list of conditions and the following disclaimer. 11*bc421551SDag-Erling Smørgrav 2. Redistributions in binary form must reproduce the above copyright 12*bc421551SDag-Erling Smørgrav notice, this list of conditions and the following disclaimer in the 13*bc421551SDag-Erling Smørgrav documentation and/or other materials provided with the distribution. 14*bc421551SDag-Erling Smørgrav 3. Neither the name of the University nor the names of its contributors 15*bc421551SDag-Erling Smørgrav may be used to endorse or promote products derived from this software 16*bc421551SDag-Erling Smørgrav without specific prior written permission. 17*bc421551SDag-Erling Smørgrav 18*bc421551SDag-Erling Smørgrav THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND 19*bc421551SDag-Erling Smørgrav ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*bc421551SDag-Erling Smørgrav IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*bc421551SDag-Erling Smørgrav ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22*bc421551SDag-Erling Smørgrav FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*bc421551SDag-Erling Smørgrav DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*bc421551SDag-Erling Smørgrav OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*bc421551SDag-Erling Smørgrav HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*bc421551SDag-Erling Smørgrav LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*bc421551SDag-Erling Smørgrav OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*bc421551SDag-Erling Smørgrav SUCH DAMAGE. */ 29*bc421551SDag-Erling Smørgrav 30*bc421551SDag-Erling Smørgrav /* 31*bc421551SDag-Erling Smørgrav ** Based on the UCB version with the copyright notice appearing above. 32*bc421551SDag-Erling Smørgrav ** 33*bc421551SDag-Erling Smørgrav ** This is ANSIish only when "multibyte character == plain character". 34*bc421551SDag-Erling Smørgrav */ 35*bc421551SDag-Erling Smørgrav 36*bc421551SDag-Erling Smørgrav #include "private.h" 37*bc421551SDag-Erling Smørgrav 38*bc421551SDag-Erling Smørgrav #include <fcntl.h> 39*bc421551SDag-Erling Smørgrav #include <locale.h> 40*bc421551SDag-Erling Smørgrav #include <stdio.h> 41*bc421551SDag-Erling Smørgrav 42*bc421551SDag-Erling Smørgrav #ifndef DEPRECATE_TWO_DIGIT_YEARS 43*bc421551SDag-Erling Smørgrav # define DEPRECATE_TWO_DIGIT_YEARS false 44*bc421551SDag-Erling Smørgrav #endif 45*bc421551SDag-Erling Smørgrav 46*bc421551SDag-Erling Smørgrav struct lc_time_T { 47*bc421551SDag-Erling Smørgrav const char * mon[MONSPERYEAR]; 48*bc421551SDag-Erling Smørgrav const char * month[MONSPERYEAR]; 49*bc421551SDag-Erling Smørgrav const char * wday[DAYSPERWEEK]; 50*bc421551SDag-Erling Smørgrav const char * weekday[DAYSPERWEEK]; 51*bc421551SDag-Erling Smørgrav const char * X_fmt; 52*bc421551SDag-Erling Smørgrav const char * x_fmt; 53*bc421551SDag-Erling Smørgrav const char * c_fmt; 54*bc421551SDag-Erling Smørgrav const char * am; 55*bc421551SDag-Erling Smørgrav const char * pm; 56*bc421551SDag-Erling Smørgrav const char * date_fmt; 57*bc421551SDag-Erling Smørgrav }; 58*bc421551SDag-Erling Smørgrav 59*bc421551SDag-Erling Smørgrav static const struct lc_time_T C_time_locale = { 60*bc421551SDag-Erling Smørgrav { 61*bc421551SDag-Erling Smørgrav "Jan", "Feb", "Mar", "Apr", "May", "Jun", 62*bc421551SDag-Erling Smørgrav "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 63*bc421551SDag-Erling Smørgrav }, { 64*bc421551SDag-Erling Smørgrav "January", "February", "March", "April", "May", "June", 65*bc421551SDag-Erling Smørgrav "July", "August", "September", "October", "November", "December" 66*bc421551SDag-Erling Smørgrav }, { 67*bc421551SDag-Erling Smørgrav "Sun", "Mon", "Tue", "Wed", 68*bc421551SDag-Erling Smørgrav "Thu", "Fri", "Sat" 69*bc421551SDag-Erling Smørgrav }, { 70*bc421551SDag-Erling Smørgrav "Sunday", "Monday", "Tuesday", "Wednesday", 71*bc421551SDag-Erling Smørgrav "Thursday", "Friday", "Saturday" 72*bc421551SDag-Erling Smørgrav }, 73*bc421551SDag-Erling Smørgrav 74*bc421551SDag-Erling Smørgrav /* X_fmt */ 75*bc421551SDag-Erling Smørgrav "%H:%M:%S", 76*bc421551SDag-Erling Smørgrav 77*bc421551SDag-Erling Smørgrav /* 78*bc421551SDag-Erling Smørgrav ** x_fmt 79*bc421551SDag-Erling Smørgrav ** C99 and later require this format. 80*bc421551SDag-Erling Smørgrav ** Using just numbers (as here) makes Quakers happier; 81*bc421551SDag-Erling Smørgrav ** it's also compatible with SVR4. 82*bc421551SDag-Erling Smørgrav */ 83*bc421551SDag-Erling Smørgrav "%m/%d/%y", 84*bc421551SDag-Erling Smørgrav 85*bc421551SDag-Erling Smørgrav /* 86*bc421551SDag-Erling Smørgrav ** c_fmt 87*bc421551SDag-Erling Smørgrav ** C99 and later require this format. 88*bc421551SDag-Erling Smørgrav ** Previously this code used "%D %X", but we now conform to C99. 89*bc421551SDag-Erling Smørgrav ** Note that 90*bc421551SDag-Erling Smørgrav ** "%a %b %d %H:%M:%S %Y" 91*bc421551SDag-Erling Smørgrav ** is used by Solaris 2.3. 92*bc421551SDag-Erling Smørgrav */ 93*bc421551SDag-Erling Smørgrav "%a %b %e %T %Y", 94*bc421551SDag-Erling Smørgrav 95*bc421551SDag-Erling Smørgrav /* am */ 96*bc421551SDag-Erling Smørgrav "AM", 97*bc421551SDag-Erling Smørgrav 98*bc421551SDag-Erling Smørgrav /* pm */ 99*bc421551SDag-Erling Smørgrav "PM", 100*bc421551SDag-Erling Smørgrav 101*bc421551SDag-Erling Smørgrav /* date_fmt */ 102*bc421551SDag-Erling Smørgrav "%a %b %e %H:%M:%S %Z %Y" 103*bc421551SDag-Erling Smørgrav }; 104*bc421551SDag-Erling Smørgrav 105*bc421551SDag-Erling Smørgrav enum warn { IN_NONE, IN_SOME, IN_THIS, IN_ALL }; 106*bc421551SDag-Erling Smørgrav 107*bc421551SDag-Erling Smørgrav static char * _add(const char *, char *, const char *); 108*bc421551SDag-Erling Smørgrav static char * _conv(int, const char *, char *, const char *); 109*bc421551SDag-Erling Smørgrav static char * _fmt(const char *, const struct tm *, char *, const char *, 110*bc421551SDag-Erling Smørgrav enum warn *); 111*bc421551SDag-Erling Smørgrav static char * _yconv(int, int, bool, bool, char *, char const *); 112*bc421551SDag-Erling Smørgrav 113*bc421551SDag-Erling Smørgrav #ifndef YEAR_2000_NAME 114*bc421551SDag-Erling Smørgrav # define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS" 115*bc421551SDag-Erling Smørgrav #endif /* !defined YEAR_2000_NAME */ 116*bc421551SDag-Erling Smørgrav 117*bc421551SDag-Erling Smørgrav #if HAVE_STRFTIME_L 118*bc421551SDag-Erling Smørgrav size_t 119*bc421551SDag-Erling Smørgrav strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t, 120*bc421551SDag-Erling Smørgrav ATTRIBUTE_MAYBE_UNUSED locale_t locale) 121*bc421551SDag-Erling Smørgrav { 122*bc421551SDag-Erling Smørgrav /* Just call strftime, as only the C locale is supported. */ 123*bc421551SDag-Erling Smørgrav return strftime(s, maxsize, format, t); 124*bc421551SDag-Erling Smørgrav } 125*bc421551SDag-Erling Smørgrav #endif 126*bc421551SDag-Erling Smørgrav 127*bc421551SDag-Erling Smørgrav size_t 128*bc421551SDag-Erling Smørgrav strftime(char *s, size_t maxsize, const char *format, const struct tm *t) 129*bc421551SDag-Erling Smørgrav { 130*bc421551SDag-Erling Smørgrav char * p; 131*bc421551SDag-Erling Smørgrav int saved_errno = errno; 132*bc421551SDag-Erling Smørgrav enum warn warn = IN_NONE; 133*bc421551SDag-Erling Smørgrav 134*bc421551SDag-Erling Smørgrav tzset(); 135*bc421551SDag-Erling Smørgrav p = _fmt(format, t, s, s + maxsize, &warn); 136*bc421551SDag-Erling Smørgrav if (!p) { 137*bc421551SDag-Erling Smørgrav errno = EOVERFLOW; 138*bc421551SDag-Erling Smørgrav return 0; 139*bc421551SDag-Erling Smørgrav } 140*bc421551SDag-Erling Smørgrav if (DEPRECATE_TWO_DIGIT_YEARS 141*bc421551SDag-Erling Smørgrav && warn != IN_NONE && getenv(YEAR_2000_NAME)) { 142*bc421551SDag-Erling Smørgrav fprintf(stderr, "\n"); 143*bc421551SDag-Erling Smørgrav fprintf(stderr, "strftime format \"%s\" ", format); 144*bc421551SDag-Erling Smørgrav fprintf(stderr, "yields only two digits of years in "); 145*bc421551SDag-Erling Smørgrav if (warn == IN_SOME) 146*bc421551SDag-Erling Smørgrav fprintf(stderr, "some locales"); 147*bc421551SDag-Erling Smørgrav else if (warn == IN_THIS) 148*bc421551SDag-Erling Smørgrav fprintf(stderr, "the current locale"); 149*bc421551SDag-Erling Smørgrav else fprintf(stderr, "all locales"); 150*bc421551SDag-Erling Smørgrav fprintf(stderr, "\n"); 151*bc421551SDag-Erling Smørgrav } 152*bc421551SDag-Erling Smørgrav if (p == s + maxsize) { 153*bc421551SDag-Erling Smørgrav errno = ERANGE; 154*bc421551SDag-Erling Smørgrav return 0; 155*bc421551SDag-Erling Smørgrav } 156*bc421551SDag-Erling Smørgrav *p = '\0'; 157*bc421551SDag-Erling Smørgrav errno = saved_errno; 158*bc421551SDag-Erling Smørgrav return p - s; 159*bc421551SDag-Erling Smørgrav } 160*bc421551SDag-Erling Smørgrav 161*bc421551SDag-Erling Smørgrav static char * 162*bc421551SDag-Erling Smørgrav _fmt(const char *format, const struct tm *t, char *pt, 163*bc421551SDag-Erling Smørgrav const char *ptlim, enum warn *warnp) 164*bc421551SDag-Erling Smørgrav { 165*bc421551SDag-Erling Smørgrav struct lc_time_T const *Locale = &C_time_locale; 166*bc421551SDag-Erling Smørgrav 167*bc421551SDag-Erling Smørgrav for ( ; *format; ++format) { 168*bc421551SDag-Erling Smørgrav if (*format == '%') { 169*bc421551SDag-Erling Smørgrav label: 170*bc421551SDag-Erling Smørgrav switch (*++format) { 171*bc421551SDag-Erling Smørgrav case '\0': 172*bc421551SDag-Erling Smørgrav --format; 173*bc421551SDag-Erling Smørgrav break; 174*bc421551SDag-Erling Smørgrav case 'A': 175*bc421551SDag-Erling Smørgrav pt = _add((t->tm_wday < 0 || 176*bc421551SDag-Erling Smørgrav t->tm_wday >= DAYSPERWEEK) ? 177*bc421551SDag-Erling Smørgrav "?" : Locale->weekday[t->tm_wday], 178*bc421551SDag-Erling Smørgrav pt, ptlim); 179*bc421551SDag-Erling Smørgrav continue; 180*bc421551SDag-Erling Smørgrav case 'a': 181*bc421551SDag-Erling Smørgrav pt = _add((t->tm_wday < 0 || 182*bc421551SDag-Erling Smørgrav t->tm_wday >= DAYSPERWEEK) ? 183*bc421551SDag-Erling Smørgrav "?" : Locale->wday[t->tm_wday], 184*bc421551SDag-Erling Smørgrav pt, ptlim); 185*bc421551SDag-Erling Smørgrav continue; 186*bc421551SDag-Erling Smørgrav case 'B': 187*bc421551SDag-Erling Smørgrav pt = _add((t->tm_mon < 0 || 188*bc421551SDag-Erling Smørgrav t->tm_mon >= MONSPERYEAR) ? 189*bc421551SDag-Erling Smørgrav "?" : Locale->month[t->tm_mon], 190*bc421551SDag-Erling Smørgrav pt, ptlim); 191*bc421551SDag-Erling Smørgrav continue; 192*bc421551SDag-Erling Smørgrav case 'b': 193*bc421551SDag-Erling Smørgrav case 'h': 194*bc421551SDag-Erling Smørgrav pt = _add((t->tm_mon < 0 || 195*bc421551SDag-Erling Smørgrav t->tm_mon >= MONSPERYEAR) ? 196*bc421551SDag-Erling Smørgrav "?" : Locale->mon[t->tm_mon], 197*bc421551SDag-Erling Smørgrav pt, ptlim); 198*bc421551SDag-Erling Smørgrav continue; 199*bc421551SDag-Erling Smørgrav case 'C': 200*bc421551SDag-Erling Smørgrav /* 201*bc421551SDag-Erling Smørgrav ** %C used to do a... 202*bc421551SDag-Erling Smørgrav ** _fmt("%a %b %e %X %Y", t); 203*bc421551SDag-Erling Smørgrav ** ...whereas now POSIX 1003.2 calls for 204*bc421551SDag-Erling Smørgrav ** something completely different. 205*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 206*bc421551SDag-Erling Smørgrav */ 207*bc421551SDag-Erling Smørgrav pt = _yconv(t->tm_year, TM_YEAR_BASE, 208*bc421551SDag-Erling Smørgrav true, false, pt, ptlim); 209*bc421551SDag-Erling Smørgrav continue; 210*bc421551SDag-Erling Smørgrav case 'c': 211*bc421551SDag-Erling Smørgrav { 212*bc421551SDag-Erling Smørgrav enum warn warn2 = IN_SOME; 213*bc421551SDag-Erling Smørgrav 214*bc421551SDag-Erling Smørgrav pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2); 215*bc421551SDag-Erling Smørgrav if (warn2 == IN_ALL) 216*bc421551SDag-Erling Smørgrav warn2 = IN_THIS; 217*bc421551SDag-Erling Smørgrav if (warn2 > *warnp) 218*bc421551SDag-Erling Smørgrav *warnp = warn2; 219*bc421551SDag-Erling Smørgrav } 220*bc421551SDag-Erling Smørgrav continue; 221*bc421551SDag-Erling Smørgrav case 'D': 222*bc421551SDag-Erling Smørgrav pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); 223*bc421551SDag-Erling Smørgrav continue; 224*bc421551SDag-Erling Smørgrav case 'd': 225*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_mday, "%02d", pt, ptlim); 226*bc421551SDag-Erling Smørgrav continue; 227*bc421551SDag-Erling Smørgrav case 'E': 228*bc421551SDag-Erling Smørgrav case 'O': 229*bc421551SDag-Erling Smørgrav /* 230*bc421551SDag-Erling Smørgrav ** Locale modifiers of C99 and later. 231*bc421551SDag-Erling Smørgrav ** The sequences 232*bc421551SDag-Erling Smørgrav ** %Ec %EC %Ex %EX %Ey %EY 233*bc421551SDag-Erling Smørgrav ** %Od %oe %OH %OI %Om %OM 234*bc421551SDag-Erling Smørgrav ** %OS %Ou %OU %OV %Ow %OW %Oy 235*bc421551SDag-Erling Smørgrav ** are supposed to provide alternative 236*bc421551SDag-Erling Smørgrav ** representations. 237*bc421551SDag-Erling Smørgrav */ 238*bc421551SDag-Erling Smørgrav goto label; 239*bc421551SDag-Erling Smørgrav case 'e': 240*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_mday, "%2d", pt, ptlim); 241*bc421551SDag-Erling Smørgrav continue; 242*bc421551SDag-Erling Smørgrav case 'F': 243*bc421551SDag-Erling Smørgrav pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); 244*bc421551SDag-Erling Smørgrav continue; 245*bc421551SDag-Erling Smørgrav case 'H': 246*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_hour, "%02d", pt, ptlim); 247*bc421551SDag-Erling Smørgrav continue; 248*bc421551SDag-Erling Smørgrav case 'I': 249*bc421551SDag-Erling Smørgrav pt = _conv((t->tm_hour % 12) ? 250*bc421551SDag-Erling Smørgrav (t->tm_hour % 12) : 12, 251*bc421551SDag-Erling Smørgrav "%02d", pt, ptlim); 252*bc421551SDag-Erling Smørgrav continue; 253*bc421551SDag-Erling Smørgrav case 'j': 254*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim); 255*bc421551SDag-Erling Smørgrav continue; 256*bc421551SDag-Erling Smørgrav case 'k': 257*bc421551SDag-Erling Smørgrav /* 258*bc421551SDag-Erling Smørgrav ** This used to be... 259*bc421551SDag-Erling Smørgrav ** _conv(t->tm_hour % 12 ? 260*bc421551SDag-Erling Smørgrav ** t->tm_hour % 12 : 12, 2, ' '); 261*bc421551SDag-Erling Smørgrav ** ...and has been changed to the below to 262*bc421551SDag-Erling Smørgrav ** match SunOS 4.1.1 and Arnold Robbins' 263*bc421551SDag-Erling Smørgrav ** strftime version 3.0. That is, "%k" and 264*bc421551SDag-Erling Smørgrav ** "%l" have been swapped. 265*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 266*bc421551SDag-Erling Smørgrav */ 267*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_hour, "%2d", pt, ptlim); 268*bc421551SDag-Erling Smørgrav continue; 269*bc421551SDag-Erling Smørgrav #ifdef KITCHEN_SINK 270*bc421551SDag-Erling Smørgrav case 'K': 271*bc421551SDag-Erling Smørgrav /* 272*bc421551SDag-Erling Smørgrav ** After all this time, still unclaimed! 273*bc421551SDag-Erling Smørgrav */ 274*bc421551SDag-Erling Smørgrav pt = _add("kitchen sink", pt, ptlim); 275*bc421551SDag-Erling Smørgrav continue; 276*bc421551SDag-Erling Smørgrav #endif /* defined KITCHEN_SINK */ 277*bc421551SDag-Erling Smørgrav case 'l': 278*bc421551SDag-Erling Smørgrav /* 279*bc421551SDag-Erling Smørgrav ** This used to be... 280*bc421551SDag-Erling Smørgrav ** _conv(t->tm_hour, 2, ' '); 281*bc421551SDag-Erling Smørgrav ** ...and has been changed to the below to 282*bc421551SDag-Erling Smørgrav ** match SunOS 4.1.1 and Arnold Robbin's 283*bc421551SDag-Erling Smørgrav ** strftime version 3.0. That is, "%k" and 284*bc421551SDag-Erling Smørgrav ** "%l" have been swapped. 285*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 286*bc421551SDag-Erling Smørgrav */ 287*bc421551SDag-Erling Smørgrav pt = _conv((t->tm_hour % 12) ? 288*bc421551SDag-Erling Smørgrav (t->tm_hour % 12) : 12, 289*bc421551SDag-Erling Smørgrav "%2d", pt, ptlim); 290*bc421551SDag-Erling Smørgrav continue; 291*bc421551SDag-Erling Smørgrav case 'M': 292*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_min, "%02d", pt, ptlim); 293*bc421551SDag-Erling Smørgrav continue; 294*bc421551SDag-Erling Smørgrav case 'm': 295*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim); 296*bc421551SDag-Erling Smørgrav continue; 297*bc421551SDag-Erling Smørgrav case 'n': 298*bc421551SDag-Erling Smørgrav pt = _add("\n", pt, ptlim); 299*bc421551SDag-Erling Smørgrav continue; 300*bc421551SDag-Erling Smørgrav case 'p': 301*bc421551SDag-Erling Smørgrav pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ? 302*bc421551SDag-Erling Smørgrav Locale->pm : 303*bc421551SDag-Erling Smørgrav Locale->am, 304*bc421551SDag-Erling Smørgrav pt, ptlim); 305*bc421551SDag-Erling Smørgrav continue; 306*bc421551SDag-Erling Smørgrav case 'R': 307*bc421551SDag-Erling Smørgrav pt = _fmt("%H:%M", t, pt, ptlim, warnp); 308*bc421551SDag-Erling Smørgrav continue; 309*bc421551SDag-Erling Smørgrav case 'r': 310*bc421551SDag-Erling Smørgrav pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); 311*bc421551SDag-Erling Smørgrav continue; 312*bc421551SDag-Erling Smørgrav case 'S': 313*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_sec, "%02d", pt, ptlim); 314*bc421551SDag-Erling Smørgrav continue; 315*bc421551SDag-Erling Smørgrav case 's': 316*bc421551SDag-Erling Smørgrav { 317*bc421551SDag-Erling Smørgrav struct tm tm; 318*bc421551SDag-Erling Smørgrav char buf[INT_STRLEN_MAXIMUM( 319*bc421551SDag-Erling Smørgrav time_t) + 1]; 320*bc421551SDag-Erling Smørgrav time_t mkt; 321*bc421551SDag-Erling Smørgrav 322*bc421551SDag-Erling Smørgrav tm.tm_sec = t->tm_sec; 323*bc421551SDag-Erling Smørgrav tm.tm_min = t->tm_min; 324*bc421551SDag-Erling Smørgrav tm.tm_hour = t->tm_hour; 325*bc421551SDag-Erling Smørgrav tm.tm_mday = t->tm_mday; 326*bc421551SDag-Erling Smørgrav tm.tm_mon = t->tm_mon; 327*bc421551SDag-Erling Smørgrav tm.tm_year = t->tm_year; 328*bc421551SDag-Erling Smørgrav tm.tm_isdst = t->tm_isdst; 329*bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP 330*bc421551SDag-Erling Smørgrav tm.TM_GMTOFF = t->TM_GMTOFF; 331*bc421551SDag-Erling Smørgrav #endif 332*bc421551SDag-Erling Smørgrav mkt = mktime(&tm); 333*bc421551SDag-Erling Smørgrav /* If mktime fails, %s expands to the 334*bc421551SDag-Erling Smørgrav value of (time_t) -1 as a failure 335*bc421551SDag-Erling Smørgrav marker; this is better in practice 336*bc421551SDag-Erling Smørgrav than strftime failing. */ 337*bc421551SDag-Erling Smørgrav if (TYPE_SIGNED(time_t)) { 338*bc421551SDag-Erling Smørgrav intmax_t n = mkt; 339*bc421551SDag-Erling Smørgrav sprintf(buf, "%"PRIdMAX, n); 340*bc421551SDag-Erling Smørgrav } else { 341*bc421551SDag-Erling Smørgrav uintmax_t n = mkt; 342*bc421551SDag-Erling Smørgrav sprintf(buf, "%"PRIuMAX, n); 343*bc421551SDag-Erling Smørgrav } 344*bc421551SDag-Erling Smørgrav pt = _add(buf, pt, ptlim); 345*bc421551SDag-Erling Smørgrav } 346*bc421551SDag-Erling Smørgrav continue; 347*bc421551SDag-Erling Smørgrav case 'T': 348*bc421551SDag-Erling Smørgrav pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); 349*bc421551SDag-Erling Smørgrav continue; 350*bc421551SDag-Erling Smørgrav case 't': 351*bc421551SDag-Erling Smørgrav pt = _add("\t", pt, ptlim); 352*bc421551SDag-Erling Smørgrav continue; 353*bc421551SDag-Erling Smørgrav case 'U': 354*bc421551SDag-Erling Smørgrav pt = _conv((t->tm_yday + DAYSPERWEEK - 355*bc421551SDag-Erling Smørgrav t->tm_wday) / DAYSPERWEEK, 356*bc421551SDag-Erling Smørgrav "%02d", pt, ptlim); 357*bc421551SDag-Erling Smørgrav continue; 358*bc421551SDag-Erling Smørgrav case 'u': 359*bc421551SDag-Erling Smørgrav /* 360*bc421551SDag-Erling Smørgrav ** From Arnold Robbins' strftime version 3.0: 361*bc421551SDag-Erling Smørgrav ** "ISO 8601: Weekday as a decimal number 362*bc421551SDag-Erling Smørgrav ** [1 (Monday) - 7]" 363*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 364*bc421551SDag-Erling Smørgrav */ 365*bc421551SDag-Erling Smørgrav pt = _conv((t->tm_wday == 0) ? 366*bc421551SDag-Erling Smørgrav DAYSPERWEEK : t->tm_wday, 367*bc421551SDag-Erling Smørgrav "%d", pt, ptlim); 368*bc421551SDag-Erling Smørgrav continue; 369*bc421551SDag-Erling Smørgrav case 'V': /* ISO 8601 week number */ 370*bc421551SDag-Erling Smørgrav case 'G': /* ISO 8601 year (four digits) */ 371*bc421551SDag-Erling Smørgrav case 'g': /* ISO 8601 year (two digits) */ 372*bc421551SDag-Erling Smørgrav /* 373*bc421551SDag-Erling Smørgrav ** From Arnold Robbins' strftime version 3.0: "the week number of the 374*bc421551SDag-Erling Smørgrav ** year (the first Monday as the first day of week 1) as a decimal number 375*bc421551SDag-Erling Smørgrav ** (01-53)." 376*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 377*bc421551SDag-Erling Smørgrav ** 378*bc421551SDag-Erling Smørgrav ** From <https://www.cl.cam.ac.uk/~mgk25/iso-time.html> by Markus Kuhn: 379*bc421551SDag-Erling Smørgrav ** "Week 01 of a year is per definition the first week which has the 380*bc421551SDag-Erling Smørgrav ** Thursday in this year, which is equivalent to the week which contains 381*bc421551SDag-Erling Smørgrav ** the fourth day of January. In other words, the first week of a new year 382*bc421551SDag-Erling Smørgrav ** is the week which has the majority of its days in the new year. Week 01 383*bc421551SDag-Erling Smørgrav ** might also contain days from the previous year and the week before week 384*bc421551SDag-Erling Smørgrav ** 01 of a year is the last week (52 or 53) of the previous year even if 385*bc421551SDag-Erling Smørgrav ** it contains days from the new year. A week starts with Monday (day 1) 386*bc421551SDag-Erling Smørgrav ** and ends with Sunday (day 7). For example, the first week of the year 387*bc421551SDag-Erling Smørgrav ** 1997 lasts from 1996-12-30 to 1997-01-05..." 388*bc421551SDag-Erling Smørgrav ** (ado, 1996-01-02) 389*bc421551SDag-Erling Smørgrav */ 390*bc421551SDag-Erling Smørgrav { 391*bc421551SDag-Erling Smørgrav int year; 392*bc421551SDag-Erling Smørgrav int base; 393*bc421551SDag-Erling Smørgrav int yday; 394*bc421551SDag-Erling Smørgrav int wday; 395*bc421551SDag-Erling Smørgrav int w; 396*bc421551SDag-Erling Smørgrav 397*bc421551SDag-Erling Smørgrav year = t->tm_year; 398*bc421551SDag-Erling Smørgrav base = TM_YEAR_BASE; 399*bc421551SDag-Erling Smørgrav yday = t->tm_yday; 400*bc421551SDag-Erling Smørgrav wday = t->tm_wday; 401*bc421551SDag-Erling Smørgrav for ( ; ; ) { 402*bc421551SDag-Erling Smørgrav int len; 403*bc421551SDag-Erling Smørgrav int bot; 404*bc421551SDag-Erling Smørgrav int top; 405*bc421551SDag-Erling Smørgrav 406*bc421551SDag-Erling Smørgrav len = isleap_sum(year, base) ? 407*bc421551SDag-Erling Smørgrav DAYSPERLYEAR : 408*bc421551SDag-Erling Smørgrav DAYSPERNYEAR; 409*bc421551SDag-Erling Smørgrav /* 410*bc421551SDag-Erling Smørgrav ** What yday (-3 ... 3) does 411*bc421551SDag-Erling Smørgrav ** the ISO year begin on? 412*bc421551SDag-Erling Smørgrav */ 413*bc421551SDag-Erling Smørgrav bot = ((yday + 11 - wday) % 414*bc421551SDag-Erling Smørgrav DAYSPERWEEK) - 3; 415*bc421551SDag-Erling Smørgrav /* 416*bc421551SDag-Erling Smørgrav ** What yday does the NEXT 417*bc421551SDag-Erling Smørgrav ** ISO year begin on? 418*bc421551SDag-Erling Smørgrav */ 419*bc421551SDag-Erling Smørgrav top = bot - 420*bc421551SDag-Erling Smørgrav (len % DAYSPERWEEK); 421*bc421551SDag-Erling Smørgrav if (top < -3) 422*bc421551SDag-Erling Smørgrav top += DAYSPERWEEK; 423*bc421551SDag-Erling Smørgrav top += len; 424*bc421551SDag-Erling Smørgrav if (yday >= top) { 425*bc421551SDag-Erling Smørgrav ++base; 426*bc421551SDag-Erling Smørgrav w = 1; 427*bc421551SDag-Erling Smørgrav break; 428*bc421551SDag-Erling Smørgrav } 429*bc421551SDag-Erling Smørgrav if (yday >= bot) { 430*bc421551SDag-Erling Smørgrav w = 1 + ((yday - bot) / 431*bc421551SDag-Erling Smørgrav DAYSPERWEEK); 432*bc421551SDag-Erling Smørgrav break; 433*bc421551SDag-Erling Smørgrav } 434*bc421551SDag-Erling Smørgrav --base; 435*bc421551SDag-Erling Smørgrav yday += isleap_sum(year, base) ? 436*bc421551SDag-Erling Smørgrav DAYSPERLYEAR : 437*bc421551SDag-Erling Smørgrav DAYSPERNYEAR; 438*bc421551SDag-Erling Smørgrav } 439*bc421551SDag-Erling Smørgrav #ifdef XPG4_1994_04_09 440*bc421551SDag-Erling Smørgrav if ((w == 52 && 441*bc421551SDag-Erling Smørgrav t->tm_mon == TM_JANUARY) || 442*bc421551SDag-Erling Smørgrav (w == 1 && 443*bc421551SDag-Erling Smørgrav t->tm_mon == TM_DECEMBER)) 444*bc421551SDag-Erling Smørgrav w = 53; 445*bc421551SDag-Erling Smørgrav #endif /* defined XPG4_1994_04_09 */ 446*bc421551SDag-Erling Smørgrav if (*format == 'V') 447*bc421551SDag-Erling Smørgrav pt = _conv(w, "%02d", 448*bc421551SDag-Erling Smørgrav pt, ptlim); 449*bc421551SDag-Erling Smørgrav else if (*format == 'g') { 450*bc421551SDag-Erling Smørgrav *warnp = IN_ALL; 451*bc421551SDag-Erling Smørgrav pt = _yconv(year, base, 452*bc421551SDag-Erling Smørgrav false, true, 453*bc421551SDag-Erling Smørgrav pt, ptlim); 454*bc421551SDag-Erling Smørgrav } else pt = _yconv(year, base, 455*bc421551SDag-Erling Smørgrav true, true, 456*bc421551SDag-Erling Smørgrav pt, ptlim); 457*bc421551SDag-Erling Smørgrav } 458*bc421551SDag-Erling Smørgrav continue; 459*bc421551SDag-Erling Smørgrav case 'v': 460*bc421551SDag-Erling Smørgrav /* 461*bc421551SDag-Erling Smørgrav ** From Arnold Robbins' strftime version 3.0: 462*bc421551SDag-Erling Smørgrav ** "date as dd-bbb-YYYY" 463*bc421551SDag-Erling Smørgrav ** (ado, 1993-05-24) 464*bc421551SDag-Erling Smørgrav */ 465*bc421551SDag-Erling Smørgrav pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); 466*bc421551SDag-Erling Smørgrav continue; 467*bc421551SDag-Erling Smørgrav case 'W': 468*bc421551SDag-Erling Smørgrav pt = _conv((t->tm_yday + DAYSPERWEEK - 469*bc421551SDag-Erling Smørgrav (t->tm_wday ? 470*bc421551SDag-Erling Smørgrav (t->tm_wday - 1) : 471*bc421551SDag-Erling Smørgrav (DAYSPERWEEK - 1))) / DAYSPERWEEK, 472*bc421551SDag-Erling Smørgrav "%02d", pt, ptlim); 473*bc421551SDag-Erling Smørgrav continue; 474*bc421551SDag-Erling Smørgrav case 'w': 475*bc421551SDag-Erling Smørgrav pt = _conv(t->tm_wday, "%d", pt, ptlim); 476*bc421551SDag-Erling Smørgrav continue; 477*bc421551SDag-Erling Smørgrav case 'X': 478*bc421551SDag-Erling Smørgrav pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); 479*bc421551SDag-Erling Smørgrav continue; 480*bc421551SDag-Erling Smørgrav case 'x': 481*bc421551SDag-Erling Smørgrav { 482*bc421551SDag-Erling Smørgrav enum warn warn2 = IN_SOME; 483*bc421551SDag-Erling Smørgrav 484*bc421551SDag-Erling Smørgrav pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2); 485*bc421551SDag-Erling Smørgrav if (warn2 == IN_ALL) 486*bc421551SDag-Erling Smørgrav warn2 = IN_THIS; 487*bc421551SDag-Erling Smørgrav if (warn2 > *warnp) 488*bc421551SDag-Erling Smørgrav *warnp = warn2; 489*bc421551SDag-Erling Smørgrav } 490*bc421551SDag-Erling Smørgrav continue; 491*bc421551SDag-Erling Smørgrav case 'y': 492*bc421551SDag-Erling Smørgrav *warnp = IN_ALL; 493*bc421551SDag-Erling Smørgrav pt = _yconv(t->tm_year, TM_YEAR_BASE, 494*bc421551SDag-Erling Smørgrav false, true, 495*bc421551SDag-Erling Smørgrav pt, ptlim); 496*bc421551SDag-Erling Smørgrav continue; 497*bc421551SDag-Erling Smørgrav case 'Y': 498*bc421551SDag-Erling Smørgrav pt = _yconv(t->tm_year, TM_YEAR_BASE, 499*bc421551SDag-Erling Smørgrav true, true, 500*bc421551SDag-Erling Smørgrav pt, ptlim); 501*bc421551SDag-Erling Smørgrav continue; 502*bc421551SDag-Erling Smørgrav case 'Z': 503*bc421551SDag-Erling Smørgrav #ifdef TM_ZONE 504*bc421551SDag-Erling Smørgrav pt = _add(t->TM_ZONE, pt, ptlim); 505*bc421551SDag-Erling Smørgrav #elif HAVE_TZNAME 506*bc421551SDag-Erling Smørgrav if (t->tm_isdst >= 0) 507*bc421551SDag-Erling Smørgrav pt = _add(tzname[t->tm_isdst != 0], 508*bc421551SDag-Erling Smørgrav pt, ptlim); 509*bc421551SDag-Erling Smørgrav #endif 510*bc421551SDag-Erling Smørgrav /* 511*bc421551SDag-Erling Smørgrav ** C99 and later say that %Z must be 512*bc421551SDag-Erling Smørgrav ** replaced by the empty string if the 513*bc421551SDag-Erling Smørgrav ** time zone abbreviation is not 514*bc421551SDag-Erling Smørgrav ** determinable. 515*bc421551SDag-Erling Smørgrav */ 516*bc421551SDag-Erling Smørgrav continue; 517*bc421551SDag-Erling Smørgrav case 'z': 518*bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF || USG_COMPAT || ALTZONE 519*bc421551SDag-Erling Smørgrav { 520*bc421551SDag-Erling Smørgrav long diff; 521*bc421551SDag-Erling Smørgrav char const * sign; 522*bc421551SDag-Erling Smørgrav bool negative; 523*bc421551SDag-Erling Smørgrav 524*bc421551SDag-Erling Smørgrav # ifdef TM_GMTOFF 525*bc421551SDag-Erling Smørgrav diff = t->TM_GMTOFF; 526*bc421551SDag-Erling Smørgrav # else 527*bc421551SDag-Erling Smørgrav /* 528*bc421551SDag-Erling Smørgrav ** C99 and later say that the UT offset must 529*bc421551SDag-Erling Smørgrav ** be computed by looking only at 530*bc421551SDag-Erling Smørgrav ** tm_isdst. This requirement is 531*bc421551SDag-Erling Smørgrav ** incorrect, since it means the code 532*bc421551SDag-Erling Smørgrav ** must rely on magic (in this case 533*bc421551SDag-Erling Smørgrav ** altzone and timezone), and the 534*bc421551SDag-Erling Smørgrav ** magic might not have the correct 535*bc421551SDag-Erling Smørgrav ** offset. Doing things correctly is 536*bc421551SDag-Erling Smørgrav ** tricky and requires disobeying the standard; 537*bc421551SDag-Erling Smørgrav ** see GNU C strftime for details. 538*bc421551SDag-Erling Smørgrav ** For now, punt and conform to the 539*bc421551SDag-Erling Smørgrav ** standard, even though it's incorrect. 540*bc421551SDag-Erling Smørgrav ** 541*bc421551SDag-Erling Smørgrav ** C99 and later say that %z must be replaced by 542*bc421551SDag-Erling Smørgrav ** the empty string if the time zone is not 543*bc421551SDag-Erling Smørgrav ** determinable, so output nothing if the 544*bc421551SDag-Erling Smørgrav ** appropriate variables are not available. 545*bc421551SDag-Erling Smørgrav */ 546*bc421551SDag-Erling Smørgrav if (t->tm_isdst < 0) 547*bc421551SDag-Erling Smørgrav continue; 548*bc421551SDag-Erling Smørgrav if (t->tm_isdst == 0) 549*bc421551SDag-Erling Smørgrav # if USG_COMPAT 550*bc421551SDag-Erling Smørgrav diff = -timezone; 551*bc421551SDag-Erling Smørgrav # else 552*bc421551SDag-Erling Smørgrav continue; 553*bc421551SDag-Erling Smørgrav # endif 554*bc421551SDag-Erling Smørgrav else 555*bc421551SDag-Erling Smørgrav # if ALTZONE 556*bc421551SDag-Erling Smørgrav diff = -altzone; 557*bc421551SDag-Erling Smørgrav # else 558*bc421551SDag-Erling Smørgrav continue; 559*bc421551SDag-Erling Smørgrav # endif 560*bc421551SDag-Erling Smørgrav # endif 561*bc421551SDag-Erling Smørgrav negative = diff < 0; 562*bc421551SDag-Erling Smørgrav if (diff == 0) { 563*bc421551SDag-Erling Smørgrav # ifdef TM_ZONE 564*bc421551SDag-Erling Smørgrav negative = t->TM_ZONE[0] == '-'; 565*bc421551SDag-Erling Smørgrav # else 566*bc421551SDag-Erling Smørgrav negative = t->tm_isdst < 0; 567*bc421551SDag-Erling Smørgrav # if HAVE_TZNAME 568*bc421551SDag-Erling Smørgrav if (tzname[t->tm_isdst != 0][0] == '-') 569*bc421551SDag-Erling Smørgrav negative = true; 570*bc421551SDag-Erling Smørgrav # endif 571*bc421551SDag-Erling Smørgrav # endif 572*bc421551SDag-Erling Smørgrav } 573*bc421551SDag-Erling Smørgrav if (negative) { 574*bc421551SDag-Erling Smørgrav sign = "-"; 575*bc421551SDag-Erling Smørgrav diff = -diff; 576*bc421551SDag-Erling Smørgrav } else sign = "+"; 577*bc421551SDag-Erling Smørgrav pt = _add(sign, pt, ptlim); 578*bc421551SDag-Erling Smørgrav diff /= SECSPERMIN; 579*bc421551SDag-Erling Smørgrav diff = (diff / MINSPERHOUR) * 100 + 580*bc421551SDag-Erling Smørgrav (diff % MINSPERHOUR); 581*bc421551SDag-Erling Smørgrav pt = _conv(diff, "%04d", pt, ptlim); 582*bc421551SDag-Erling Smørgrav } 583*bc421551SDag-Erling Smørgrav #endif 584*bc421551SDag-Erling Smørgrav continue; 585*bc421551SDag-Erling Smørgrav case '+': 586*bc421551SDag-Erling Smørgrav pt = _fmt(Locale->date_fmt, t, pt, ptlim, 587*bc421551SDag-Erling Smørgrav warnp); 588*bc421551SDag-Erling Smørgrav continue; 589*bc421551SDag-Erling Smørgrav case '%': 590*bc421551SDag-Erling Smørgrav /* 591*bc421551SDag-Erling Smørgrav ** X311J/88-090 (4.12.3.5): if conversion char is 592*bc421551SDag-Erling Smørgrav ** undefined, behavior is undefined. Print out the 593*bc421551SDag-Erling Smørgrav ** character itself as printf(3) also does. 594*bc421551SDag-Erling Smørgrav */ 595*bc421551SDag-Erling Smørgrav default: 596*bc421551SDag-Erling Smørgrav break; 597*bc421551SDag-Erling Smørgrav } 598*bc421551SDag-Erling Smørgrav } 599*bc421551SDag-Erling Smørgrav if (pt == ptlim) 600*bc421551SDag-Erling Smørgrav break; 601*bc421551SDag-Erling Smørgrav *pt++ = *format; 602*bc421551SDag-Erling Smørgrav } 603*bc421551SDag-Erling Smørgrav return pt; 604*bc421551SDag-Erling Smørgrav } 605*bc421551SDag-Erling Smørgrav 606*bc421551SDag-Erling Smørgrav static char * 607*bc421551SDag-Erling Smørgrav _conv(int n, const char *format, char *pt, const char *ptlim) 608*bc421551SDag-Erling Smørgrav { 609*bc421551SDag-Erling Smørgrav char buf[INT_STRLEN_MAXIMUM(int) + 1]; 610*bc421551SDag-Erling Smørgrav 611*bc421551SDag-Erling Smørgrav sprintf(buf, format, n); 612*bc421551SDag-Erling Smørgrav return _add(buf, pt, ptlim); 613*bc421551SDag-Erling Smørgrav } 614*bc421551SDag-Erling Smørgrav 615*bc421551SDag-Erling Smørgrav static char * 616*bc421551SDag-Erling Smørgrav _add(const char *str, char *pt, const char *ptlim) 617*bc421551SDag-Erling Smørgrav { 618*bc421551SDag-Erling Smørgrav while (pt < ptlim && (*pt = *str++) != '\0') 619*bc421551SDag-Erling Smørgrav ++pt; 620*bc421551SDag-Erling Smørgrav return pt; 621*bc421551SDag-Erling Smørgrav } 622*bc421551SDag-Erling Smørgrav 623*bc421551SDag-Erling Smørgrav /* 624*bc421551SDag-Erling Smørgrav ** POSIX and the C Standard are unclear or inconsistent about 625*bc421551SDag-Erling Smørgrav ** what %C and %y do if the year is negative or exceeds 9999. 626*bc421551SDag-Erling Smørgrav ** Use the convention that %C concatenated with %y yields the 627*bc421551SDag-Erling Smørgrav ** same output as %Y, and that %Y contains at least 4 bytes, 628*bc421551SDag-Erling Smørgrav ** with more only if necessary. 629*bc421551SDag-Erling Smørgrav */ 630*bc421551SDag-Erling Smørgrav 631*bc421551SDag-Erling Smørgrav static char * 632*bc421551SDag-Erling Smørgrav _yconv(int a, int b, bool convert_top, bool convert_yy, 633*bc421551SDag-Erling Smørgrav char *pt, const char *ptlim) 634*bc421551SDag-Erling Smørgrav { 635*bc421551SDag-Erling Smørgrav register int lead; 636*bc421551SDag-Erling Smørgrav register int trail; 637*bc421551SDag-Erling Smørgrav 638*bc421551SDag-Erling Smørgrav int DIVISOR = 100; 639*bc421551SDag-Erling Smørgrav trail = a % DIVISOR + b % DIVISOR; 640*bc421551SDag-Erling Smørgrav lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR; 641*bc421551SDag-Erling Smørgrav trail %= DIVISOR; 642*bc421551SDag-Erling Smørgrav if (trail < 0 && lead > 0) { 643*bc421551SDag-Erling Smørgrav trail += DIVISOR; 644*bc421551SDag-Erling Smørgrav --lead; 645*bc421551SDag-Erling Smørgrav } else if (lead < 0 && trail > 0) { 646*bc421551SDag-Erling Smørgrav trail -= DIVISOR; 647*bc421551SDag-Erling Smørgrav ++lead; 648*bc421551SDag-Erling Smørgrav } 649*bc421551SDag-Erling Smørgrav if (convert_top) { 650*bc421551SDag-Erling Smørgrav if (lead == 0 && trail < 0) 651*bc421551SDag-Erling Smørgrav pt = _add("-0", pt, ptlim); 652*bc421551SDag-Erling Smørgrav else pt = _conv(lead, "%02d", pt, ptlim); 653*bc421551SDag-Erling Smørgrav } 654*bc421551SDag-Erling Smørgrav if (convert_yy) 655*bc421551SDag-Erling Smørgrav pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim); 656*bc421551SDag-Erling Smørgrav return pt; 657*bc421551SDag-Erling Smørgrav } 658