strptime.c revision 79664
128019Sjoerg/* 228021Sjoerg * Powerdog Industries kindly requests feedback from anyone modifying 328021Sjoerg * this function: 428021Sjoerg * 528021Sjoerg * Date: Thu, 05 Jun 1997 23:17:17 -0400 628021Sjoerg * From: Kevin Ruddy <kevin.ruddy@powerdog.com> 728021Sjoerg * To: James FitzGibbon <james@nexis.net> 828021Sjoerg * Subject: Re: Use of your strptime(3) code (fwd) 928021Sjoerg * 1028021Sjoerg * The reason for the "no mod" clause was so that modifications would 1128021Sjoerg * come back and we could integrate them and reissue so that a wider 1228021Sjoerg * audience could use it (thereby spreading the wealth). This has 1328021Sjoerg * made it possible to get strptime to work on many operating systems. 1428021Sjoerg * I'm not sure why that's "plain unacceptable" to the FreeBSD team. 1528021Sjoerg * 1628021Sjoerg * Anyway, you can change it to "with or without modification" as 1728021Sjoerg * you see fit. Enjoy. 1828021Sjoerg * 1928021Sjoerg * Kevin Ruddy 2028021Sjoerg * Powerdog Industries, Inc. 2128021Sjoerg */ 2228021Sjoerg/* 2328019Sjoerg * Copyright (c) 1994 Powerdog Industries. All rights reserved. 2428019Sjoerg * 2528021Sjoerg * Redistribution and use in source and binary forms, with or without 2628019Sjoerg * modification, are permitted provided that the following conditions 2728019Sjoerg * are met: 2828019Sjoerg * 1. Redistributions of source code must retain the above copyright 2928019Sjoerg * notice, this list of conditions and the following disclaimer. 3028019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 3128019Sjoerg * notice, this list of conditions and the following disclaimer 3228019Sjoerg * in the documentation and/or other materials provided with the 3328019Sjoerg * distribution. 3428019Sjoerg * 3. All advertising materials mentioning features or use of this 3528019Sjoerg * software must display the following acknowledgement: 3628019Sjoerg * This product includes software developed by Powerdog Industries. 3728019Sjoerg * 4. The name of Powerdog Industries may not be used to endorse or 3828019Sjoerg * promote products derived from this software without specific prior 3928019Sjoerg * written permission. 4028019Sjoerg * 4128019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 4228019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4328019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4428019Sjoerg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 4528019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 4628019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 4728019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 4828019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 4928019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 5028019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 5128019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5228019Sjoerg */ 5328019Sjoerg 5428021Sjoerg#ifdef LIBC_RCS 5528021Sjoergstatic const char rcsid[] = 5650476Speter "$FreeBSD: head/lib/libc/stdtime/strptime.c 79664 2001-07-13 13:59:24Z dd $"; 5728021Sjoerg#endif 5828021Sjoerg 5928019Sjoerg#ifndef lint 6028021Sjoerg#ifndef NOID 6128019Sjoergstatic char copyright[] = 6228019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 6328021Sjoergstatic char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 6428021Sjoerg#endif /* !defined NOID */ 6528019Sjoerg#endif /* not lint */ 6628019Sjoerg 6771579Sdeischen#include "namespace.h" 6828019Sjoerg#include <time.h> 6928019Sjoerg#include <ctype.h> 7079664Sdd#include <limits.h> 7179664Sdd#include <stdlib.h> 7228019Sjoerg#include <string.h> 7348614Sobrien#include <pthread.h> 7471579Sdeischen#include "un-namespace.h" 7571579Sdeischen#include "libc_private.h" 7628021Sjoerg#include "timelocal.h" 7728019Sjoerg 7848614Sobrienstatic char * _strptime(const char *, const char *, struct tm *); 7948614Sobrien 8071579Sdeischenstatic pthread_mutex_t gotgmt_mutex = PTHREAD_MUTEX_INITIALIZER; 8148614Sobrienstatic int got_GMT; 8248614Sobrien 8328021Sjoerg#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 8428019Sjoerg 8548614Sobrienstatic char * 8648614Sobrien_strptime(const char *buf, const char *fmt, struct tm *tm) 8728019Sjoerg{ 8828021Sjoerg char c; 8928021Sjoerg const char *ptr; 9028021Sjoerg int i, 9128021Sjoerg len; 9253941Sache int Ealternative, Oalternative; 9372168Sphantom struct lc_time_T *tptr = __get_current_time_locale(); 9428019Sjoerg 9528021Sjoerg ptr = fmt; 9628021Sjoerg while (*ptr != 0) { 9728021Sjoerg if (*buf == 0) 9828021Sjoerg break; 9928019Sjoerg 10028021Sjoerg c = *ptr++; 10128019Sjoerg 10228021Sjoerg if (c != '%') { 10328164Sache if (isspace((unsigned char)c)) 10428164Sache while (*buf != 0 && isspace((unsigned char)*buf)) 10528021Sjoerg buf++; 10628021Sjoerg else if (c != *buf++) 10728021Sjoerg return 0; 10828021Sjoerg continue; 10928021Sjoerg } 11028019Sjoerg 11153941Sache Ealternative = 0; 11253941Sache Oalternative = 0; 11353941Sachelabel: 11428021Sjoerg c = *ptr++; 11528021Sjoerg switch (c) { 11628021Sjoerg case 0: 11728021Sjoerg case '%': 11828021Sjoerg if (*buf++ != '%') 11928021Sjoerg return 0; 12028021Sjoerg break; 12128019Sjoerg 12253941Sache case '+': 12372168Sphantom buf = _strptime(buf, tptr->date_fmt, tm); 12428021Sjoerg if (buf == 0) 12528021Sjoerg return 0; 12628021Sjoerg break; 12728019Sjoerg 12853941Sache case 'C': 12953941Sache if (!isdigit((unsigned char)*buf)) 13053941Sache return 0; 13153941Sache 13254316Ssheldonh /* XXX This will break for 3-digit centuries. */ 13354316Ssheldonh len = 2; 13454316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 13553941Sache i *= 10; 13653941Sache i += *buf - '0'; 13754316Ssheldonh len--; 13853941Sache } 13953941Sache if (i < 19) 14053941Sache return 0; 14153941Sache 14253941Sache tm->tm_year = i * 100 - 1900; 14353941Sache break; 14453941Sache 14528021Sjoerg case 'c': 14672183Sache buf = _strptime(buf, tptr->c_fmt, tm); 14728021Sjoerg if (buf == 0) 14828021Sjoerg return 0; 14928021Sjoerg break; 15028019Sjoerg 15128021Sjoerg case 'D': 15248614Sobrien buf = _strptime(buf, "%m/%d/%y", tm); 15328021Sjoerg if (buf == 0) 15428021Sjoerg return 0; 15528021Sjoerg break; 15628019Sjoerg 15753941Sache case 'E': 15853960Sache if (Ealternative || Oalternative) 15953960Sache break; 16053941Sache Ealternative++; 16153941Sache goto label; 16253941Sache 16353941Sache case 'O': 16453960Sache if (Ealternative || Oalternative) 16553960Sache break; 16653941Sache Oalternative++; 16753941Sache goto label; 16853941Sache 16953960Sache case 'F': 17074578Sache buf = _strptime(buf, "%Y-%m-%d", tm); 17174412Sache if (buf == 0) 17274412Sache return 0; 17374412Sache break; 17474412Sache 17528021Sjoerg case 'R': 17648614Sobrien buf = _strptime(buf, "%H:%M", tm); 17728021Sjoerg if (buf == 0) 17828021Sjoerg return 0; 17928021Sjoerg break; 18028019Sjoerg 18128021Sjoerg case 'r': 18273359Sache buf = _strptime(buf, tptr->ampm_fmt, tm); 18328021Sjoerg if (buf == 0) 18428021Sjoerg return 0; 18528021Sjoerg break; 18628019Sjoerg 18728021Sjoerg case 'T': 18848614Sobrien buf = _strptime(buf, "%H:%M:%S", tm); 18928021Sjoerg if (buf == 0) 19028021Sjoerg return 0; 19128021Sjoerg break; 19228019Sjoerg 19328021Sjoerg case 'X': 19472168Sphantom buf = _strptime(buf, tptr->X_fmt, tm); 19528021Sjoerg if (buf == 0) 19628021Sjoerg return 0; 19728021Sjoerg break; 19828019Sjoerg 19928021Sjoerg case 'x': 20072168Sphantom buf = _strptime(buf, tptr->x_fmt, tm); 20128021Sjoerg if (buf == 0) 20228021Sjoerg return 0; 20328021Sjoerg break; 20428019Sjoerg 20528021Sjoerg case 'j': 20628164Sache if (!isdigit((unsigned char)*buf)) 20728021Sjoerg return 0; 20828019Sjoerg 20954316Ssheldonh len = 3; 21054316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 21128021Sjoerg i *= 10; 21228021Sjoerg i += *buf - '0'; 21354316Ssheldonh len--; 21428021Sjoerg } 21553083Ssheldonh if (i < 1 || i > 366) 21628021Sjoerg return 0; 21728019Sjoerg 21853083Ssheldonh tm->tm_yday = i - 1; 21928021Sjoerg break; 22028019Sjoerg 22128021Sjoerg case 'M': 22228021Sjoerg case 'S': 22328164Sache if (*buf == 0 || isspace((unsigned char)*buf)) 22428021Sjoerg break; 22528019Sjoerg 22628164Sache if (!isdigit((unsigned char)*buf)) 22728021Sjoerg return 0; 22828019Sjoerg 22954316Ssheldonh len = 2; 23054316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 23128021Sjoerg i *= 10; 23228021Sjoerg i += *buf - '0'; 23354316Ssheldonh len--; 23428021Sjoerg } 23528019Sjoerg 23653083Ssheldonh if (c == 'M') { 23753083Ssheldonh if (i > 59) 23853083Ssheldonh return 0; 23928021Sjoerg tm->tm_min = i; 24053083Ssheldonh } else { 24153083Ssheldonh if (i > 60) 24253083Ssheldonh return 0; 24328021Sjoerg tm->tm_sec = i; 24453083Ssheldonh } 24528019Sjoerg 24628164Sache if (*buf != 0 && isspace((unsigned char)*buf)) 24728164Sache while (*ptr != 0 && !isspace((unsigned char)*ptr)) 24828021Sjoerg ptr++; 24928021Sjoerg break; 25028019Sjoerg 25128021Sjoerg case 'H': 25228021Sjoerg case 'I': 25328021Sjoerg case 'k': 25428021Sjoerg case 'l': 25554316Ssheldonh /* 25654316Ssheldonh * Of these, %l is the only specifier explicitly 25754316Ssheldonh * documented as not being zero-padded. However, 25854316Ssheldonh * there is no harm in allowing zero-padding. 25954316Ssheldonh * 26054316Ssheldonh * XXX The %l specifier may gobble one too many 26154316Ssheldonh * digits if used incorrectly. 26254316Ssheldonh */ 26328164Sache if (!isdigit((unsigned char)*buf)) 26428021Sjoerg return 0; 26528019Sjoerg 26654316Ssheldonh len = 2; 26754316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 26828021Sjoerg i *= 10; 26928021Sjoerg i += *buf - '0'; 27054316Ssheldonh len--; 27128021Sjoerg } 27228021Sjoerg if (c == 'H' || c == 'k') { 27328021Sjoerg if (i > 23) 27428021Sjoerg return 0; 27554301Ssheldonh } else if (i > 12) 27628021Sjoerg return 0; 27728019Sjoerg 27828021Sjoerg tm->tm_hour = i; 27928019Sjoerg 28028164Sache if (*buf != 0 && isspace((unsigned char)*buf)) 28128164Sache while (*ptr != 0 && !isspace((unsigned char)*ptr)) 28228021Sjoerg ptr++; 28328021Sjoerg break; 28428019Sjoerg 28528021Sjoerg case 'p': 28654316Ssheldonh /* 28754316Ssheldonh * XXX This is bogus if parsed before hour-related 28854316Ssheldonh * specifiers. 28954316Ssheldonh */ 29072168Sphantom len = strlen(tptr->am); 29172168Sphantom if (strncasecmp(buf, tptr->am, len) == 0) { 29228021Sjoerg if (tm->tm_hour > 12) 29328021Sjoerg return 0; 29428021Sjoerg if (tm->tm_hour == 12) 29528021Sjoerg tm->tm_hour = 0; 29628021Sjoerg buf += len; 29728021Sjoerg break; 29828021Sjoerg } 29928019Sjoerg 30072168Sphantom len = strlen(tptr->pm); 30172168Sphantom if (strncasecmp(buf, tptr->pm, len) == 0) { 30228021Sjoerg if (tm->tm_hour > 12) 30328021Sjoerg return 0; 30428021Sjoerg if (tm->tm_hour != 12) 30528021Sjoerg tm->tm_hour += 12; 30628021Sjoerg buf += len; 30728021Sjoerg break; 30828021Sjoerg } 30928019Sjoerg 31028021Sjoerg return 0; 31128019Sjoerg 31228021Sjoerg case 'A': 31328021Sjoerg case 'a': 31472168Sphantom for (i = 0; i < asizeof(tptr->weekday); i++) { 31574409Sache len = strlen(tptr->weekday[i]); 31674409Sache if (strncasecmp(buf, tptr->weekday[i], 31774409Sache len) == 0) 31874409Sache break; 31974409Sache len = strlen(tptr->wday[i]); 32074409Sache if (strncasecmp(buf, tptr->wday[i], 32174409Sache len) == 0) 32274409Sache break; 32328021Sjoerg } 32472168Sphantom if (i == asizeof(tptr->weekday)) 32528021Sjoerg return 0; 32628019Sjoerg 32728021Sjoerg tm->tm_wday = i; 32828021Sjoerg buf += len; 32928021Sjoerg break; 33028019Sjoerg 33153083Ssheldonh case 'U': 33253083Ssheldonh case 'W': 33353083Ssheldonh /* 33453083Ssheldonh * XXX This is bogus, as we can not assume any valid 33553083Ssheldonh * information present in the tm structure at this 33653083Ssheldonh * point to calculate a real value, so just check the 33753083Ssheldonh * range for now. 33853083Ssheldonh */ 33953083Ssheldonh if (!isdigit((unsigned char)*buf)) 34053083Ssheldonh return 0; 34153083Ssheldonh 34254316Ssheldonh len = 2; 34354316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 34453083Ssheldonh i *= 10; 34553083Ssheldonh i += *buf - '0'; 34654316Ssheldonh len--; 34753083Ssheldonh } 34853083Ssheldonh if (i > 53) 34953083Ssheldonh return 0; 35053083Ssheldonh 35153083Ssheldonh if (*buf != 0 && isspace((unsigned char)*buf)) 35253083Ssheldonh while (*ptr != 0 && !isspace((unsigned char)*ptr)) 35353083Ssheldonh ptr++; 35453083Ssheldonh break; 35553083Ssheldonh 35653083Ssheldonh case 'w': 35753083Ssheldonh if (!isdigit((unsigned char)*buf)) 35853083Ssheldonh return 0; 35953083Ssheldonh 36054316Ssheldonh i = *buf - '0'; 36153083Ssheldonh if (i > 6) 36253083Ssheldonh return 0; 36353083Ssheldonh 36453083Ssheldonh tm->tm_wday = i; 36553083Ssheldonh 36653083Ssheldonh if (*buf != 0 && isspace((unsigned char)*buf)) 36753083Ssheldonh while (*ptr != 0 && !isspace((unsigned char)*ptr)) 36853083Ssheldonh ptr++; 36953083Ssheldonh break; 37053083Ssheldonh 37128021Sjoerg case 'd': 37228021Sjoerg case 'e': 37354316Ssheldonh /* 37454316Ssheldonh * The %e specifier is explicitly documented as not 37554316Ssheldonh * being zero-padded but there is no harm in allowing 37654316Ssheldonh * such padding. 37754316Ssheldonh * 37854316Ssheldonh * XXX The %e specifier may gobble one too many 37954316Ssheldonh * digits if used incorrectly. 38054316Ssheldonh */ 38128164Sache if (!isdigit((unsigned char)*buf)) 38228021Sjoerg return 0; 38328019Sjoerg 38454316Ssheldonh len = 2; 38554316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 38628021Sjoerg i *= 10; 38728021Sjoerg i += *buf - '0'; 38854316Ssheldonh len--; 38928021Sjoerg } 39028021Sjoerg if (i > 31) 39128021Sjoerg return 0; 39228019Sjoerg 39328021Sjoerg tm->tm_mday = i; 39428019Sjoerg 39528164Sache if (*buf != 0 && isspace((unsigned char)*buf)) 39628164Sache while (*ptr != 0 && !isspace((unsigned char)*ptr)) 39728021Sjoerg ptr++; 39828021Sjoerg break; 39928019Sjoerg 40028021Sjoerg case 'B': 40128021Sjoerg case 'b': 40228021Sjoerg case 'h': 40372168Sphantom for (i = 0; i < asizeof(tptr->month); i++) { 40453941Sache if (Oalternative) { 40553941Sache if (c == 'B') { 40672168Sphantom len = strlen(tptr->alt_month[i]); 40753941Sache if (strncasecmp(buf, 40872168Sphantom tptr->alt_month[i], 40953941Sache len) == 0) 41053941Sache break; 41153941Sache } 41253941Sache } else { 41374409Sache len = strlen(tptr->month[i]); 41474409Sache if (strncasecmp(buf, tptr->month[i], 41574409Sache len) == 0) 41674409Sache break; 41774409Sache len = strlen(tptr->mon[i]); 41874409Sache if (strncasecmp(buf, tptr->mon[i], 41974409Sache len) == 0) 42074409Sache break; 42153941Sache } 42228021Sjoerg } 42372168Sphantom if (i == asizeof(tptr->month)) 42428021Sjoerg return 0; 42528019Sjoerg 42628021Sjoerg tm->tm_mon = i; 42728021Sjoerg buf += len; 42828021Sjoerg break; 42928019Sjoerg 43028021Sjoerg case 'm': 43128164Sache if (!isdigit((unsigned char)*buf)) 43228021Sjoerg return 0; 43328019Sjoerg 43454316Ssheldonh len = 2; 43554316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 43628021Sjoerg i *= 10; 43728021Sjoerg i += *buf - '0'; 43854316Ssheldonh len--; 43928021Sjoerg } 44028021Sjoerg if (i < 1 || i > 12) 44128021Sjoerg return 0; 44228019Sjoerg 44328021Sjoerg tm->tm_mon = i - 1; 44428019Sjoerg 44528164Sache if (*buf != 0 && isspace((unsigned char)*buf)) 44628164Sache while (*ptr != 0 && !isspace((unsigned char)*ptr)) 44728021Sjoerg ptr++; 44828021Sjoerg break; 44928019Sjoerg 45079664Sdd case 's': 45179664Sdd { 45279664Sdd char *cp; 45379664Sdd time_t t; 45479664Sdd 45579664Sdd t = strtol(buf, &cp, 10); 45679664Sdd if (t == LONG_MAX) 45779664Sdd return 0; 45879664Sdd buf = cp; 45979664Sdd gmtime_r(&t, tm); 46079664Sdd got_GMT = 1; 46179664Sdd } 46279664Sdd break; 46379664Sdd 46428021Sjoerg case 'Y': 46528021Sjoerg case 'y': 46628164Sache if (*buf == 0 || isspace((unsigned char)*buf)) 46728021Sjoerg break; 46828019Sjoerg 46928164Sache if (!isdigit((unsigned char)*buf)) 47028021Sjoerg return 0; 47128019Sjoerg 47254316Ssheldonh len = (c == 'Y') ? 4 : 2; 47354316Ssheldonh for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { 47428021Sjoerg i *= 10; 47528021Sjoerg i += *buf - '0'; 47654316Ssheldonh len--; 47728021Sjoerg } 47828021Sjoerg if (c == 'Y') 47928021Sjoerg i -= 1900; 48046051Swes if (c == 'y' && i < 69) 48146042Swes i += 100; 48228021Sjoerg if (i < 0) 48328021Sjoerg return 0; 48428019Sjoerg 48528021Sjoerg tm->tm_year = i; 48628019Sjoerg 48728164Sache if (*buf != 0 && isspace((unsigned char)*buf)) 48828164Sache while (*ptr != 0 && !isspace((unsigned char)*ptr)) 48928021Sjoerg ptr++; 49028021Sjoerg break; 49148550Sobrien 49248550Sobrien case 'Z': 49348550Sobrien { 49448550Sobrien const char *cp; 49548550Sobrien char *zonestr; 49648550Sobrien 49752860Sache for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/} 49848550Sobrien if (cp - buf) { 49948550Sobrien zonestr = alloca(cp - buf + 1); 50048550Sobrien strncpy(zonestr, buf, cp - buf); 50148550Sobrien zonestr[cp - buf] = '\0'; 50248550Sobrien tzset(); 50348550Sobrien if (0 == strcmp(zonestr, "GMT")) { 50448614Sobrien got_GMT = 1; 50548550Sobrien } else if (0 == strcmp(zonestr, tzname[0])) { 50648614Sobrien tm->tm_isdst = 0; 50748550Sobrien } else if (0 == strcmp(zonestr, tzname[1])) { 50848614Sobrien tm->tm_isdst = 1; 50948550Sobrien } else { 51048614Sobrien return 0; 51148550Sobrien } 51248550Sobrien buf += cp - buf; 51348550Sobrien } 51448550Sobrien } 51548550Sobrien break; 51628021Sjoerg } 51728021Sjoerg } 51848614Sobrien return (char *)buf; 51948614Sobrien} 52028019Sjoerg 52148614Sobrien 52248614Sobrienchar * 52348614Sobrienstrptime(const char *buf, const char *fmt, struct tm *tm) 52448614Sobrien{ 52548614Sobrien char *ret; 52648614Sobrien 52771579Sdeischen if (__isthreaded) 52871579Sdeischen _pthread_mutex_lock(&gotgmt_mutex); 52948614Sobrien 53048614Sobrien got_GMT = 0; 53148614Sobrien ret = _strptime(buf, fmt, tm); 53248614Sobrien if (ret && got_GMT) { 53348550Sobrien time_t t = timegm(tm); 53471579Sdeischen localtime_r(&t, tm); 53548614Sobrien got_GMT = 0; 53648550Sobrien } 53748614Sobrien 53871579Sdeischen if (__isthreaded) 53971579Sdeischen _pthread_mutex_unlock(&gotgmt_mutex); 54048614Sobrien 54148614Sobrien return ret; 54228019Sjoerg} 543