+ size = SIZE_def;
+ switch (*p++) {
+ case 'h':
+ if (*p == 'h') p++, size = SIZE_hh;
+ else size = SIZE_h;
+ break;
+ case 'l':
+ if (*p == 'l') p++, size = SIZE_ll;
+ else size = SIZE_l;
+ break;
+ case 'j':
+ size = SIZE_ll;
+ break;
+ case 'z':
+ case 't':
+ size = SIZE_l;
+ break;
+ case 'L':
+ size = SIZE_L;
+ break;
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 's': case 'c': case '[':
+ case 'S': case 'C':
+ case 'p': case 'n':
+ p--;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ t = *p;
+
+ /* Transform ls,lc -> S,C */
+ if (size==SIZE_l && (t&15)==3) t&=~32;
+
+ if (t != 'n') {
+ if (t != '[' && (t|32) != 'c')
+ while (iswspace((c=getwc(f)))) pos++;
+ else
+ c=getwc(f);
+ if (c < 0) goto input_fail;
+ ungetwc(c, f);
+ }
+
+ switch (t) {
+ case 'n':
+ store_int(dest, size, pos);
+ /* do not increment match count, etc! */
+ continue;
+
+ case 'c':
+ if (width < 1) width = 1;
+ s = dest;
+ for (; width && (c=getwc(f)) >= 0; width--) {
+ int l = wctomb(s?s:tmp, c);
+ if (l<0) goto input_fail;
+ if (s) s+=l;
+ pos++;
+ }
+ if (width) goto match_fail;
+ break;
+
+ case 'C':
+ if (width < 1) width = 1;
+ wcs = dest;
+ for (; width && (c=getwc(f)) >= 0; width--)
+ pos++, wcs && (*wcs++ = c);
+ if (width) goto match_fail;
+ break;
+
+ case 's':
+ if (width < 1) width = -1;
+ s = dest;
+ while (width && !iswspace(c=getwc(f)) && c!=EOF) {
+ int l = wctomb(s?s:tmp, c);
+ if (l<0) goto input_fail;
+ if (s) s+=l;
+ pos++;
+ width-=(width>0);
+ }
+ if (width) ungetwc(c, f);
+ if (s) *s = 0;
+ break;
+
+ case 'S':
+ wcs = dest;
+ if (width < 1) width = -1;
+ while (width && !iswspace(c=getwc(f)) && c!=EOF)
+ width-=(width>0), pos++, *wcs++ = c;
+ if (width) ungetwc(c, f);
+ if (wcs) *wcs = 0;
+ break;
+
+ case '[':
+ s = (size == SIZE_def) ? dest : 0;
+ wcs = (size == SIZE_l) ? dest : 0;
+
+ if (*++p == '^') p++, invert = 1;
+ else invert = 0;
+
+ int gotmatch = 0;
+
+ if (width < 1) width = -1;
+
+ while (width) {
+ if ((c=getwc(f))<0) break;
+ if (in_set(p, c) == invert)
+ break;
+ if (wcs) {
+ *wcs++ = c;
+ } else if (size != SIZE_l) {
+ int l = wctomb(s?s:tmp, c);
+ if (l<0) goto input_fail;
+ if (s) s+=l;
+ }
+ pos++;
+ width-=(width>0);
+ gotmatch=1;
+ }
+ if (width) ungetwc(c, f);
+
+ if (!gotmatch) goto match_fail;
+
+ if (*p==']') p++;
+ while (*p!=']') {
+ if (!*p) goto fmt_fail;
+ p++;
+ }
+
+ if (wcs) *wcs++ = 0;
+ if (s) *s++ = 0;
+ break;
+
+ case 'd': case 'i': case 'o': case 'u': case 'x':
+ case 'a': case 'e': case 'f': case 'g':
+ case 'A': case 'E': case 'F': case 'G': case 'X':
+ case 'p':
+ if (width < 1) width = 0;
+ snprintf(tmp, sizeof tmp, "%.*s%.0d%s%c%%lln",
+ 1+!dest, "%*", width, size_pfx[size+2], t);
+ cnt = 0;
+ if (fscanf(f, tmp, dest?dest:&cnt, &cnt) == -1)
+ goto input_fail;
+ else if (!cnt)
+ goto match_fail;
+ pos += cnt;
+ break;
+ default:
+ goto fmt_fail;
+ }
+
+ if (dest) matches++;
+ }
+ if (0) {
+fmt_fail:
+input_fail:
+ if (!matches) matches--;
+ }
+match_fail:
+ FUNLOCK(f);
+ return matches;