E char *FDECL(nonconst, (const char *, char *));
E int FDECL(swapbits, (int, int, int));
E void FDECL(shuffle_int_array, (int *, int));
+/* note: the snprintf CPP wrapper includes the "fmt" argument in "..."
+ (__VA_ARGS__) to allow for zero arguments after fmt */
+#define Snprintf(str, size, ...) \
+ nh_snprintf(__func__, __LINE__, str, size, __VA_ARGS__)
+extern void nh_snprintf(const char *func, int line, char *str, size_t size,
+ const char *fmt, ...);
/* ### insight.c ### */
char * nonconst (const char *, char *)
int swapbits (int, int, int)
void shuffle_int_array (int *, int)
+ void nh_snprintf (const char *, int, char *, size_t,
+ const char *, ...)
=*/
#ifdef LINT
#define Static /* pacify lint */
}
}
+/*
+ * Wrap snprintf for use in the main code.
+ *
+ * Wrap reasons:
+ * 1. If there are any platform issues, we have one spot to fix them -
+ * snprintf is a routine with a troubling history of bad implementations.
+ * 2. Add combersome error checking in one spot. Problems with text wrangling
+ * do not have to be fatal.
+ * 3. Gcc 9+ will issue a warning unless the return value is used.
+ * Annoyingly, explicitly casting to void does not remove the error.
+ * So, use the result - see reason #2.
+ */
+void
+nh_snprintf(const char *func, int line, char *str, size_t size,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+#ifdef NO_VSNPRINTF
+ n = vsprintf(str, fmt, ap);
+#else
+ n = vsnprintf(str, size, fmt, ap);
+#endif
+ va_end(ap);
+ if (n < 0 || (size_t)n >= size) { /* is there a problem? */
+ impossible("snprintf %s: func %s, file line %d",
+ n < 0 ? "format error"
+ : "overflow",
+ func, line);
+ str[size-1] = 0; /* make sure it is nul terminated */
+ }
+}
+
/*hacklib.c*/
early_version_info(pastebuf)
boolean pastebuf;
{
- char buf[BUFSZ], buf2[BUFSZ];
- char *tmp = getversionstring(buf);
+ char buf1[BUFSZ], buf2[BUFSZ];
+ char *buf, *tmp;
- /* this is early enough that we have to do
- our own line-splitting */
+ Snprintf(buf1, sizeof(buf1), "test");
+ /* this is early enough that we have to do our own line-splitting */
+ getversionstring(buf1);
+ tmp = strstri(buf1, " ("); /* split at start of version info */
if (tmp) {
- tmp = strstri(buf," (");
- if (tmp) *tmp++ = '\0';
+ /* retain one buffer so that it all goes into the paste buffer */
+ *tmp++ = '\0';
+ Snprintf(buf2, sizeof(buf2), "%s\n%s", buf1, tmp);
+ buf = buf2;
+ } else {
+ buf = buf1;
}
- Sprintf(buf2, "%s\n", buf);
- if (tmp) Sprintf(eos(buf2), "%s\n", tmp);
- raw_printf("%s", buf2);
+ raw_printf("%s", buf);
if (pastebuf) {
#if defined(RUNTIME_PASTEBUF_SUPPORT) && !defined(LIBNH)
* version information into a paste buffer. Useful for
* easy inclusion in bug reports.
*/
- port_insert_pastebuf(buf2);
+ port_insert_pastebuf(buf);
#else
raw_printf("%s", "Paste buffer copy is not available.\n");
#endif
(void) skill_level_name(i, sklnambuf);
if (wizard) {
if (!iflags.menu_tab_sep)
- n = snprintf(buf, sizeof(buf), " %s%-*s %-12s %5d(%4d)", prefix,
- longest, P_NAME(i), sklnambuf, P_ADVANCE(i),
- practice_needed_to_advance(P_SKILL(i)));
+ Snprintf(buf, sizeof(buf), " %s%-*s %-12s %5d(%4d)", prefix,
+ longest, P_NAME(i), sklnambuf, P_ADVANCE(i),
+ practice_needed_to_advance(P_SKILL(i)));
else
- n = snprintf(buf, sizeof(buf), " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i),
- sklnambuf, P_ADVANCE(i),
- practice_needed_to_advance(P_SKILL(i)));
+ Snprintf(buf, sizeof(buf), " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i),
+ sklnambuf, P_ADVANCE(i),
+ practice_needed_to_advance(P_SKILL(i)));
} else {
if (!iflags.menu_tab_sep)
- n = snprintf(buf, sizeof(buf), " %s %-*s [%s]", prefix, longest,
- P_NAME(i), sklnambuf);
+ Snprintf(buf, sizeof(buf), " %s %-*s [%s]", prefix, longest,
+ P_NAME(i), sklnambuf);
else
- n = snprintf(buf, sizeof(buf), " %s%s\t[%s]", prefix, P_NAME(i),
- sklnambuf);
+ Snprintf(buf, sizeof(buf), " %s%s\t[%s]", prefix, P_NAME(i),
+ sklnambuf);
}
- if (n >= sizeof(buf)) /* check for overflow */
- buf[sizeof(buf)-1] = 0; /* terminate string */
any.a_int = can_advance(i, speedy) ? i + 1 : 0;
add_menu(win, &nul_glyphinfo, &any, 0, 0,
ATR_NONE, buf, MENU_ITEMFLAGS_NONE);