summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-05-30 18:08:31 -0700
committerKaz Kylheku <kaz@kylheku.com>2020-05-30 18:08:31 -0700
commit2364f7d445f7fd21695c0c651b1b80a581602980 (patch)
treec9e356ae8595260e7a589bed8e23a3626df4906f /stream.c
parent1f54ad5cc1d384d0818a6bf6cec20a95ecc5a5ae (diff)
downloadtxr-2364f7d445f7fd21695c0c651b1b80a581602980.tar.gz
txr-2364f7d445f7fd21695c0c651b1b80a581602980.tar.bz2
txr-2364f7d445f7fd21695c0c651b1b80a581602980.zip
streams: maintain integer format string detector.
* configure: provide LONGLONG_TYPE and INTPTR_TYPE macros in config.h that expand to a string literal capturing the original tokens of the type that was probed. * stream.c (struct fmt): Removed size member, replaced with type string. We can match format strings to the textual type, which will work even if we cannot compile that type. So that is to say, for instance the "%I64d" entry in the table is associated with "int64", whereas an expression like sizeof (int64) won't compile where that type doesn't exist. (fmt_tab): Replace sizes with type names. Also fix an issue: %llx was replicated in three rows of the table. (detect_format_string): Determine the textual type of cnum. It is a typedef for intptr_t, and the new INPTR_TYPE macro gives the tokens that were used to typedef intptr_t. If INTPTR_TYPE happens to be "longlong_t", we use LONGLONG_TYPE in its place. Then using the determined type, we can search the table for an appropriate entry: one which matches the type and whose conversion specifier works. Also, we now test all four conversion specifiers rather than assuming that if the decimal one is okay, the others work. Plus, if a working format string is not found, we now abort.
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/stream.c b/stream.c
index 23dfc30e..3cacb4dd 100644
--- a/stream.c
+++ b/stream.c
@@ -3071,7 +3071,7 @@ val get_line_as_buf(val stream_in)
}
struct fmt {
- size_t minsize;
+ const char *type;
const char *dec;
const char *oct;
const char *hex;
@@ -3079,13 +3079,14 @@ struct fmt {
};
static struct fmt fmt_tab[] = {
- { sizeof(short),"%hd", "%ho", "%hx", "%hX" },
- { sizeof(int), "%d", "%o", "%x", "%X" },
- { sizeof(long), "%ld", "%lo", "%lx", "%llX" },
- { sizeof(cnum), "%lld", "%llo", "%llx", "%llX" },
- { sizeof(cnum), "%Ld", "%Lo", "%Lx", "%llX" },
- { sizeof(cnum), "%qd", "%qo", "%qx", "%qX", },
- { sizeof(cnum), "%I64d", "%I64o", "%I64x", "%I64X" },
+ { "short", "%hd", "%ho", "%hx", "%hX" },
+ { "int", "%d", "%o", "%x", "%X" },
+ { "long", "%ld", "%lo", "%lx", "%lX" },
+ { "long long", "%lld", "%llo", "%llx", "%llX" },
+ { "long long", "%Ld", "%Lo", "%Lx", "%LX" },
+ { "long long", "%qd", "%qo", "%qx", "%qX", },
+ { "int64", "%I64d", "%I64o", "%I64x", "%I64X" },
+ { "__int64", "%I64d", "%I64o", "%I64x", "%I64X" },
{ 0, 0, 0, 0, 0 }
};
@@ -3096,16 +3097,29 @@ static void detect_format_string(void)
struct fmt *f;
char buf[64];
cnum num = 1234;
+ const char *cnum_type = if3(strcmp(INTPTR_TYPE, "longlong_t") == 0,
+ LONGLONG_TYPE, INTPTR_TYPE);
- for (f = fmt_tab; f->minsize != 0; f++) {
+ for (f = fmt_tab; f->type != 0; f++) {
+ if (strcmp(cnum_type, f->type) != 0)
+ continue;
memset(buf, 0, sizeof buf);
- if (f->minsize != sizeof num)
+ if (sprintf(buf, f->dec, num) != 4 || strcmp(buf, "1234") != 0)
continue;
- if (sprintf(buf, f->dec, num) == 4 && strcmp(buf, "1234") == 0) {
- num_fmt = f;
- break;
- }
+ memset(buf, 0, sizeof buf);
+ if (sprintf(buf, f->oct, num) != 4 || strcmp(buf, "2322") != 0)
+ continue;
+ memset(buf, 0, sizeof buf);
+ if (sprintf(buf, f->hex, num) != 3 || strcmp(buf, "4d2") != 0)
+ continue;
+ memset(buf, 0, sizeof buf);
+ if (sprintf(buf, f->HEX, num) != 3 || strcmp(buf, "4D2") != 0)
+ continue;
+ num_fmt = f;
+ break;
}
+
+ bug_unless (num_fmt != 0);
}
enum align { al_left, al_center, al_right };