00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023
00024 #ifndef HAVE_STRFTIME
00025
00026 #ifdef _LIBC
00027 # define HAVE_LIMITS_H 1
00028 # define HAVE_MBLEN 1
00029 # define HAVE_MBRLEN 1
00030 # define HAVE_STRUCT_ERA_ENTRY 1
00031 # define HAVE_TM_GMTOFF 1
00032 # define HAVE_STRUCT_TM_TM_ZONE 1
00033 # define MULTIBYTE_IS_FORMAT_SAFE 1
00034 # define STDC_HEADERS 1
00035 # include <ansidecl.h>
00036 # include "../locale/localeinfo.h"
00037 #endif
00038
00039 #include <sys/types.h>
00040
00041 #ifdef TIME_WITH_SYS_TIME
00042 # include <sys/time.h>
00043 # include <time.h>
00044 #else
00045 # ifdef HAVE_SYS_TIME_H
00046 # include <sys/time.h>
00047 # else
00048 # include <time.h>
00049 # endif
00050 #endif
00051
00052 #if HAVE_TZNAME
00053 extern char *tzname[];
00054 #endif
00055
00056
00057
00058
00059
00060
00061
00062 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
00063
00064 #if DO_MULTIBYTE
00065 # if HAVE_MBRLEN
00066 # include <wchar.h>
00067 # else
00068
00069 # define mbstate_t int
00070 # define mbrlen(s, n, ps) mblen (s, n)
00071 # define mbsinit(ps) (*(ps) == 0)
00072 # endif
00073 static const mbstate_t mbstate_zero;
00074 #endif
00075
00076 #if HAVE_LIMITS_H
00077 # include <limits.h>
00078 #endif
00079
00080 #if STDC_HEADERS
00081 # include <stddef.h>
00082 # include <stdlib.h>
00083 # include <string.h>
00084 #else
00085 # define memcpy(d, s, n) bcopy (s, d, n)
00086 #endif
00087
00088 #ifndef __P
00089 #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
00090 #define __P(args) args
00091 #else
00092 #define __P(args) ()
00093 #endif
00094 #endif
00095
00096 #ifndef PTR
00097 #ifdef __STDC__
00098 #define PTR void *
00099 #else
00100 #define PTR char *
00101 #endif
00102 #endif
00103
00104 #ifndef CHAR_BIT
00105 #define CHAR_BIT 8
00106 #endif
00107
00108 #define TYPE_SIGNED(t) ((t) -1 < 0)
00109
00110
00111
00112
00113
00114
00115 #define INT_STRLEN_BOUND(t) \
00116 ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
00117
00118 #define TM_YEAR_BASE 1900
00119
00120 #ifndef __isleap
00121
00122
00123 #define __isleap(year) \
00124 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
00125 #endif
00126
00127
00128 #ifdef _LIBC
00129 # define gmtime_r __gmtime_r
00130 # define localtime_r __localtime_r
00131 #else
00132 # if ! HAVE_LOCALTIME_R
00133 # if ! HAVE_TM_GMTOFF
00134
00135 #define gmtime_r my_gmtime_r
00136 static struct tm *gmtime_r __P ((const time_t *, struct tm *));
00137 static struct tm *
00138 gmtime_r (t, tp)
00139 const time_t *t;
00140 struct tm *tp;
00141 {
00142 struct tm *l = gmtime (t);
00143 if (! l)
00144 return 0;
00145 *tp = *l;
00146 return tp;
00147 }
00148 # endif
00149
00150
00151 #define localtime_r my_localtime_r
00152 static struct tm *localtime_r __P ((const time_t *, struct tm *));
00153 static struct tm *
00154 localtime_r (t, tp)
00155 const time_t *t;
00156 struct tm *tp;
00157 {
00158 struct tm *l = localtime (t);
00159 if (! l)
00160 return 0;
00161 *tp = *l;
00162 return tp;
00163 }
00164 # endif
00165 #endif
00166
00167
00168 #define add(n, f) \
00169 do \
00170 { \
00171 i += (n); \
00172 if (i >= maxsize) \
00173 return 0; \
00174 else \
00175 if (p) \
00176 { \
00177 f; \
00178 p += (n); \
00179 } \
00180 } while (0)
00181 #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
00182
00183 #if ! HAVE_TM_GMTOFF
00184
00185
00186 static int tm_diff __P ((const struct tm *, const struct tm *));
00187 static int
00188 tm_diff (a, b)
00189 const struct tm *a;
00190 const struct tm *b;
00191 {
00192
00193
00194
00195 int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
00196 int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
00197 int a100 = a4 / 25 - (a4 % 25 < 0);
00198 int b100 = b4 / 25 - (b4 % 25 < 0);
00199 int a400 = a100 >> 2;
00200 int b400 = b100 >> 2;
00201 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
00202 int years = a->tm_year - b->tm_year;
00203 int days = (365 * years + intervening_leap_days
00204 + (a->tm_yday - b->tm_yday));
00205 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
00206 + (a->tm_min - b->tm_min))
00207 + (a->tm_sec - b->tm_sec));
00208 }
00209 #endif
00210
00211
00212
00213
00214
00215
00216
00217 #define ISO_WEEK_START_WDAY 1
00218 #define ISO_WEEK1_WDAY 4
00219 #define YDAY_MINIMUM (-366)
00220 static int iso_week_days __P ((int, int));
00221 #ifdef __GNUC__
00222 inline
00223 #endif
00224 static int
00225 iso_week_days (yday, wday)
00226 int yday;
00227 int wday;
00228 {
00229
00230 int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
00231 return (yday
00232 - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
00233 + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
00234 }
00235
00236
00237 #ifndef _NL_CURRENT
00238 static char const weekday_name[][10] =
00239 {
00240 "Sunday", "Monday", "Tuesday", "Wednesday",
00241 "Thursday", "Friday", "Saturday"
00242 };
00243 static char const month_name[][10] =
00244 {
00245 "January", "February", "March", "April", "May", "June",
00246 "July", "August", "September", "October", "November", "December"
00247 };
00248 #endif
00249
00250
00251
00252
00253
00254
00255
00256 size_t
00257 strftime (s, maxsize, format, tp)
00258 char *s;
00259 size_t maxsize;
00260 const char *format;
00261 register const struct tm *tp;
00262 {
00263 int hour12 = tp->tm_hour;
00264 #ifdef _NL_CURRENT
00265 const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
00266 const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
00267 const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
00268 const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
00269 const char *const ampm = _NL_CURRENT (LC_TIME,
00270 hour12 > 11 ? PM_STR : AM_STR);
00271 size_t aw_len = strlen (a_wkday);
00272 size_t am_len = strlen (a_month);
00273 size_t ap_len = strlen (ampm);
00274 #else
00275 const char *const f_wkday = weekday_name[tp->tm_wday];
00276 const char *const f_month = month_name[tp->tm_mon];
00277 const char *const a_wkday = f_wkday;
00278 const char *const a_month = f_month;
00279 const char *const ampm = "AMPM" + 2 * (hour12 > 11);
00280 size_t aw_len = 3;
00281 size_t am_len = 3;
00282 size_t ap_len = 2;
00283 #endif
00284 size_t wkday_len = strlen (f_wkday);
00285 size_t month_len = strlen (f_month);
00286 const char *zone;
00287 size_t zonelen;
00288 register size_t i = 0;
00289 register char *p = s;
00290 register const char *f;
00291
00292 zone = 0;
00293 #if HAVE_STRUCT_TM_TM_ZONE
00294 zone = (const char *) tp->tm_zone;
00295 #endif
00296 #if HAVE_TZNAME
00297 if (!(zone && *zone) && tp->tm_isdst >= 0)
00298 zone = tzname[tp->tm_isdst];
00299 #endif
00300 if (! zone)
00301 zone = "";
00302
00303 zonelen = strlen (zone);
00304
00305 if (hour12 > 12)
00306 hour12 -= 12;
00307 else
00308 if (hour12 == 0) hour12 = 12;
00309
00310 for (f = format; *f != '\0'; ++f)
00311 {
00312 int pad;
00313 int modifier;
00314 int digits;
00315 int number_value;
00316 int negative_number;
00317 const char *subfmt;
00318 char *bufp;
00319 char buf[1 + (sizeof (int) < sizeof (time_t)
00320 ? INT_STRLEN_BOUND (time_t)
00321 : INT_STRLEN_BOUND (int))];
00322
00323 #if DO_MULTIBYTE
00324
00325 switch (*f)
00326 {
00327 case '%':
00328 break;
00329
00330 case '\a': case '\b': case '\t': case '\n':
00331 case '\v': case '\f': case '\r':
00332 case ' ': case '!': case '"': case '#': case '&': case'\'':
00333 case '(': case ')': case '*': case '+': case ',': case '-':
00334 case '.': case '/': case '0': case '1': case '2': case '3':
00335 case '4': case '5': case '6': case '7': case '8': case '9':
00336 case ':': case ';': case '<': case '=': case '>': case '?':
00337 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
00338 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
00339 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
00340 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
00341 case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
00342 case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
00343 case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
00344 case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
00345 case 'r': case 's': case 't': case 'u': case 'v': case 'w':
00346 case 'x': case 'y': case 'z': case '{': case '|': case '}':
00347 case '~':
00348
00349
00350
00351
00352 add (1, *p = *f);
00353 continue;
00354
00355 default:
00356
00357
00358 {
00359 mbstate_t mbstate = mbstate_zero;
00360 size_t len = 0;
00361
00362 do
00363 {
00364 size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
00365
00366 if (bytes == 0)
00367 break;
00368
00369 if (bytes == (size_t) -2 || bytes == (size_t) -1)
00370 {
00371 len++;
00372 break;
00373 }
00374
00375 len += bytes;
00376 }
00377 while (! mbsinit (&mbstate));
00378
00379 cpy (len, f);
00380 continue;
00381 }
00382 }
00383
00384 #else
00385
00386
00387
00388 if (*f != '%')
00389 {
00390 add (1, *p = *f);
00391 continue;
00392 }
00393
00394 #endif
00395
00396
00397 ++f;
00398 switch (*f)
00399 {
00400 case '_':
00401 case '-':
00402 pad = *f++;
00403 break;
00404
00405 default:
00406 pad = 0;
00407 break;
00408 }
00409
00410
00411 switch (*f)
00412 {
00413 case 'E':
00414 case 'O':
00415 modifier = *f++;
00416 break;
00417
00418 default:
00419 modifier = 0;
00420 break;
00421 }
00422
00423
00424 switch (*f)
00425 {
00426 #define DO_NUMBER(d, v) \
00427 digits = d; number_value = v; goto do_number
00428 #define DO_NUMBER_SPACEPAD(d, v) \
00429 digits = d; number_value = v; goto do_number_spacepad
00430
00431 case '%':
00432 if (modifier != 0)
00433 goto bad_format;
00434 add (1, *p = *f);
00435 break;
00436
00437 case 'a':
00438 if (modifier != 0)
00439 goto bad_format;
00440 cpy (aw_len, a_wkday);
00441 break;
00442
00443 case 'A':
00444 if (modifier != 0)
00445 goto bad_format;
00446 cpy (wkday_len, f_wkday);
00447 break;
00448
00449 case 'b':
00450 case 'h':
00451 if (modifier != 0)
00452 goto bad_format;
00453 cpy (am_len, a_month);
00454 break;
00455
00456 case 'B':
00457 if (modifier != 0)
00458 goto bad_format;
00459 cpy (month_len, f_month);
00460 break;
00461
00462 case 'c':
00463 if (modifier == 'O')
00464 goto bad_format;
00465 #ifdef _NL_CURRENT
00466 if (! (modifier == 'E'
00467 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
00468 subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
00469 #else
00470 subfmt = "%a %b %e %H:%M:%S %Y";
00471 #endif
00472
00473 subformat:
00474 {
00475 size_t len = strftime (p, maxsize - i, subfmt, tp);
00476 if (len == 0 && *subfmt)
00477 return 0;
00478 add (len, ;);
00479 }
00480 break;
00481
00482 case 'C':
00483 if (modifier == 'O')
00484 goto bad_format;
00485 #if HAVE_STRUCT_ERA_ENTRY
00486 if (modifier == 'E')
00487 {
00488 struct era_entry *era = _nl_get_era_entry (tp);
00489 if (era)
00490 {
00491 size_t len = strlen (era->name_fmt);
00492 cpy (len, era->name_fmt);
00493 break;
00494 }
00495 }
00496 #endif
00497 {
00498 int year = tp->tm_year + TM_YEAR_BASE;
00499 DO_NUMBER (1, year / 100 - (year % 100 < 0));
00500 }
00501
00502 case 'x':
00503 if (modifier == 'O')
00504 goto bad_format;
00505 #ifdef _NL_CURRENT
00506 if (! (modifier == 'E'
00507 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
00508 subfmt = _NL_CURRENT (LC_TIME, D_FMT);
00509 goto subformat;
00510 #endif
00511
00512 case 'D':
00513 if (modifier != 0)
00514 goto bad_format;
00515 subfmt = "%m/%d/%y";
00516 goto subformat;
00517
00518 case 'd':
00519 if (modifier == 'E')
00520 goto bad_format;
00521
00522 DO_NUMBER (2, tp->tm_mday);
00523
00524 case 'e':
00525 if (modifier == 'E')
00526 goto bad_format;
00527
00528 DO_NUMBER_SPACEPAD (2, tp->tm_mday);
00529
00530
00531
00532
00533 do_number_spacepad:
00534
00535 pad = '_';
00536
00537 do_number:
00538
00539
00540 #ifdef _NL_CURRENT
00541 if (modifier == 'O' && 0 <= number_value)
00542 {
00543
00544
00545 const char *cp = _nl_get_alt_digit (number_value);
00546
00547 if (cp != NULL)
00548 {
00549 size_t digitlen = strlen (cp);
00550 if (digitlen != 0)
00551 {
00552 cpy (digitlen, cp);
00553 break;
00554 }
00555 }
00556 }
00557 #endif
00558 {
00559 unsigned int u = number_value;
00560
00561 bufp = buf + sizeof (buf);
00562 negative_number = number_value < 0;
00563
00564 if (negative_number)
00565 u = -u;
00566
00567 do
00568 *--bufp = u % 10 + '0';
00569 while ((u /= 10) != 0);
00570 }
00571
00572 do_number_sign_and_padding:
00573 if (negative_number)
00574 *--bufp = '-';
00575
00576 if (pad != '-')
00577 {
00578 int padding = digits - (buf + sizeof (buf) - bufp);
00579
00580 if (pad == '_')
00581 {
00582 while (0 < padding--)
00583 *--bufp = ' ';
00584 }
00585 else
00586 {
00587 bufp += negative_number;
00588 while (0 < padding--)
00589 *--bufp = '0';
00590 if (negative_number)
00591 *--bufp = '-';
00592 }
00593 }
00594
00595 cpy (buf + sizeof (buf) - bufp, bufp);
00596 break;
00597
00598
00599 case 'H':
00600 if (modifier == 'E')
00601 goto bad_format;
00602
00603 DO_NUMBER (2, tp->tm_hour);
00604
00605 case 'I':
00606 if (modifier == 'E')
00607 goto bad_format;
00608
00609 DO_NUMBER (2, hour12);
00610
00611 case 'k':
00612 if (modifier == 'E')
00613 goto bad_format;
00614
00615 DO_NUMBER_SPACEPAD (2, tp->tm_hour);
00616
00617 case 'l':
00618 if (modifier == 'E')
00619 goto bad_format;
00620
00621 DO_NUMBER_SPACEPAD (2, hour12);
00622
00623 case 'j':
00624 if (modifier == 'E')
00625 goto bad_format;
00626
00627 DO_NUMBER (3, 1 + tp->tm_yday);
00628
00629 case 'M':
00630 if (modifier == 'E')
00631 goto bad_format;
00632
00633 DO_NUMBER (2, tp->tm_min);
00634
00635 case 'm':
00636 if (modifier == 'E')
00637 goto bad_format;
00638
00639 DO_NUMBER (2, tp->tm_mon + 1);
00640
00641 case 'n':
00642 add (1, *p = '\n');
00643 break;
00644
00645 case 'p':
00646 cpy (ap_len, ampm);
00647 break;
00648
00649 case 'R':
00650 subfmt = "%H:%M";
00651 goto subformat;
00652
00653 case 'r':
00654 #ifdef _NL_CURRENT
00655 if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
00656 #endif
00657 subfmt = "%I:%M:%S %p";
00658 goto subformat;
00659
00660 case 'S':
00661 if (modifier == 'E')
00662 goto bad_format;
00663
00664 DO_NUMBER (2, tp->tm_sec);
00665
00666 case 's':
00667 {
00668 struct tm ltm;
00669 time_t t;
00670
00671 ltm = *tp;
00672 t = mktime (<m);
00673
00674
00675
00676
00677 bufp = buf + sizeof (buf);
00678 negative_number = t < 0;
00679
00680 do
00681 {
00682 int d = t % 10;
00683 t /= 10;
00684
00685 if (negative_number)
00686 {
00687 d = -d;
00688
00689
00690 if (0 < -1 % 10 && d < 0)
00691 {
00692 t++;
00693 d += 10;
00694 }
00695 }
00696
00697 *--bufp = d + '0';
00698 }
00699 while (t != 0);
00700
00701 digits = 1;
00702 goto do_number_sign_and_padding;
00703 }
00704
00705 case 'X':
00706 if (modifier == 'O')
00707 goto bad_format;
00708 #ifdef _NL_CURRENT
00709 if (! (modifier == 'E'
00710 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
00711 subfmt = _NL_CURRENT (LC_TIME, T_FMT);
00712 goto subformat;
00713 #endif
00714
00715 case 'T':
00716 subfmt = "%H:%M:%S";
00717 goto subformat;
00718
00719 case 't':
00720 add (1, *p = '\t');
00721 break;
00722
00723 case 'u':
00724 DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
00725
00726 case 'U':
00727 if (modifier == 'E')
00728 goto bad_format;
00729
00730 DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
00731
00732 case 'V':
00733 case 'g':
00734 case 'G':
00735 if (modifier == 'E')
00736 goto bad_format;
00737 {
00738 int year = tp->tm_year + TM_YEAR_BASE;
00739 int days = iso_week_days (tp->tm_yday, tp->tm_wday);
00740
00741 if (days < 0)
00742 {
00743
00744 year--;
00745 days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
00746 tp->tm_wday);
00747 }
00748 else
00749 {
00750 int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
00751 tp->tm_wday);
00752 if (0 <= d)
00753 {
00754
00755 year++;
00756 days = d;
00757 }
00758 }
00759
00760 switch (*f)
00761 {
00762 case 'g':
00763 DO_NUMBER (2, (year % 100 + 100) % 100);
00764
00765 case 'G':
00766 DO_NUMBER (1, year);
00767
00768 default:
00769 DO_NUMBER (2, days / 7 + 1);
00770 }
00771 }
00772
00773 case 'W':
00774 if (modifier == 'E')
00775 goto bad_format;
00776
00777 DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
00778
00779 case 'w':
00780 if (modifier == 'E')
00781 goto bad_format;
00782
00783 DO_NUMBER (1, tp->tm_wday);
00784
00785 case 'Y':
00786 #if HAVE_STRUCT_ERA_ENTRY
00787 if (modifier == 'E')
00788 {
00789 struct era_entry *era = _nl_get_era_entry (tp);
00790 if (era)
00791 {
00792 subfmt = strchr (era->name_fmt, '\0') + 1;
00793 goto subformat;
00794 }
00795 }
00796 #endif
00797 if (modifier == 'O')
00798 goto bad_format;
00799 else
00800 DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
00801
00802 case 'y':
00803 #if HAVE_STRUCT_ERA_ENTRY
00804 if (modifier == 'E')
00805 {
00806 struct era_entry *era = _nl_get_era_entry (tp);
00807 if (era)
00808 {
00809 int delta = tp->tm_year - era->start_date[0];
00810 DO_NUMBER (1, (era->offset
00811 + (era->direction == '-' ? -delta : delta)));
00812 }
00813 }
00814 #endif
00815 DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
00816
00817 case 'Z':
00818 cpy (zonelen, zone);
00819 break;
00820
00821 case 'z':
00822 if (tp->tm_isdst < 0)
00823 break;
00824
00825 {
00826 int diff;
00827 #if HAVE_TM_GMTOFF
00828 diff = tp->tm_gmtoff;
00829 #else
00830 struct tm gtm;
00831 struct tm ltm;
00832 time_t lt;
00833
00834 ltm = *tp;
00835 lt = mktime (<m);
00836
00837 if (lt == (time_t) -1)
00838 {
00839
00840
00841
00842 struct tm tm;
00843 localtime_r (<, &tm);
00844
00845 if ((ltm.tm_sec ^ tm.tm_sec)
00846 | (ltm.tm_min ^ tm.tm_min)
00847 | (ltm.tm_hour ^ tm.tm_hour)
00848 | (ltm.tm_mday ^ tm.tm_mday)
00849 | (ltm.tm_mon ^ tm.tm_mon)
00850 | (ltm.tm_year ^ tm.tm_year))
00851 break;
00852 }
00853
00854 if (! gmtime_r (<, >m))
00855 break;
00856
00857 diff = tm_diff (<m, >m);
00858 #endif
00859
00860 if (diff < 0)
00861 {
00862 add (1, *p = '-');
00863 diff = -diff;
00864 }
00865 else
00866 add (1, *p = '+');
00867
00868 diff /= 60;
00869 DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
00870 }
00871
00872 case '\0':
00873 --f;
00874
00875 default:
00876
00877
00878
00879 bad_format:
00880 {
00881 int flen;
00882 for (flen = 1; f[1 - flen] != '%'; flen++)
00883 continue;
00884 cpy (flen, &f[1 - flen]);
00885 }
00886 break;
00887 }
00888 }
00889
00890 if (p)
00891 *p = '\0';
00892 return i;
00893 }
00894
00895 #endif