Safely & portably read a value into a predefined integral type of varying size like mode_t I need to read a value from a text file and put it into a predefined type, in this particular case mode_t. This typedef can have a variety of types underlying it, so what is the portable way to read such a value and assign it to a variable of the predefined type.

Since you have no idea how large the type is, I was starting under the assumption that you should read using strtoimax/strtoumax and then range check somehow.  What I came up with "works" (seemingly) but looks ugly to my eye.

For example:

static mode_t parse_mode ( const char * s ) {
    char *       e = NULL;
    uintmax_t    u;
    uintmax_t    x;
    mode_t       m;
    int          c;

    if ( s == NULL) goto error_no_value;
    if (*s == '\0') goto error_no_value;
    if (*s == '-' ) goto error_negative;
    errno = 0;
    u = strtoumax(s, &amp;e, 8);              /* value is in octal */
    if (errno) goto error_range;
    if (e == s) goto error_bogus;
    c = *e;
    if (c &amp;&amp; !isspace(c)) goto error_bogus;   /* WS after is OK */

    /* now the question part -- better way??? */
         if (sizeof(mode_t) == 1) x = UINT8_MAX;
    else if (sizeof(mode_t) == 2) x = UINT16_MAX;
    else if (sizeof(mode_t) == 4) x = UINT32_MAX;
    else if (sizeof(mode_t) == 8) x = UINT64_MAX;
    else goto error_what_size;
    if (u &gt; x) goto error_too_big;

    m = (mode_t)u;
    return m;
error_no_value: fprintf(stderr, "Error: no value\n");    return (mode_t)-1;
error_negative: fprintf(stderr, "Error: negative\n");    return (mode_t)-1;
error_range:    fprintf(stderr, "Error: range\n");       return (mode_t)-1;
error_bogus:    fprintf(stderr, "Error: bogus\n");       return (mode_t)-1;
error_what_size:fprintf(stderr, "Error: what size\n");   return (mode_t)-1;
error_too_big:  fprintf(stderr, "Error: too big\n");     return (mode_t)-1;
}


[I've totally glossed over the question of whether or not the type is signed or unsigned and just assumed unsigned here]

PS, yes, I have "secret knowledge" that no valid mode is likely to exceed 0177777; please ignore that as it is not necessarily true for other predefined types of its ilk.

PPS, junk like time_t which might not even be integral is not a part of this question

EDIT Added in the error goop.
Also, note that all leading whitespace has been skipped prior to this being called.
An alternative would be to store the value, then test whether any truncation occured:

m = u;
if (m != u) goto error_too_big;


I think some of the single-character variables (e, u, c, etc.) could be given better names.  The next person to modify the code (which could be Future You) will pick it up more quickly if it has meaningful variable names.