Mercurial > pidgin
comparison libgaim/protocols/msn/msn-utils.c @ 20392:9ba7dee775e1
The first msn-p13-merge-head.diff.gz from SF Patch #1621854 from Ka-Hing Cheung.
"uploaded a diff, this diff is unchanged from the last tarball that I
previously uploaded, except that it's against HEAD. This should be a little
easier for most people."
(This was apparently msn-p13-merge-head.diff, which SourceForge didn't allow to
be uploaded.)
PLUS
"Updated the diff with basically no change, except with simom's icon fix.
The previous diff was broken because some of the files were not added"
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Sun, 15 Apr 2007 03:01:41 +0000 |
parents | 0b0ecee55091 |
children |
comparison
equal
deleted
inserted
replaced
20391:0b0ecee55091 | 20392:9ba7dee775e1 |
---|---|
21 * along with this program; if not, write to the Free Software | 21 * along with this program; if not, write to the Free Software |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 */ | 23 */ |
24 #include "msn.h" | 24 #include "msn.h" |
25 #include "msn-utils.h" | 25 #include "msn-utils.h" |
26 #include "time.h" | |
27 //#include <openssl/md5.h> | |
28 | |
29 char *rand_guid(void); | |
30 | |
31 /************************************************************************** | |
32 * Util | |
33 **************************************************************************/ | |
34 char * | |
35 rand_guid() | |
36 { | |
37 return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", | |
38 rand() % 0xAAFF + 0x1111, | |
39 rand() % 0xAAFF + 0x1111, | |
40 rand() % 0xAAFF + 0x1111, | |
41 rand() % 0xAAFF + 0x1111, | |
42 rand() % 0xAAFF + 0x1111, | |
43 rand() % 0xAAFF + 0x1111, | |
44 rand() % 0xAAFF + 0x1111, | |
45 rand() % 0xAAFF + 0x1111); | |
46 } | |
47 | 26 |
48 void | 27 void |
49 msn_parse_format(const char *mime, char **pre_ret, char **post_ret) | 28 msn_parse_format(const char *mime, char **pre_ret, char **post_ret) |
50 { | 29 { |
51 char *cur; | 30 char *cur; |
144 | 123 |
145 if (post_ret != NULL) | 124 if (post_ret != NULL) |
146 *post_ret = cur; | 125 *post_ret = cur; |
147 else | 126 else |
148 g_free(cur); | 127 g_free(cur); |
149 } | |
150 | |
151 /*encode the str to RFC2047 style | |
152 * Currently only support the UTF-8 and base64 encode | |
153 */ | |
154 char * | |
155 msn_encode_mime(const char *str) | |
156 { | |
157 char *base64; | |
158 | |
159 base64 = gaim_base64_encode((guchar *)str, strlen(str)); | |
160 return g_strdup_printf("=?utf-8?B?%s?=", base64); | |
161 } | 128 } |
162 | 129 |
163 /* | 130 /* |
164 * We need this because we're only supposed to encode spaces in the font | 131 * We need this because we're only supposed to encode spaces in the font |
165 * names. gaim_url_encode() isn't acceptable. | 132 * names. gaim_url_encode() isn't acceptable. |
382 char *c; | 349 char *c; |
383 int port; | 350 int port; |
384 | 351 |
385 host = g_strdup(str); | 352 host = g_strdup(str); |
386 | 353 |
387 if ((c = strchr(host, ':')) != NULL){ | 354 if ((c = strchr(host, ':')) != NULL) |
355 { | |
388 *c = '\0'; | 356 *c = '\0'; |
389 port = atoi(c + 1); | 357 port = atoi(c + 1); |
390 }else{ | 358 } |
359 else | |
391 port = 1863; | 360 port = 1863; |
392 } | |
393 | 361 |
394 *ret_host = host; | 362 *ret_host = host; |
395 *ret_port = port; | 363 *ret_port = port; |
396 } | 364 } |
397 /*************************************************************************** | |
398 * MSN Time Related Funciton | |
399 ***************************************************************************/ | |
400 #if 0 | |
401 int | |
402 msn_convert_iso8601(const char *timestr,struct tm tm_time) | |
403 { | |
404 char temp[64]; | |
405 struct tm ctime; | |
406 time_t ts; | |
407 | |
408 gaim_debug_info("MaYuan","convert string is{%s}\n",timestr); | |
409 tzset(); | |
410 /*copy string first*/ | |
411 memset(temp, 0, sizeof(temp)); | |
412 strncpy(temp, timestr, strlen(timestr)); | |
413 | |
414 /*convert via strptime()*/ | |
415 memset(&ctime, 0, sizeof(struct tm)); | |
416 strptime(temp, "%d %b %Y %T %Z", &ctime); | |
417 ts = mktime(&ctime) - timezone; | |
418 localtime_r(&ts, tm_time); | |
419 } | |
420 #endif | |
421 | |
422 /*************************************************************************** | |
423 * MSN Challenge Computing Function | |
424 ***************************************************************************/ | |
425 /*check the edian of system*/ | |
426 int | |
427 isBigEndian(void) | |
428 { | |
429 short int word = 0x0100; | |
430 char *byte = (char *)&word; | |
431 | |
432 return(byte[0]); | |
433 } | |
434 | |
435 /*swap utility*/ | |
436 unsigned int | |
437 swapInt(unsigned int dw) | |
438 { | |
439 unsigned int tmp; | |
440 tmp = (dw & 0x000000FF); | |
441 tmp = ((dw & 0x0000FF00) >> 0x08) | (tmp << 0x08); | |
442 tmp = ((dw & 0x00FF0000) >> 0x10) | (tmp << 0x08); | |
443 tmp = ((dw & 0xFF000000) >> 0x18) | (tmp << 0x08); | |
444 return(tmp); | |
445 } | |
446 | |
447 /* | |
448 * Handle MSN Chanllege computation | |
449 *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges | |
450 */ | |
451 #define BUFSIZE 256 | |
452 void | |
453 msn_handle_chl(char *input, char *output) | |
454 { | |
455 GaimCipher *cipher; | |
456 GaimCipherContext *context; | |
457 char *productKey = MSNP13_WLM_PRODUCT_KEY, | |
458 *productID = MSNP13_WLM_PRODUCT_ID, | |
459 *hexChars = "0123456789abcdef", | |
460 buf[BUFSIZE]; | |
461 unsigned char md5Hash[16], *newHash; | |
462 unsigned int *md5Parts, *chlStringParts, newHashParts[5]; | |
463 | |
464 long long nHigh=0, nLow=0; | |
465 | |
466 int i, bigEndian; | |
467 | |
468 /* Determine our endianess */ | |
469 bigEndian = isBigEndian(); | |
470 | |
471 /* Create the MD5 hash by using Gaim MD5 algorithm*/ | |
472 cipher = gaim_ciphers_find_cipher("md5"); | |
473 context = gaim_cipher_context_new(cipher, NULL); | |
474 | |
475 gaim_cipher_context_append(context, (const guchar *)input, | |
476 strlen(input)); | |
477 gaim_cipher_context_append(context, (const guchar *)productKey, | |
478 strlen(productKey)); | |
479 gaim_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); | |
480 gaim_cipher_context_destroy(context); | |
481 | |
482 /* Split it into four integers */ | |
483 md5Parts = (unsigned int *)md5Hash; | |
484 for(i=0; i<4; i++){ | |
485 /* check for endianess */ | |
486 if(bigEndian) | |
487 md5Parts[i] = swapInt(md5Parts[i]); | |
488 | |
489 /* & each integer with 0x7FFFFFFF */ | |
490 /* and save one unmodified array for later */ | |
491 newHashParts[i] = md5Parts[i]; | |
492 md5Parts[i] &= 0x7FFFFFFF; | |
493 } | |
494 | |
495 /* make a new string and pad with '0' */ | |
496 snprintf(buf, BUFSIZE-5, "%s%s", input, productID); | |
497 i = strlen(buf); | |
498 memset(&buf[i], '0', 8 - (i % 8)); | |
499 buf[i + (8 - (i % 8))]='\0'; | |
500 | |
501 /* split into integers */ | |
502 chlStringParts = (unsigned int *)buf; | |
503 | |
504 /* this is magic */ | |
505 for (i=0; i<(strlen(buf)/4)-1; i+=2){ | |
506 long long temp; | |
507 | |
508 if(bigEndian){ | |
509 chlStringParts[i] = swapInt(chlStringParts[i]); | |
510 chlStringParts[i+1] = swapInt(chlStringParts[i+1]); | |
511 } | |
512 | |
513 temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; | |
514 nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; | |
515 nLow=nLow + nHigh + temp; | |
516 } | |
517 nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF; | |
518 nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF; | |
519 | |
520 newHashParts[0]^=nHigh; | |
521 newHashParts[1]^=nLow; | |
522 newHashParts[2]^=nHigh; | |
523 newHashParts[3]^=nLow; | |
524 | |
525 /* swap more bytes if big endian */ | |
526 for(i=0; i<4 && bigEndian; i++) | |
527 newHashParts[i] = swapInt(newHashParts[i]); | |
528 | |
529 /* make a string of the parts */ | |
530 newHash = (unsigned char *)newHashParts; | |
531 | |
532 /* convert to hexadecimal */ | |
533 for (i=0; i<16; i++) | |
534 { | |
535 output[i*2]=hexChars[(newHash[i]>>4)&0xF]; | |
536 output[(i*2)+1]=hexChars[newHash[i]&0xF]; | |
537 } | |
538 | |
539 output[32]='\0'; | |
540 | |
541 // gaim_debug_info("MaYuan","chl output{%s}\n",output); | |
542 } | |
543 | |
544 #if (!defined(_XOPEN_SOURCE))||defined(_WIN32) | |
545 | |
546 #ifndef __P | |
547 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__) | |
548 # define __P(args) args | |
549 # else | |
550 # define __P(args) () | |
551 # endif /* GCC. */ | |
552 #endif /* Not __P. */ | |
553 | |
554 #if defined(HAVE_LOCALTIME_R) && ! HAVE_LOCALTIME_R && ! defined localtime_r | |
555 # ifdef _LIBC | |
556 # define localtime_r __localtime_r | |
557 # else | |
558 /* Approximate localtime_r as best we can in its absence. */ | |
559 # define localtime_r my_localtime_r | |
560 static struct tm *localtime_r __P ((const time_t *, struct tm *)); | |
561 static struct tm * | |
562 localtime_r (t, tp) | |
563 const time_t *t; | |
564 struct tm *tp; | |
565 { | |
566 struct tm *l = localtime (t); | |
567 if (! l) | |
568 return 0; | |
569 *tp = *l; | |
570 return tp; | |
571 } | |
572 # endif /* ! _LIBC */ | |
573 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ | |
574 | |
575 | |
576 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL | |
577 | |
578 #if defined __GNUC__ && __GNUC__ >= 2 | |
579 # define match_string(cs1, s2) \ | |
580 ({ size_t len = strlen (cs1); \ | |
581 int result = strncasecmp ((cs1), (s2), len) == 0; \ | |
582 if (result) (s2) += len; \ | |
583 result; }) | |
584 #else | |
585 /* Oh come on. Get a reasonable compiler. */ | |
586 # define match_string(cs1, s2) \ | |
587 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) | |
588 #endif | |
589 | |
590 /* We intentionally do not use isdigit() for testing because this will | |
591 lead to problems with the wide character version. */ | |
592 #define get_number(from, to, n) \ | |
593 do { \ | |
594 int __n = n; \ | |
595 val = 0; \ | |
596 while (*rp == ' ') \ | |
597 ++rp; \ | |
598 if ((*rp < '0') || (*rp > '9')) \ | |
599 return NULL; \ | |
600 do { \ | |
601 val *= 10; \ | |
602 val += *rp++ - '0'; \ | |
603 } while ((--__n > 0) && (val * 10 <= to) && (*rp >= '0') && (*rp <= '9')); \ | |
604 if ((val < from) || (val > to)) \ | |
605 return NULL; \ | |
606 } while (0) | |
607 | |
608 #ifdef _NL_CURRENT | |
609 # define get_alt_number(from, to, n) \ | |
610 ({ \ | |
611 __label__ do_normal; \ | |
612 if (*decided != raw) \ | |
613 { \ | |
614 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \ | |
615 int __n = n; \ | |
616 int any = 0; \ | |
617 while (*rp == ' ') \ | |
618 ++rp; \ | |
619 val = 0; \ | |
620 do { \ | |
621 val *= 10; \ | |
622 while (*alts != '\0') \ | |
623 { \ | |
624 size_t len = strlen (alts); \ | |
625 if (strncasecmp (alts, rp, len) == 0) \ | |
626 break; \ | |
627 alts += len + 1; \ | |
628 ++val; \ | |
629 } \ | |
630 if (*alts == '\0') \ | |
631 { \ | |
632 if (*decided == not && ! any) \ | |
633 goto do_normal; \ | |
634 /* If we haven't read anything it's an error. */ \ | |
635 if (! any) \ | |
636 return NULL; \ | |
637 /* Correct the premature multiplication. */ \ | |
638 val /= 10; \ | |
639 break; \ | |
640 } \ | |
641 else \ | |
642 *decided = loc; \ | |
643 } while (--__n > 0 && val * 10 <= to); \ | |
644 if (val < from || val > to) \ | |
645 return NULL; \ | |
646 } \ | |
647 else \ | |
648 { \ | |
649 do_normal: \ | |
650 get_number (from, to, n); \ | |
651 } \ | |
652 0; \ | |
653 }) | |
654 #else | |
655 # define get_alt_number(from, to, n) \ | |
656 /* We don't have the alternate representation. */ \ | |
657 get_number(from, to, n) | |
658 #endif | |
659 | |
660 #define recursive(new_fmt) \ | |
661 (*(new_fmt) != '\0' \ | |
662 && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL) | |
663 | |
664 | |
665 #ifdef _LIBC | |
666 /* This is defined in locale/C-time.c in the GNU libc. */ | |
667 extern const struct locale_data _nl_C_LC_TIME; | |
668 extern const unsigned short int __mon_yday[2][13]; | |
669 | |
670 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string) | |
671 # define ab_weekday_name \ | |
672 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string) | |
673 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string) | |
674 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string) | |
675 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string) | |
676 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string) | |
677 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string) | |
678 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string) | |
679 # define HERE_T_FMT_AMPM \ | |
680 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string) | |
681 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string) | |
682 | |
683 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n) | |
684 #else | |
685 static char const weekday_name[][10] = | |
686 { | |
687 "Sunday", "Monday", "Tuesday", "Wednesday", | |
688 "Thursday", "Friday", "Saturday" | |
689 }; | |
690 static char const ab_weekday_name[][4] = | |
691 { | |
692 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | |
693 }; | |
694 static char const month_name[][10] = | |
695 { | |
696 "January", "February", "March", "April", "May", "June", | |
697 "July", "August", "September", "October", "November", "December" | |
698 }; | |
699 static char const ab_month_name[][4] = | |
700 { | |
701 "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
702 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | |
703 }; | |
704 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" | |
705 # define HERE_D_FMT "%m/%d/%y" | |
706 # define HERE_AM_STR "AM" | |
707 # define HERE_PM_STR "PM" | |
708 # define HERE_T_FMT_AMPM "%I:%M:%S %p" | |
709 # define HERE_T_FMT "%H:%M:%S" | |
710 | |
711 const unsigned short int __mon_yday[2][13] = | |
712 { | |
713 /* Normal years. */ | |
714 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | |
715 /* Leap years. */ | |
716 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | |
717 }; | |
718 #endif | |
719 | |
720 /* Status of lookup: do we use the locale data or the raw data? */ | |
721 enum locale_status { not, loc, raw }; | |
722 | |
723 | |
724 #ifndef __isleap | |
725 /* Nonzero if YEAR is a leap year (every 4 years, | |
726 except every 100th isn't, and every 400th is). */ | |
727 # define __isleap(year) \ | |
728 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) | |
729 #endif | |
730 | |
731 /* Compute the day of the week. */ | |
732 static void | |
733 day_of_the_week (struct tm *tm) | |
734 { | |
735 /* We know that January 1st 1970 was a Thursday (= 4). Compute the | |
736 the difference between this data in the one on TM and so determine | |
737 the weekday. */ | |
738 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); | |
739 int wday = (-473 | |
740 + (365 * (tm->tm_year - 70)) | |
741 + (corr_year / 4) | |
742 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) | |
743 + (((corr_year / 4) / 25) / 4) | |
744 + __mon_yday[0][tm->tm_mon] | |
745 + tm->tm_mday - 1); | |
746 tm->tm_wday = ((wday % 7) + 7) % 7; | |
747 } | |
748 | |
749 /* Compute the day of the year. */ | |
750 static void | |
751 day_of_the_year (struct tm *tm) | |
752 { | |
753 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] | |
754 + (tm->tm_mday - 1)); | |
755 } | |
756 | |
757 static char * | |
758 #ifdef _LIBC | |
759 internal_function | |
760 #endif | |
761 strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm, | |
762 enum locale_status *decided, int era_cnt)); | |
763 | |
764 static char * | |
765 #ifdef _LIBC | |
766 internal_function | |
767 #endif | |
768 strptime_internal (rp, fmt, tm, decided, era_cnt) | |
769 const char *rp; | |
770 const char *fmt; | |
771 struct tm *tm; | |
772 enum locale_status *decided; | |
773 int era_cnt; | |
774 { | |
775 const char *rp_backup; | |
776 int cnt; | |
777 size_t val; | |
778 int have_I, is_pm; | |
779 int century, want_century; | |
780 int want_era; | |
781 int have_wday, want_xday; | |
782 int have_yday; | |
783 int have_mon, have_mday; | |
784 #ifdef _NL_CURRENT | |
785 size_t num_eras; | |
786 #endif | |
787 struct era_entry *era; | |
788 | |
789 have_I = is_pm = 0; | |
790 century = -1; | |
791 want_century = 0; | |
792 want_era = 0; | |
793 era = NULL; | |
794 | |
795 have_wday = want_xday = have_yday = have_mon = have_mday = 0; | |
796 | |
797 while (*fmt != '\0') | |
798 { | |
799 /* A white space in the format string matches 0 more or white | |
800 space in the input string. */ | |
801 if (isspace (*fmt)) | |
802 { | |
803 while (isspace (*rp)) | |
804 ++rp; | |
805 ++fmt; | |
806 continue; | |
807 } | |
808 | |
809 /* Any character but `%' must be matched by the same character | |
810 in the iput string. */ | |
811 if (*fmt != '%') | |
812 { | |
813 match_char (*fmt++, *rp++); | |
814 continue; | |
815 } | |
816 | |
817 ++fmt; | |
818 #ifndef _NL_CURRENT | |
819 /* We need this for handling the `E' modifier. */ | |
820 start_over: | |
821 #endif | |
822 | |
823 /* Make back up of current processing pointer. */ | |
824 rp_backup = rp; | |
825 | |
826 switch (*fmt++) | |
827 { | |
828 case '%': | |
829 /* Match the `%' character itself. */ | |
830 match_char ('%', *rp++); | |
831 break; | |
832 case 'a': | |
833 case 'A': | |
834 /* Match day of week. */ | |
835 for (cnt = 0; cnt < 7; ++cnt) | |
836 { | |
837 #ifdef _NL_CURRENT | |
838 if (*decided !=raw) | |
839 { | |
840 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp)) | |
841 { | |
842 if (*decided == not | |
843 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), | |
844 weekday_name[cnt])) | |
845 *decided = loc; | |
846 break; | |
847 } | |
848 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp)) | |
849 { | |
850 if (*decided == not | |
851 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), | |
852 ab_weekday_name[cnt])) | |
853 *decided = loc; | |
854 break; | |
855 } | |
856 } | |
857 #endif | |
858 if (*decided != loc | |
859 && (match_string (weekday_name[cnt], rp) | |
860 || match_string (ab_weekday_name[cnt], rp))) | |
861 { | |
862 *decided = raw; | |
863 break; | |
864 } | |
865 } | |
866 if (cnt == 7) | |
867 /* Does not match a weekday name. */ | |
868 return NULL; | |
869 tm->tm_wday = cnt; | |
870 have_wday = 1; | |
871 break; | |
872 case 'b': | |
873 case 'B': | |
874 case 'h': | |
875 /* Match month name. */ | |
876 for (cnt = 0; cnt < 12; ++cnt) | |
877 { | |
878 #ifdef _NL_CURRENT | |
879 if (*decided !=raw) | |
880 { | |
881 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp)) | |
882 { | |
883 if (*decided == not | |
884 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), | |
885 month_name[cnt])) | |
886 *decided = loc; | |
887 break; | |
888 } | |
889 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp)) | |
890 { | |
891 if (*decided == not | |
892 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), | |
893 ab_month_name[cnt])) | |
894 *decided = loc; | |
895 break; | |
896 } | |
897 } | |
898 #endif | |
899 if (match_string (month_name[cnt], rp) | |
900 || match_string (ab_month_name[cnt], rp)) | |
901 { | |
902 *decided = raw; | |
903 break; | |
904 } | |
905 } | |
906 if (cnt == 12) | |
907 /* Does not match a month name. */ | |
908 return NULL; | |
909 tm->tm_mon = cnt; | |
910 want_xday = 1; | |
911 break; | |
912 case 'c': | |
913 /* Match locale's date and time format. */ | |
914 #ifdef _NL_CURRENT | |
915 if (*decided != raw) | |
916 { | |
917 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) | |
918 { | |
919 if (*decided == loc) | |
920 return NULL; | |
921 else | |
922 rp = rp_backup; | |
923 } | |
924 else | |
925 { | |
926 if (*decided == not && | |
927 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) | |
928 *decided = loc; | |
929 want_xday = 1; | |
930 break; | |
931 } | |
932 *decided = raw; | |
933 } | |
934 #endif | |
935 if (!recursive (HERE_D_T_FMT)) | |
936 return NULL; | |
937 want_xday = 1; | |
938 break; | |
939 case 'C': | |
940 /* Match century number. */ | |
941 #ifdef _NL_CURRENT | |
942 match_century: | |
943 #endif | |
944 get_number (0, 99, 2); | |
945 century = val; | |
946 want_xday = 1; | |
947 break; | |
948 case 'd': | |
949 case 'e': | |
950 /* Match day of month. */ | |
951 get_number (1, 31, 2); | |
952 tm->tm_mday = val; | |
953 have_mday = 1; | |
954 want_xday = 1; | |
955 break; | |
956 case 'F': | |
957 if (!recursive ("%Y-%m-%d")) | |
958 return NULL; | |
959 want_xday = 1; | |
960 break; | |
961 case 'x': | |
962 #ifdef _NL_CURRENT | |
963 if (*decided != raw) | |
964 { | |
965 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) | |
966 { | |
967 if (*decided == loc) | |
968 return NULL; | |
969 else | |
970 rp = rp_backup; | |
971 } | |
972 else | |
973 { | |
974 if (*decided == not | |
975 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) | |
976 *decided = loc; | |
977 want_xday = 1; | |
978 break; | |
979 } | |
980 *decided = raw; | |
981 } | |
982 #endif | |
983 /* Fall through. */ | |
984 case 'D': | |
985 /* Match standard day format. */ | |
986 if (!recursive (HERE_D_FMT)) | |
987 return NULL; | |
988 want_xday = 1; | |
989 break; | |
990 case 'k': | |
991 case 'H': | |
992 /* Match hour in 24-hour clock. */ | |
993 get_number (0, 23, 2); | |
994 tm->tm_hour = val; | |
995 have_I = 0; | |
996 break; | |
997 case 'I': | |
998 /* Match hour in 12-hour clock. */ | |
999 get_number (1, 12, 2); | |
1000 tm->tm_hour = val % 12; | |
1001 have_I = 1; | |
1002 break; | |
1003 case 'j': | |
1004 /* Match day number of year. */ | |
1005 get_number (1, 366, 3); | |
1006 tm->tm_yday = val - 1; | |
1007 have_yday = 1; | |
1008 break; | |
1009 case 'm': | |
1010 /* Match number of month. */ | |
1011 get_number (1, 12, 2); | |
1012 tm->tm_mon = val - 1; | |
1013 have_mon = 1; | |
1014 want_xday = 1; | |
1015 break; | |
1016 case 'M': | |
1017 /* Match minute. */ | |
1018 get_number (0, 59, 2); | |
1019 tm->tm_min = val; | |
1020 break; | |
1021 case 'n': | |
1022 case 't': | |
1023 /* Match any white space. */ | |
1024 while (isspace (*rp)) | |
1025 ++rp; | |
1026 break; | |
1027 case 'p': | |
1028 /* Match locale's equivalent of AM/PM. */ | |
1029 #ifdef _NL_CURRENT | |
1030 if (*decided != raw) | |
1031 { | |
1032 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) | |
1033 { | |
1034 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) | |
1035 *decided = loc; | |
1036 break; | |
1037 } | |
1038 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) | |
1039 { | |
1040 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) | |
1041 *decided = loc; | |
1042 is_pm = 1; | |
1043 break; | |
1044 } | |
1045 *decided = raw; | |
1046 } | |
1047 #endif | |
1048 if (!match_string (HERE_AM_STR, rp)) | |
1049 if (match_string (HERE_PM_STR, rp)) | |
1050 is_pm = 1; | |
1051 else | |
1052 return NULL; | |
1053 break; | |
1054 case 'r': | |
1055 #ifdef _NL_CURRENT | |
1056 if (*decided != raw) | |
1057 { | |
1058 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) | |
1059 { | |
1060 if (*decided == loc) | |
1061 return NULL; | |
1062 else | |
1063 rp = rp_backup; | |
1064 } | |
1065 else | |
1066 { | |
1067 if (*decided == not && | |
1068 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), | |
1069 HERE_T_FMT_AMPM)) | |
1070 *decided = loc; | |
1071 break; | |
1072 } | |
1073 *decided = raw; | |
1074 } | |
1075 #endif | |
1076 if (!recursive (HERE_T_FMT_AMPM)) | |
1077 return NULL; | |
1078 break; | |
1079 case 'R': | |
1080 if (!recursive ("%H:%M")) | |
1081 return NULL; | |
1082 break; | |
1083 case 's': | |
1084 { | |
1085 /* The number of seconds may be very high so we cannot use | |
1086 the `get_number' macro. Instead read the number | |
1087 character for character and construct the result while | |
1088 doing this. */ | |
1089 time_t secs = 0; | |
1090 if (*rp < '0' || *rp > '9') | |
1091 /* We need at least one digit. */ | |
1092 return NULL; | |
1093 | |
1094 do | |
1095 { | |
1096 secs *= 10; | |
1097 secs += *rp++ - '0'; | |
1098 } | |
1099 while (*rp >= '0' && *rp <= '9'); | |
1100 | |
1101 if (localtime_r (&secs, tm) == NULL) | |
1102 /* Error in function. */ | |
1103 return NULL; | |
1104 } | |
1105 break; | |
1106 case 'S': | |
1107 get_number (0, 61, 2); | |
1108 tm->tm_sec = val; | |
1109 break; | |
1110 case 'X': | |
1111 #ifdef _NL_CURRENT | |
1112 if (*decided != raw) | |
1113 { | |
1114 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) | |
1115 { | |
1116 if (*decided == loc) | |
1117 return NULL; | |
1118 else | |
1119 rp = rp_backup; | |
1120 } | |
1121 else | |
1122 { | |
1123 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) | |
1124 *decided = loc; | |
1125 break; | |
1126 } | |
1127 *decided = raw; | |
1128 } | |
1129 #endif | |
1130 /* Fall through. */ | |
1131 case 'T': | |
1132 if (!recursive (HERE_T_FMT)) | |
1133 return NULL; | |
1134 break; | |
1135 case 'u': | |
1136 get_number (1, 7, 1); | |
1137 tm->tm_wday = val % 7; | |
1138 have_wday = 1; | |
1139 break; | |
1140 case 'g': | |
1141 get_number (0, 99, 2); | |
1142 /* XXX This cannot determine any field in TM. */ | |
1143 break; | |
1144 case 'G': | |
1145 if (*rp < '0' || *rp > '9') | |
1146 return NULL; | |
1147 /* XXX Ignore the number since we would need some more | |
1148 information to compute a real date. */ | |
1149 do | |
1150 ++rp; | |
1151 while (*rp >= '0' && *rp <= '9'); | |
1152 break; | |
1153 case 'U': | |
1154 case 'V': | |
1155 case 'W': | |
1156 get_number (0, 53, 2); | |
1157 /* XXX This cannot determine any field in TM without some | |
1158 information. */ | |
1159 break; | |
1160 case 'w': | |
1161 /* Match number of weekday. */ | |
1162 get_number (0, 6, 1); | |
1163 tm->tm_wday = val; | |
1164 have_wday = 1; | |
1165 break; | |
1166 case 'y': | |
1167 #ifdef _NL_CURRENT | |
1168 match_year_in_century: | |
1169 #endif | |
1170 /* Match year within century. */ | |
1171 get_number (0, 99, 2); | |
1172 /* The "Year 2000: The Millennium Rollover" paper suggests that | |
1173 values in the range 69-99 refer to the twentieth century. */ | |
1174 tm->tm_year = val >= 69 ? val : val + 100; | |
1175 /* Indicate that we want to use the century, if specified. */ | |
1176 want_century = 1; | |
1177 want_xday = 1; | |
1178 break; | |
1179 case 'Y': | |
1180 /* Match year including century number. */ | |
1181 get_number (0, 9999, 4); | |
1182 tm->tm_year = val - 1900; | |
1183 want_century = 0; | |
1184 want_xday = 1; | |
1185 break; | |
1186 case 'Z': | |
1187 /* XXX How to handle this? */ | |
1188 break; | |
1189 case 'E': | |
1190 #ifdef _NL_CURRENT | |
1191 switch (*fmt++) | |
1192 { | |
1193 case 'c': | |
1194 /* Match locale's alternate date and time format. */ | |
1195 if (*decided != raw) | |
1196 { | |
1197 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); | |
1198 | |
1199 if (*fmt == '\0') | |
1200 fmt = _NL_CURRENT (LC_TIME, D_T_FMT); | |
1201 | |
1202 if (!recursive (fmt)) | |
1203 { | |
1204 if (*decided == loc) | |
1205 return NULL; | |
1206 else | |
1207 rp = rp_backup; | |
1208 } | |
1209 else | |
1210 { | |
1211 if (strcmp (fmt, HERE_D_T_FMT)) | |
1212 *decided = loc; | |
1213 want_xday = 1; | |
1214 break; | |
1215 } | |
1216 *decided = raw; | |
1217 } | |
1218 /* The C locale has no era information, so use the | |
1219 normal representation. */ | |
1220 if (!recursive (HERE_D_T_FMT)) | |
1221 return NULL; | |
1222 want_xday = 1; | |
1223 break; | |
1224 case 'C': | |
1225 if (*decided != raw) | |
1226 { | |
1227 if (era_cnt >= 0) | |
1228 { | |
1229 era = _nl_select_era_entry (era_cnt); | |
1230 if (match_string (era->era_name, rp)) | |
1231 { | |
1232 *decided = loc; | |
1233 break; | |
1234 } | |
1235 else | |
1236 return NULL; | |
1237 } | |
1238 else | |
1239 { | |
1240 num_eras = _NL_CURRENT_WORD (LC_TIME, | |
1241 _NL_TIME_ERA_NUM_ENTRIES); | |
1242 for (era_cnt = 0; era_cnt < (int) num_eras; | |
1243 ++era_cnt, rp = rp_backup) | |
1244 { | |
1245 era = _nl_select_era_entry (era_cnt); | |
1246 if (match_string (era->era_name, rp)) | |
1247 { | |
1248 *decided = loc; | |
1249 break; | |
1250 } | |
1251 } | |
1252 if (era_cnt == (int) num_eras) | |
1253 { | |
1254 era_cnt = -1; | |
1255 if (*decided == loc) | |
1256 return NULL; | |
1257 } | |
1258 else | |
1259 break; | |
1260 } | |
1261 | |
1262 *decided = raw; | |
1263 } | |
1264 /* The C locale has no era information, so use the | |
1265 normal representation. */ | |
1266 goto match_century; | |
1267 case 'y': | |
1268 if (*decided == raw) | |
1269 goto match_year_in_century; | |
1270 | |
1271 get_number(0, 9999, 4); | |
1272 tm->tm_year = val; | |
1273 want_era = 1; | |
1274 want_xday = 1; | |
1275 break; | |
1276 case 'Y': | |
1277 if (*decided != raw) | |
1278 { | |
1279 num_eras = _NL_CURRENT_WORD (LC_TIME, | |
1280 _NL_TIME_ERA_NUM_ENTRIES); | |
1281 for (era_cnt = 0; era_cnt < (int) num_eras; | |
1282 ++era_cnt, rp = rp_backup) | |
1283 { | |
1284 era = _nl_select_era_entry (era_cnt); | |
1285 if (recursive (era->era_format)) | |
1286 break; | |
1287 } | |
1288 if (era_cnt == (int) num_eras) | |
1289 { | |
1290 era_cnt = -1; | |
1291 if (*decided == loc) | |
1292 return NULL; | |
1293 else | |
1294 rp = rp_backup; | |
1295 } | |
1296 else | |
1297 { | |
1298 *decided = loc; | |
1299 era_cnt = -1; | |
1300 break; | |
1301 } | |
1302 | |
1303 *decided = raw; | |
1304 } | |
1305 get_number (0, 9999, 4); | |
1306 tm->tm_year = val - 1900; | |
1307 want_century = 0; | |
1308 want_xday = 1; | |
1309 break; | |
1310 case 'x': | |
1311 if (*decided != raw) | |
1312 { | |
1313 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); | |
1314 | |
1315 if (*fmt == '\0') | |
1316 fmt = _NL_CURRENT (LC_TIME, D_FMT); | |
1317 | |
1318 if (!recursive (fmt)) | |
1319 { | |
1320 if (*decided == loc) | |
1321 return NULL; | |
1322 else | |
1323 rp = rp_backup; | |
1324 } | |
1325 else | |
1326 { | |
1327 if (strcmp (fmt, HERE_D_FMT)) | |
1328 *decided = loc; | |
1329 break; | |
1330 } | |
1331 *decided = raw; | |
1332 } | |
1333 if (!recursive (HERE_D_FMT)) | |
1334 return NULL; | |
1335 break; | |
1336 case 'X': | |
1337 if (*decided != raw) | |
1338 { | |
1339 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); | |
1340 | |
1341 if (*fmt == '\0') | |
1342 fmt = _NL_CURRENT (LC_TIME, T_FMT); | |
1343 | |
1344 if (!recursive (fmt)) | |
1345 { | |
1346 if (*decided == loc) | |
1347 return NULL; | |
1348 else | |
1349 rp = rp_backup; | |
1350 } | |
1351 else | |
1352 { | |
1353 if (strcmp (fmt, HERE_T_FMT)) | |
1354 *decided = loc; | |
1355 break; | |
1356 } | |
1357 *decided = raw; | |
1358 } | |
1359 if (!recursive (HERE_T_FMT)) | |
1360 return NULL; | |
1361 break; | |
1362 default: | |
1363 return NULL; | |
1364 } | |
1365 break; | |
1366 #else | |
1367 /* We have no information about the era format. Just use | |
1368 the normal format. */ | |
1369 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' | |
1370 && *fmt != 'x' && *fmt != 'X') | |
1371 /* This is an illegal format. */ | |
1372 return NULL; | |
1373 | |
1374 goto start_over; | |
1375 #endif | |
1376 case 'O': | |
1377 switch (*fmt++) | |
1378 { | |
1379 case 'd': | |
1380 case 'e': | |
1381 /* Match day of month using alternate numeric symbols. */ | |
1382 get_alt_number (1, 31, 2); | |
1383 tm->tm_mday = val; | |
1384 have_mday = 1; | |
1385 want_xday = 1; | |
1386 break; | |
1387 case 'H': | |
1388 /* Match hour in 24-hour clock using alternate numeric | |
1389 symbols. */ | |
1390 get_alt_number (0, 23, 2); | |
1391 tm->tm_hour = val; | |
1392 have_I = 0; | |
1393 break; | |
1394 case 'I': | |
1395 /* Match hour in 12-hour clock using alternate numeric | |
1396 symbols. */ | |
1397 get_alt_number (1, 12, 2); | |
1398 tm->tm_hour = val - 1; | |
1399 have_I = 1; | |
1400 break; | |
1401 case 'm': | |
1402 /* Match month using alternate numeric symbols. */ | |
1403 get_alt_number (1, 12, 2); | |
1404 tm->tm_mon = val - 1; | |
1405 have_mon = 1; | |
1406 want_xday = 1; | |
1407 break; | |
1408 case 'M': | |
1409 /* Match minutes using alternate numeric symbols. */ | |
1410 get_alt_number (0, 59, 2); | |
1411 tm->tm_min = val; | |
1412 break; | |
1413 case 'S': | |
1414 /* Match seconds using alternate numeric symbols. */ | |
1415 get_alt_number (0, 61, 2); | |
1416 tm->tm_sec = val; | |
1417 break; | |
1418 case 'U': | |
1419 case 'V': | |
1420 case 'W': | |
1421 get_alt_number (0, 53, 2); | |
1422 /* XXX This cannot determine any field in TM without | |
1423 further information. */ | |
1424 break; | |
1425 case 'w': | |
1426 /* Match number of weekday using alternate numeric symbols. */ | |
1427 get_alt_number (0, 6, 1); | |
1428 tm->tm_wday = val; | |
1429 have_wday = 1; | |
1430 break; | |
1431 case 'y': | |
1432 /* Match year within century using alternate numeric symbols. */ | |
1433 get_alt_number (0, 99, 2); | |
1434 tm->tm_year = val >= 69 ? val : val + 100; | |
1435 want_xday = 1; | |
1436 break; | |
1437 default: | |
1438 return NULL; | |
1439 } | |
1440 break; | |
1441 default: | |
1442 return NULL; | |
1443 } | |
1444 } | |
1445 | |
1446 if (have_I && is_pm) | |
1447 tm->tm_hour += 12; | |
1448 | |
1449 if (century != -1) | |
1450 { | |
1451 if (want_century) | |
1452 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; | |
1453 else | |
1454 /* Only the century, but not the year. Strange, but so be it. */ | |
1455 tm->tm_year = (century - 19) * 100; | |
1456 } | |
1457 | |
1458 #ifdef _NL_CURRENT | |
1459 if (era_cnt != -1) | |
1460 { | |
1461 era = _nl_select_era_entry(era_cnt); | |
1462 if (want_era) | |
1463 tm->tm_year = (era->start_date[0] | |
1464 + ((tm->tm_year - era->offset) | |
1465 * era->absolute_direction)); | |
1466 else | |
1467 /* Era start year assumed. */ | |
1468 tm->tm_year = era->start_date[0]; | |
1469 } | |
1470 else | |
1471 #endif | |
1472 if (want_era) | |
1473 return NULL; | |
1474 | |
1475 if (want_xday && !have_wday) | |
1476 { | |
1477 if ( !(have_mon && have_mday) && have_yday) | |
1478 { | |
1479 /* We don't have tm_mon and/or tm_mday, compute them. */ | |
1480 int t_mon = 0; | |
1481 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) | |
1482 t_mon++; | |
1483 if (!have_mon) | |
1484 tm->tm_mon = t_mon - 1; | |
1485 if (!have_mday) | |
1486 tm->tm_mday = | |
1487 (tm->tm_yday | |
1488 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); | |
1489 } | |
1490 day_of_the_week (tm); | |
1491 } | |
1492 if (want_xday && !have_yday) | |
1493 day_of_the_year (tm); | |
1494 | |
1495 return (char *) rp; | |
1496 } | |
1497 | |
1498 | |
1499 char * | |
1500 msn_strptime (buf, format, tm) | |
1501 const char *buf; | |
1502 const char *format; | |
1503 struct tm *tm; | |
1504 { | |
1505 enum locale_status decided; | |
1506 | |
1507 #ifdef _NL_CURRENT | |
1508 decided = not; | |
1509 #else | |
1510 decided = raw; | |
1511 #endif | |
1512 return strptime_internal (buf, format, tm, &decided, -1); | |
1513 } | |
1514 #else | |
1515 #define msn_strptime strptime | |
1516 #endif |