i synced Android's strptime.c with openbsd's recently, getting rid of
unnecessary/accidental differences. i'm left with the following, which i
thought was interesting (the last one's probably the most interesting, so
definitely stick around even if -- as is likely -- you don't care
about/actively don't want the first two!)...

comment says it all here for %v:

@@ -182,6 +188,12 @@
  return (NULL);
  break;

+ case 'v': /* Android: the date as "%e-%b-%Y" for strftime() compat; glibc
does this too. */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%e-%b-%Y", tm, 0)))
+ return (NULL);
+ break;
+
  case 'X': /* The time, using the locale's format. */
  _LEGAL_ALT(_ALT_E);
  if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))

(full disclosure: although bionic [Android] and glibc both implement this,
free- and net- don't, and iOS/macOS don't.)

then "different conversion, similar story" (even down to the details of
other OSes that do/don't have this) for %P as a synonym for %p:

@@ -305,6 +317,7 @@
  fields |= FIELD_TM_MON;
  break;

+ case 'P': /* Android addition for strftime() compat; glibc does this too.
*/
  case 'p': /* The locale's equivalent of AM/PM. */
  _LEGAL_ALT(0);
  /* AM? */

and now the interesting one... specifically the gmtime_r() vs localtime_r()
difference. as you can see from the comment, freebsd uses localtime_r() --
albeit in a complicated way where they use gmtime_r() but set a flag to
translate it back! -- and netbsd uses localtime_r() directly. i'm guessing
openbsd might be a mistranslation of the freebsd code, missing that freebsd
does two translations? glibc is localtime_r() too, fwiw. am i missing
something here, or is this indeed an accidental mistranslation of freebsd?
(or have _i_ misunderstood freebsd?)

(ignore the whole strtol() bit in the hunk --- that's just noise from me
papering over Android's 32-bit ABIs having a 32-bit time_t... another 5-10
years and we should be able to remove that! it's really just the gmtime_r()
vs localtime_r() bit that's actually interesting.)

@@ -340,11 +353,23 @@
  break;
  case 's': /* Seconds since epoch */
  {
- int64_t i64;
- if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
- return (NULL);
- if (!gmtime_r(&i64, tm))
- return (NULL);
+ // Android change based on FreeBSD's implementation.
+ int saved_errno = errno;
+ errno = 0;
+ const unsigned char* old_bp = bp;
+ long n = strtol((const char*) bp, (char**) &bp, 10);
+ errno = saved_errno;
+ time_t t = n;
+ if (bp == old_bp || errno == ERANGE ||
+    ((long) t) != n) return NULL;
+
+ if (localtime_r(&t, tm) == NULL) return NULL;
+
     fields = 0xffff; /* everything */
  }
  break;

Reply via email to