diff --git a/src/buffer.c b/src/buffer.c index 668cd9c00b..294bc9b166 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2476,9 +2476,9 @@ buflist_list(eap) { IObuff[len++] = ' '; } while (--i > 0 && len < IOSIZE - 18); - sprintf((char *)IObuff + len, _("line %ld"), - buf == curbuf ? curwin->w_cursor.lnum : - (long)buflist_findlnum(buf)); + vim_snprintf((char *)IObuff + len, IOSIZE - len, _("line %ld"), + buf == curbuf ? curwin->w_cursor.lnum + : (long)buflist_findlnum(buf)); msg_outtrans(IObuff); out_flush(); /* output one line at a time */ ui_breakcheck(); @@ -2852,6 +2852,7 @@ fileinfo(fullname, shorthelp, dont_truncate) int n; char_u *p; char_u *buffer; + size_t len; buffer = alloc(IOSIZE); if (buffer == NULL) @@ -2878,7 +2879,8 @@ fileinfo(fullname, shorthelp, dont_truncate) (int)(IOSIZE - (p - buffer)), TRUE); } - sprintf((char *)buffer + STRLEN(buffer), + len = STRLEN(buffer); + vim_snprintf((char *)buffer + len, IOSIZE - len, "\"%s%s%s%s%s%s", curbufIsChanged() ? (shortmess(SHM_MOD) ? " [+]" : _(" [Modified]")) : " ", @@ -2906,24 +2908,27 @@ fileinfo(fullname, shorthelp, dont_truncate) else n = (int)(((long)curwin->w_cursor.lnum * 100L) / (long)curbuf->b_ml.ml_line_count); + len = STRLEN(buffer); if (curbuf->b_ml.ml_flags & ML_EMPTY) { - STRCPY(buffer + STRLEN(buffer), _(no_lines_msg)); + vim_snprintf((char *)buffer + len, IOSIZE - len, "%s", _(no_lines_msg)); } #ifdef FEAT_CMDL_INFO else if (p_ru) { /* Current line and column are already on the screen -- webb */ if (curbuf->b_ml.ml_line_count == 1) - sprintf((char *)buffer + STRLEN(buffer), _("1 line --%d%%--"), n); + vim_snprintf((char *)buffer + len, IOSIZE - len, + _("1 line --%d%%--"), n); else - sprintf((char *)buffer + STRLEN(buffer), _("%ld lines --%d%%--"), + vim_snprintf((char *)buffer + len, IOSIZE - len, + _("%ld lines --%d%%--"), (long)curbuf->b_ml.ml_line_count, n); } #endif else { - sprintf((char *)buffer + STRLEN(buffer), + vim_snprintf((char *)buffer + len, IOSIZE - len, _("line %ld of %ld --%d%%-- col "), (long)curwin->w_cursor.lnum, (long)curbuf->b_ml.ml_line_count, @@ -3630,7 +3635,8 @@ build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) if (*wp->w_buffer->b_p_ft != NUL && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) { - sprintf((char *)tmp, "[%s]", wp->w_buffer->b_p_ft); + vim_snprintf((char *)tmp, sizeof(tmp), "[%s]", + wp->w_buffer->b_p_ft); str = tmp; } break; @@ -3640,7 +3646,8 @@ build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) if (*wp->w_buffer->b_p_ft != NUL && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) { - sprintf((char *)tmp, ",%s", wp->w_buffer->b_p_ft); + vim_snprintf((char *)tmp, sizeof(tmp), ",%s", + wp->w_buffer->b_p_ft); for (t = tmp; *t != 0; t++) *t = TOUPPER_LOC(*t); str = tmp; @@ -3768,10 +3775,12 @@ build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) *t++ = '%'; *t = t[-3]; *++t = 0; - sprintf((char *)p, (char *)nstr, 0, num, n); + vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, + 0, num, n); } else - sprintf((char *)p, (char *)nstr, minwid, num); + vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, + minwid, num); p += STRLEN(p); } else @@ -3917,8 +3926,8 @@ build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) || defined(PROTO) /* - * Get relative cursor position in window, in the form 99%, using "Top", "Bot" - * or "All" when appropriate. + * Get relative cursor position in window into "str[]", in the form 99%, using + * "Top", "Bot" or "All" when appropriate. */ void get_rel_pos(wp, str) @@ -4694,7 +4703,7 @@ write_viminfo_bufferlist(fp) max_buffers = get_viminfo_parameter('%'); /* Allocate room for the file name, lnum and col. */ - line = alloc(MAXPATHL + 30); + line = alloc(MAXPATHL + 40); if (line == NULL) return; @@ -5076,22 +5085,13 @@ sign_list_placed(rbuf) { if (buf->b_signlist != NULL) { -#ifdef HAVE_SNPRINTF - snprintf -#else - sprintf -#endif - (lbuf, -#ifdef HAVE_SNPRINTF - BUFSIZ, -#endif - _("Signs for %s:"), buf->b_fname); + vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname); MSG_PUTS_ATTR(lbuf, hl_attr(HLF_D)); msg_putchar('\n'); } for (p = buf->b_signlist; p != NULL; p = p->next) { - sprintf(lbuf, _(" line=%ld id=%d name=%s"), + vim_snprintf(lbuf, BUFSIZ, _(" line=%ld id=%d name=%s"), (long)p->lnum, p->id, sign_typenr2name(p->typenr)); MSG_PUTS(lbuf); msg_putchar('\n'); diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 38a7d448c6..9d9062a8e8 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1054,21 +1054,11 @@ do_cmdline(cmdline, getline, cookie, flags) if (p_verbose >= 15 && sourcing_name != NULL) { - int c = -1; - ++no_wait_return; msg_scroll = TRUE; /* always scroll up, don't overwrite */ - /* Truncate long lines, smsg() can't handle that. */ - if (STRLEN(cmdline_copy) > 200) - { - c = cmdline_copy[200]; - cmdline_copy[200] = NUL; - } smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmdline_copy); msg_puts((char_u *)"\n"); /* don't overwrite this either */ - if (c >= 0) - cmdline_copy[200] = c; cmdline_row = msg_row; --no_wait_return; } @@ -1341,7 +1331,8 @@ do_cmdline(cmdline, getline, cookie, flags) switch (current_exception->type) { case ET_USER: - sprintf((char *)IObuff, _("E605: Exception not caught: %s"), + vim_snprintf((char *)IObuff, IOSIZE, + _("E605: Exception not caught: %s"), current_exception->value); p = vim_strsave(IObuff); break; @@ -4802,7 +4793,7 @@ check_more(message, forceit) if (n == 1) STRCPY(buff, _("1 more file to edit. Quit anyway?")); else - sprintf((char *)buff, + vim_snprintf((char *)buff, IOSIZE, _("%d more files to edit. Quit anyway?"), n); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) return OK; @@ -9902,6 +9893,10 @@ ex_viminfo(eap) #endif #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) +/* + * Make a dialog message in "buff[IOSIZE]". + * "format" must contain "%.*s". + */ void dialog_msg(buff, format, fname) char_u *buff; diff --git a/src/if_ruby.c b/src/if_ruby.c index 9ef504cff3..112b91e5db 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -474,7 +474,7 @@ static void error_print(int state) char *p; epath = rb_class_path(eclass); - snprintf(buff, BUFSIZ, "%s: %s", + vim_snprintf(buff, BUFSIZ, "%s: %s", RSTRING(epath)->ptr, RSTRING(einfo)->ptr); p = strchr(buff, '\n'); if (p) *p = '\0'; @@ -482,7 +482,7 @@ static void error_print(int state) } break; default: - snprintf(buff, BUFSIZ, _("E273: unknown longjmp status %d"), state); + vim_snprintf(buff, BUFSIZ, _("E273: unknown longjmp status %d"), state); EMSG(buff); break; } diff --git a/src/if_sniff.c b/src/if_sniff.c index 4cb0bee246..7730e5bdc4 100644 --- a/src/if_sniff.c +++ b/src/if_sniff.c @@ -817,14 +817,15 @@ HandleSniffRequest(buffer) vi_open_file(file); else if (buf!=curbuf) { - sprintf(VICommand, SelectBuf, file); + vim_snprintf(VICommand, sizeof(VICommand), SelectBuf, file); vi_exec_cmd(VICommand); } if (command == 'o') vi_set_cursor_pos((long)position); else { - sprintf(VICommand, GotoLine, (int)position); + vim_snprintf(VICommand, sizeof(VICommand), GotoLine, + (int)position); vi_exec_cmd(VICommand); } checkpcmark(); /* [mark.c] */ @@ -853,7 +854,7 @@ HandleSniffRequest(buffer) buf = vi_find_buffer(file); if (buf && !buf->b_changed) /* delete buffer only if not modified */ { - sprintf(VICommand, DeleteBuf, file); + vim_snprintf(VICommand, sizeof(VICommand), DeleteBuf, file); vi_exec_cmd(VICommand); } vi_open_file(new_path); @@ -875,7 +876,8 @@ HandleSniffRequest(buffer) buf->b_flags |= BF_CHECK_RO + BF_NEVERLOADED; if (writable && !buf->b_changed) { - sprintf(VICommand, UnloadBuf, file); + vim_snprintf(VICommand, sizeof(VICommand), UnloadBuf, + file); vi_exec_cmd(VICommand); } } @@ -895,7 +897,7 @@ HandleSniffRequest(buffer) if (tab_width > 0 && tab_width <= 16) { - sprintf(VICommand, SetTab, tab_width); + vim_snprintf(VICommand, sizeof(VICommand), SetTab, tab_width); vi_exec_cmd(VICommand); } break; @@ -1030,7 +1032,7 @@ SendRequest(command, symbol) } if (symbol) - sprintf(cmdstr, "%c%s%s%ld%s%s\n", + vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s%s%ld%s%s\n", command->cmd_code, buffer_name, sniff_rq_sep, @@ -1039,7 +1041,8 @@ SendRequest(command, symbol) symbol ); else - sprintf(cmdstr, "%c%s\n", command->cmd_code, buffer_name); + vim_snprintf(cmdstr, sizeof(cmdstr), "%c%s\n", + command->cmd_code, buffer_name); } else /* simple request */ { @@ -1051,7 +1054,8 @@ SendRequest(command, symbol) { if ((cmd_type & NEED_SYMBOL) && !(cmd_type & EMPTY_SYMBOL)) { - sprintf(msgtxt, "%s: %s", _(command->cmd_msg), symbol); + vim_snprintf(msgtxt, sizeof(msgtxt), "%s: %s", + _(command->cmd_msg), symbol); vi_msg(msgtxt); } else diff --git a/src/integration.c b/src/integration.c index 05a9dec3ff..48cac5353b 100644 --- a/src/integration.c +++ b/src/integration.c @@ -182,7 +182,8 @@ messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2) char buf[20]; ackNum = atoi(&cmd[4]); - sprintf(buf, NOCATGETS("ack %d\n"), ackNum); + vim_snprintf(buf, sizeof(buf), + NOCATGETS("ack %d\n"), ackNum); write(sd, buf, strlen(buf)); } else if (strncmp(cmd, NOCATGETS("addMarkType "), 12) == 0) { @@ -277,7 +278,8 @@ messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2) file = strtok(&cmd[12], " "); markid = atoi(strtok(NULL, " ")); line = workshop_get_mark_lineno(file, markid); - sprintf(buf, NOCATGETS("markLine %s %d %d\n"), + vim_snprintf(buf, sizeof(buf), + NOCATGETS("markLine %s %d %d\n"), file, markid, line); write(sd, buf, strlen(buf)); } else if (cmd[1] == 'o' && cmd[4] == 'L' && @@ -302,29 +304,34 @@ messageFromEserve(XtPointer clientData, int *NOTUSED1, XtInputId *NOTUSED2) } else if (strcmp(cmd, NOCATGETS("getCurrentFile")) == 0) { char *f = workshop_test_getcurrentfile(); char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("currentFile %d %s"), + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("currentFile %d %s"), f ? strlen(f) : 0, f ? f : ""); workshop_send_message(buffer); } else if (strcmp(cmd, NOCATGETS("getCursorRow")) == 0) { int row = workshop_test_getcursorrow(); char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("cursorRow %d"), row); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("cursorRow %d"), row); workshop_send_message(buffer); } else if (strcmp(cmd, NOCATGETS("getCursorCol")) == 0) { int col = workshop_test_getcursorcol(); char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("cursorCol %d"), col); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("cursorCol %d"), col); workshop_send_message(buffer); } else if (strcmp(cmd, NOCATGETS("getCursorRowText")) == 0) { char *t = workshop_test_getcursorrowtext(); char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("cursorRowText %d %s"), + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("cursorRowText %d %s"), t ? strlen(t) : 0, t ? t : ""); workshop_send_message(buffer); } else if (strcmp(cmd, NOCATGETS("getSelectedText")) == 0) { char *t = workshop_test_getselectedtext(); char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("selectedText %d %s"), + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("selectedText %d %s"), t ? strlen(t) : 0, t ? t : ""); workshop_send_message(buffer); #endif @@ -709,7 +716,7 @@ void workshop_connect(XtAppContext context) char buf[BUFSIZ]; unlink(file); - sprintf(buf, "date > %s", file); + vim_snprintf(buf, sizeof(buf), "date > %s", file); system(buf); dfd = fopen(file, "a"); } else { @@ -717,13 +724,13 @@ void workshop_connect(XtAppContext context) } #endif - sprintf(buf, NOCATGETS("connected %s %s %s\n"), + vim_snprintf(buf, sizeof(buf), NOCATGETS("connected %s %s %s\n"), workshop_get_editor_name(), PROTOCOL_VERSION, workshop_get_editor_version()); write(sd, buf, strlen(buf)); - sprintf(buf, NOCATGETS("ack 1\n")); + vim_snprintf(buf, sizeof(buf), NOCATGETS("ack 1\n")); write(sd, buf, strlen(buf)); } @@ -1047,21 +1054,24 @@ void workshop_set_option_first(char *name, char *value) void workshop_file_closed(char *filename) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("deletedFile %s\n"), filename); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("deletedFile %s\n"), filename); write(sd, buffer, strlen(buffer)); } void workshop_file_closed_lineno(char *filename, int lineno) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("deletedFile %s %d\n"), filename, lineno); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("deletedFile %s %d\n"), filename, lineno); write(sd, buffer, strlen(buffer)); } void workshop_file_opened(char *filename, int readOnly) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("loadedFile %s %d\n"), filename, readOnly); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("loadedFile %s %d\n"), filename, readOnly); write(sd, buffer, strlen(buffer)); } @@ -1069,7 +1079,8 @@ void workshop_file_opened(char *filename, int readOnly) void workshop_file_saved(char *filename) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("savedFile %s\n"), filename); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("savedFile %s\n"), filename); write(sd, buffer, strlen(buffer)); /* Let editor report any moved marks that the eserve client @@ -1080,14 +1091,16 @@ void workshop_file_saved(char *filename) void workshop_move_mark(char *filename, int markId, int newLineno) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("moveMark %s %d %d\n"), filename, markId, newLineno); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("moveMark %s %d %d\n"), filename, markId, newLineno); write(sd, buffer, strlen(buffer)); } void workshop_file_modified(char *filename) { char buffer[2*MAXPATHLEN]; - sprintf(buffer, NOCATGETS("modifiedFile %s\n"), filename); + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("modifiedFile %s\n"), filename); write(sd, buffer, strlen(buffer)); } @@ -1097,7 +1110,8 @@ void workshop_frame_moved(int new_x, int new_y, int new_w, int new_h) if (sd >= 0) { - sprintf(buffer, NOCATGETS("frameAt %d %d %d %d\n"), + vim_snprintf(buffer, sizeof(buffer), + NOCATGETS("frameAt %d %d %d %d\n"), new_x, new_y, new_w, new_h); write(sd, buffer, strlen(buffer)); } @@ -1150,7 +1164,8 @@ void workshop_perform_verb(char *verb, void *clientData) } } - sprintf(buf, NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"), + vim_snprintf(buf, sizeof(buf), + NOCATGETS("toolVerb %s %s %d,%d %d,%d %d,%d %d %s\n"), verb, filename, curLine, curCol, diff --git a/src/message.c b/src/message.c index 8b4a2b3f55..7efe28ca43 100644 --- a/src/message.c +++ b/src/message.c @@ -313,6 +313,15 @@ _RTLENTRYF smsg_attr __ARGS((int, char_u *, long, long, long, long, long, long, long, long, long, long)); +int vim_snprintf __ARGS((char *, size_t, char *, long, long, long, + long, long, long, long, long, long, long)); + +/* + * smsg(str, arg, ...) is like using sprintf(buf, str, arg, ...) and then + * calling msg(buf). + * The buffer used is IObuff, the message is truncated at IOSIZE. + */ + /* VARARGS */ int #ifdef __BORLANDC__ @@ -335,12 +344,16 @@ smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) char_u *s; long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; { - sprintf((char *)IObuff, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); return msg_attr(IObuff, attr); } # else /* HAVE_STDARG_H */ +int vim_snprintf(char *str, size_t str_m, char *fmt, ...); +static int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap); + int #ifdef __BORLANDC__ _RTLENTRYF @@ -350,11 +363,7 @@ smsg(char_u *s, ...) va_list arglist; va_start(arglist, s); -# ifdef HAVE_VSNPRINTF - vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist); -# else - vsprintf((char *)IObuff, (char *)s, arglist); -# endif + vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist); va_end(arglist); return msg(IObuff); } @@ -368,11 +377,7 @@ smsg_attr(int attr, char_u *s, ...) va_list arglist; va_start(arglist, s); -# ifdef HAVE_VSNPRINTF - vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist); -# else - vsprintf((char *)IObuff, (char *)s, arglist); -# endif + vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist); va_end(arglist); return msg_attr(IObuff, attr); } @@ -645,18 +650,7 @@ emsg3(s, a1, a2) #endif ) return TRUE; /* no error messages at the moment */ - - /* Check for NULL strings (just in case) */ - if (a1 == NULL) - a1 = (char_u *)"[NULL]"; - if (a2 == NULL) - a2 = (char_u *)"[NULL]"; - - /* Check for very long strings (can happen with ":help ^A"). */ - if (STRLEN(s) + STRLEN(a1) + STRLEN(a2) >= (size_t)IOSIZE) - a1 = a2 = (char_u *)_("[string too long]"); - - sprintf((char *)IObuff, (char *)s, (char *)a1, (char *)a2); + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, (char *)a1, (char *)a2); return emsg(IObuff); } @@ -674,7 +668,7 @@ emsgn(s, n) #endif ) return TRUE; /* no error messages at the moment */ - sprintf((char *)IObuff, (char *)s, n); + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n); return emsg(IObuff); } @@ -3205,3 +3199,699 @@ do_browse(flags, title, dflt, ext, initdir, filter, buf) return fname; } #endif + +/* + * This code was included to provide a portable vsnprintf() and snprintf(). + * Some systems may provide their own, but we always use these for + * consistency. + * + * This code is based on snprintf.c - a portable implementation of snprintf + * by Mark Martinec , Version 2.2, 2000-10-06. + * It was heavely modified to fit in Vim. + * The original code, including useful comments, can be found here: + * http://www.ijs.si/software/snprintf/ + * + * This snprintf() only supports the following conversion specifiers: + * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) + * with flags: '-', '+', ' ', '0' and '#'. + * An asterisk is supported for field width as well as precision. + * + * Length modifiers 'h' (short int) and 'l' (long int) are supported. + * 'll' (long long int) is not supported. + * + * It is permitted for str_m to be zero, and it is permitted to specify NULL + * pointer for resulting string argument if str_m is zero (as per ISO C99). + * + * The return value is the number of characters which would be generated + * for the given input, excluding the trailing null. If this value + * is greater or equal to str_m, not all characters from the result + * have been stored in str, output bytes beyond the (str_m-1) -th character + * are discarded. If str_m is greater than zero it is guaranteed + * the resulting string will be null-terminated. + */ + +/* + * When va_list is not supported we only define vim_snprintf(). + */ + +/* When generating prototypes all of this is skipped, cproto doesn't + * understand this. */ +#ifndef PROTO +# ifdef HAVE_STDARG_H + int +vim_snprintf(char *str, size_t str_m, char *fmt, ...) +{ + va_list ap; + int str_l; + + va_start(ap, fmt); + str_l = vim_vsnprintf(str, str_m, fmt, ap); + va_end(ap); + return str_l; +} + + static int +vim_vsnprintf(str, str_m, fmt, ap) +# else + /* clumsy way to work around missing va_list */ +# define get_a_arg(i) (i == 1 ? a1 : i == 2 ? a2 : i == 3 ? a3 : i == 4 ? a4 : i == 5 ? a5 : i == 6 ? a6 : i == 7 ? a7 : i == 8 ? a8 : i == 9 ? a9 : a10) + +/* VARARGS */ + int +#ifdef __BORLANDC__ +_RTLENTRYF +#endif +vim_snprintf(str, str_m, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) +# endif + char *str; + size_t str_m; + char *fmt; +# ifdef HAVE_STDARG_H + va_list ap; +# else + long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; +# endif +{ + size_t str_l = 0; + char *p = fmt; +# ifndef HAVE_STDARG_H + int arg_idx = 1; +# endif + + if (p == NULL) + p = ""; + while (*p != NUL) + { + if (*p != '%') + { + char *q = strchr(p + 1, '%'); + size_t n = (q == NULL) ? STRLEN(p) : (q - p); + + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, p, n > avail ? avail : n); + } + p += n; + str_l += n; + } + else + { + size_t min_field_width = 0, precision = 0; + int zero_padding = 0, precision_specified = 0, justify_left = 0; + int alternate_form = 0, force_sign = 0; + + /* If both the ' ' and '+' flags appear, the ' ' flag should be + * ignored. */ + int space_for_positive = 1; + + /* allowed values: \0, h, l, L */ + char length_modifier = '\0'; + + /* temporary buffer for simple numeric->string conversion */ + char tmp[32]; + + /* string address in case of string argument */ + char *str_arg; + + /* natural field width of arg without padding and sign */ + size_t str_arg_l; + + /* unsigned char argument value - only defined for c conversion. + * N.B. standard explicitly states the char argument for the c + * conversion is unsigned */ + unsigned char uchar_arg; + + /* number of zeros to be inserted for numeric conversions as + * required by the precision or minimal field width */ + size_t number_of_zeros_to_pad = 0; + + /* index into tmp where zero padding is to be inserted */ + size_t zero_padding_insertion_ind = 0; + + /* current conversion specifier character */ + char fmt_spec = '\0'; + + str_arg = NULL; + p++; /* skip '%' */ + + /* parse flags */ + while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' + || *p == '#' || *p == '\'') + { + switch (*p) + { + case '0': zero_padding = 1; break; + case '-': justify_left = 1; break; + case '+': force_sign = 1; space_for_positive = 0; break; + case ' ': force_sign = 1; + /* If both the ' ' and '+' flags appear, the ' ' + * flag should be ignored */ + break; + case '#': alternate_form = 1; break; + case '\'': break; + } + p++; + } + /* If the '0' and '-' flags both appear, the '0' flag should be + * ignored. */ + + /* parse field width */ + if (*p == '*') + { + int j; + + p++; +#ifndef HAVE_STDARG_H + j = get_a_arg(arg_idx); + ++arg_idx; +#else + j = va_arg(ap, int); +#endif + if (j >= 0) + min_field_width = j; + else + { + min_field_width = -j; + justify_left = 1; + } + } + else if (VIM_ISDIGIT((int)(*p))) + { + /* size_t could be wider than unsigned int; make sure we treat + * argument like common implementations do */ + unsigned int uj = *p++ - '0'; + + while (VIM_ISDIGIT((int)(*p))) + uj = 10 * uj + (unsigned int)(*p++ - '0'); + min_field_width = uj; + } + + /* parse precision */ + if (*p == '.') + { + p++; + precision_specified = 1; + if (*p == '*') + { + int j; + +#ifndef HAVE_STDARG_H + j = get_a_arg(arg_idx); + ++arg_idx; +#else + j = va_arg(ap, int); +#endif + p++; + if (j >= 0) + precision = j; + else + { + precision_specified = 0; + precision = 0; + } + } + else if (VIM_ISDIGIT((int)(*p))) + { + /* size_t could be wider than unsigned int; make sure we + * treat argument like common implementations do */ + unsigned int uj = *p++ - '0'; + + while (VIM_ISDIGIT((int)(*p))) + uj = 10 * uj + (unsigned int)(*p++ - '0'); + precision = uj; + } + } + + /* parse 'h', 'l' and 'll' length modifiers */ + if (*p == 'h' || *p == 'l') + { + length_modifier = *p; + p++; + if (length_modifier == 'l' && *p == 'l') + { + /* double l = long long */ + length_modifier = 'l'; /* treat it as a single 'l' */ + p++; + } + } + fmt_spec = *p; + + /* common synonyms: */ + switch (fmt_spec) + { + case 'i': fmt_spec = 'd'; break; + case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + default: break; + } + + /* get parameter value, do initial processing */ + switch (fmt_spec) + { + /* '%' and 'c' behave similar to 's' regarding flags and field + * widths */ + case '%': + case 'c': + case 's': + length_modifier = '\0'; + zero_padding = 0; /* turn zero padding off for string + conversions */ + str_arg_l = 1; + switch (fmt_spec) + { + case '%': + str_arg = p; + break; + + case 'c': + { + int j; +#ifndef HAVE_STDARG_H + j = get_a_arg(arg_idx); + ++arg_idx; +#else + j = va_arg(ap, int); +#endif + /* standard demands unsigned char */ + uchar_arg = (unsigned char)j; + str_arg = (char *)&uchar_arg; + break; + } + + case 's': +#ifndef HAVE_STDARG_H + str_arg = (char *)get_a_arg(arg_idx); + ++arg_idx; +#else + str_arg = va_arg(ap, char *); +#endif + if (str_arg == NULL) + { + str_arg = "[NULL]"; + str_arg_l = 6; + } + /* make sure not to address string beyond the specified + * precision !!! */ + else if (!precision_specified) + str_arg_l = strlen(str_arg); + /* truncate string if necessary as requested by precision */ + else if (precision == 0) + str_arg_l = 0; + else + { + /* memchr on HP does not like n > 2^31 !!! */ + char *q = memchr(str_arg, '\0', + precision <= 0x7fffffff ? precision + : 0x7fffffff); + str_arg_l = (q == NULL) ? precision : q - str_arg; + } + break; + + default: + break; + } + break; + + case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': + { + /* NOTE: the u, o, x, X and p conversion specifiers + * imply the value is unsigned; d implies a signed + * value */ + + /* 0 if numeric argument is zero (or if pointer is + * NULL for 'p'), +1 if greater than zero (or nonzero + * for unsigned arguments), -1 if negative (unsigned + * argument is never negative) */ + int arg_sign = 0; + + /* only defined for length modifier h, or for no + * length modifiers */ + int int_arg = 0; + unsigned int uint_arg = 0; + + /* only defined for length modifier l */ + long int long_arg = 0; + unsigned long int ulong_arg = 0; + + /* pointer argument value -only defined for p + * conversion */ + void *ptr_arg = NULL; + + if (fmt_spec == 'p') + { + length_modifier = '\0'; +#ifndef HAVE_STDARG_H + ptr_arg = (void *)get_a_arg(arg_idx); + ++arg_idx; +#else + ptr_arg = va_arg(ap, void *); +#endif + if (ptr_arg != NULL) + arg_sign = 1; + } + else if (fmt_spec == 'd') + { + /* signed */ + switch (length_modifier) + { + case '\0': + case 'h': + /* It is non-portable to specify a second argument + * of char or short to va_arg, because arguments + * seen by the called function are not char or + * short. C converts char and short arguments to + * int before passing them to a function. */ +#ifndef HAVE_STDARG_H + int_arg = get_a_arg(arg_idx); + ++arg_idx; +#else + int_arg = va_arg(ap, int); +#endif + if (int_arg > 0) + arg_sign = 1; + else if (int_arg < 0) + arg_sign = -1; + break; + case 'l': +#ifndef HAVE_STDARG_H + long_arg = get_a_arg(arg_idx); + ++arg_idx; +#else + long_arg = va_arg(ap, long int); +#endif + if (long_arg > 0) + arg_sign = 1; + else if (long_arg < 0) + arg_sign = -1; + break; + } + } + else + { + /* unsigned */ + switch (length_modifier) + { + case '\0': + case 'h': +#ifndef HAVE_STDARG_H + uint_arg = get_a_arg(arg_idx); + ++arg_idx; +#else + uint_arg = va_arg(ap, unsigned int); +#endif + if (uint_arg != 0) + arg_sign = 1; + break; + case 'l': +#ifndef HAVE_STDARG_H + ulong_arg = get_a_arg(arg_idx); + ++arg_idx; +#else + ulong_arg = va_arg(ap, unsigned long int); +#endif + if (ulong_arg != 0) + arg_sign = 1; + break; + } + } + + str_arg = tmp; + str_arg_l = 0; + + /* NOTE: + * For d, i, u, o, x, and X conversions, if precision is + * specified, the '0' flag should be ignored. This is so + * with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux, + * FreeBSD, NetBSD; but not with Perl. + */ + if (precision_specified) + zero_padding = 0; + if (fmt_spec == 'd') + { + if (force_sign && arg_sign >= 0) + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; + /* leave negative numbers for sprintf to handle, to + * avoid handling tricky cases like (short int)-32768 */ + } + else if (alternate_form) + { + if (arg_sign != 0 + && (fmt_spec == 'x' || fmt_spec == 'X') ) + { + tmp[str_arg_l++] = '0'; + tmp[str_arg_l++] = fmt_spec; + } + /* alternate form should have no effect for p + * conversion, but ... */ + } + + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) + precision = 1; /* default precision is 1 */ + if (precision == 0 && arg_sign == 0) + { + /* When zero value is formatted with an explicit + * precision 0, the resulting formatted string is + * empty (d, i, u, o, x, X, p). */ + } + else + { + char f[5]; + int f_l = 0; + + /* construct a simple format string for sprintf */ + f[f_l++] = '%'; + if (!length_modifier) + ; + else if (length_modifier == '2') + { + f[f_l++] = 'l'; + f[f_l++] = 'l'; + } + else + f[f_l++] = length_modifier; + f[f_l++] = fmt_spec; + f[f_l++] = '\0'; + + if (fmt_spec == 'p') + str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg); + else if (fmt_spec == 'd') + { + /* signed */ + switch (length_modifier) + { + case '\0': + case 'h': str_arg_l += sprintf( + tmp + str_arg_l, f, int_arg); + break; + case 'l': str_arg_l += sprintf( + tmp + str_arg_l, f, long_arg); + break; + } + } + else + { + /* unsigned */ + switch (length_modifier) + { + case '\0': + case 'h': str_arg_l += sprintf( + tmp + str_arg_l, f, uint_arg); + break; + case 'l': str_arg_l += sprintf( + tmp + str_arg_l, f, ulong_arg); + break; + } + } + + /* include the optional minus sign and possible + * "0x" in the region before the zero padding + * insertion point */ + if (zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '-') + zero_padding_insertion_ind++; + if (zero_padding_insertion_ind + 1 < str_arg_l + && tmp[zero_padding_insertion_ind] == '0' + && (tmp[zero_padding_insertion_ind + 1] == 'x' + || tmp[zero_padding_insertion_ind + 1] == 'X')) + zero_padding_insertion_ind += 2; + } + + { + size_t num_of_digits = str_arg_l + - zero_padding_insertion_ind; + + if (alternate_form && fmt_spec == 'o' + /* unless zero is already the first + * character */ + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0')) + { + /* assure leading zero for alternate-form + * octal numbers */ + if (!precision_specified + || precision < num_of_digits + 1) + { + /* precision is increased to force the + * first character to be zero, except if a + * zero value is formatted with an + * explicit precision of zero */ + precision = num_of_digits + 1; + precision_specified = 1; + } + } + /* zero padding to specified precision? */ + if (num_of_digits < precision) + number_of_zeros_to_pad = precision - num_of_digits; + } + /* zero padding to specified minimal field width? */ + if (!justify_left && zero_padding) + { + int n = min_field_width - (str_arg_l + + number_of_zeros_to_pad); + if (n > 0) + number_of_zeros_to_pad += n; + } + break; + } + + default: + /* unrecognized conversion specifier, keep format string + * as-is */ + zero_padding = 0; /* turn zero padding off for non-numeric + convers. */ + justify_left = 1; + min_field_width = 0; /* reset flags */ + + /* discard the unrecognized conversion, just keep * + * the unrecognized conversion character */ + str_arg = p; + str_arg_l = 0; + if (*p != NUL) + str_arg_l++; /* include invalid conversion specifier + unchanged if not at end-of-string */ + break; + } + + if (*p != NUL) + p++; /* step over the just processed conversion specifier */ + + /* insert padding to the left as requested by min_field_width; + * this does not include the zero padding in case of numerical + * conversions*/ + if (!justify_left) + { + /* left padding with blank or zero */ + int n = min_field_width - (str_arg_l + number_of_zeros_to_pad); + + if (n > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + vim_memset(str + str_l, zero_padding ? '0' : ' ', + n > avail ? avail : n); + } + str_l += n; + } + } + + /* zero padding as requested by the precision or by the minimal + * field width for numeric conversions required? */ + if (number_of_zeros_to_pad <= 0) + { + /* will not copy first part of numeric right now, * + * force it to be copied later in its entirety */ + zero_padding_insertion_ind = 0; + } + else + { + /* insert first part of numerics (sign or '0x') before zero + * padding */ + int n = zero_padding_insertion_ind; + + if (n > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, str_arg, + n > avail ? avail : n); + } + str_l += n; + } + + /* insert zero padding as requested by the precision or min + * field width */ + n = number_of_zeros_to_pad; + if (n > 0) + { + if (str_l < str_m) + { + size_t avail = str_m-str_l; + + vim_memset(str + str_l, '0', n > avail ? avail : n); + } + str_l += n; + } + } + + /* insert formatted string + * (or as-is conversion specifier for unknown conversions) */ + { + int n = str_arg_l - zero_padding_insertion_ind; + + if (n > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, + str_arg + zero_padding_insertion_ind, + n > avail ? avail : n); + } + str_l += n; + } + } + + /* insert right padding */ + if (justify_left) + { + /* right blank padding to the field width */ + int n = min_field_width - (str_arg_l + number_of_zeros_to_pad); + + if (n > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + vim_memset(str + str_l, ' ', n > avail ? avail : n); + } + str_l += n; + } + } + } + } + + if (str_m > 0) + { + /* make sure the string is null-terminated even at the expense of + * overwriting the last character (shouldn't happen, but just in case) + * */ + str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; + } + + /* Return the number of characters formatted (excluding trailing null + * character), that is, the number of characters that would have been + * written to the buffer if it were large enough. */ + return (int)str_l; +} + +#endif /* PROTO */ diff --git a/src/netbeans.c b/src/netbeans.c index 19d1697ede..f6fb52c4eb 100644 --- a/src/netbeans.c +++ b/src/netbeans.c @@ -403,7 +403,7 @@ netbeans_connect(void) } } - sprintf(buf, "AUTH %s\n", password); + vim_snprintf(buf, sizeof(buf), "AUTH %s\n", password); nb_send(buf, "netbeans_connect"); sprintf(buf, "0:version=0 \"%s\"\n", ExtEdProtocolVersion); @@ -2379,7 +2379,8 @@ special_keys(char_u *args) } strcpy(&keybuf[i], tok); - sprintf(cmdbuf, "<%s> :nbkey %s", keybuf, keybuf); + vim_snprintf(cmdbuf, sizeof(cmdbuf), + "<%s> :nbkey %s", keybuf, keybuf); do_map(0, (char_u *)cmdbuf, NORMAL, FALSE); tok = strtok(NULL, " "); } @@ -2516,7 +2517,8 @@ netbeans_beval_cb( p = nb_quote(text); if (p != NULL) { - sprintf(buf, "0:balloonText=%d \"%s\"\n", cmdno, p); + vim_snprintf(buf, sizeof(buf), + "0:balloonText=%d \"%s\"\n", cmdno, p); vim_free(p); } nbdebug(("EVT: %s", buf)); @@ -2613,7 +2615,7 @@ netbeans_file_activated(buf_T *bufp) if (q == NULL || bp == NULL || bufp == NULL) return; - sprintf(buffer, "%d:fileOpened=%d \"%s\" %s %s\n", + vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n", bufno, bufno, (char *)q, @@ -2649,7 +2651,7 @@ netbeans_file_opened(buf_T *bufp) else bnum = 0; - sprintf(buffer, "%d:fileOpened=%d \"%s\" %s %s\n", + vim_snprintf(buffer, sizeof(buffer), "%d:fileOpened=%d \"%s\" %s %s\n", bnum, 0, (char *)q, @@ -2913,7 +2915,7 @@ netbeans_keystring(int key, char *keyName) : nb_quote(curbuf->b_ffname); if (q == NULL) return; - sprintf(buf, "0:fileOpened=%d \"%s\" %s %s\n", 0, + vim_snprintf(buf, sizeof(buf), "0:fileOpened=%d \"%s\" %s %s\n", 0, q, "T", /* open in NetBeans */ "F"); /* modified */ @@ -2939,12 +2941,14 @@ netbeans_keystring(int key, char *keyName) */ /* now send keyCommand event */ - sprintf(buf, "%d:keyCommand=%d \"%s\"\n", bufno, cmdno, keyName); + vim_snprintf(buf, sizeof(buf), "%d:keyCommand=%d \"%s\"\n", + bufno, cmdno, keyName); nbdebug(("EVT: %s", buf)); nb_send(buf, "netbeans_keycommand"); /* New: do both at once and include the lnum/col. */ - sprintf(buf, "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n", bufno, cmdno, keyName, + vim_snprintf(buf, sizeof(buf), "%d:keyAtPos=%d \"%s\" %ld %ld/%ld\n", + bufno, cmdno, keyName, off, (long)curwin->w_cursor.lnum, (long)curwin->w_cursor.col); nbdebug(("EVT: %s", buf)); nb_send(buf, "netbeans_keycommand"); diff --git a/src/os_mac.c b/src/os_mac.c index cc656f061e..baab5a5a39 100644 --- a/src/os_mac.c +++ b/src/os_mac.c @@ -682,6 +682,7 @@ mch_get_user_name(s, len) && pw->pw_name != NULL && *(pw->pw_name) != NUL) { STRNCPY(s, pw->pw_name, len); + s[len - 1] = NUL; return OK; } #endif diff --git a/src/proto.h b/src/proto.h index cff55c3cee..e24ebb48fc 100644 --- a/src/proto.h +++ b/src/proto.h @@ -95,25 +95,32 @@ extern int _stricoll __ARGS((char *a, char *b)); # include "hashtable.pro" # include "main.pro" # include "mark.pro" +# include "memfile.pro" +# include "memline.pro" +# ifdef FEAT_MENU +# include "menu.pro" +# endif + # if !defined MESSAGE_FILE || defined(HAVE_STDARG_H) /* These prototypes cannot be produced automatically and conflict with * the old-style prototypes in message.c. */ int -#ifdef __BORLANDC__ +# ifdef __BORLANDC__ _RTLENTRYF -#endif +# endif smsg __ARGS((char_u *, ...)); int -#ifdef __BORLANDC__ +# ifdef __BORLANDC__ _RTLENTRYF -#endif +# endif smsg_attr __ARGS((int, char_u *, ...)); +int +# ifdef __BORLANDC__ +_RTLENTRYF +# endif +vim_snprintf __ARGS((char *, size_t, char *, ...)); # endif -# include "memfile.pro" -# include "memline.pro" -# ifdef FEAT_MENU -# include "menu.pro" -# endif + # include "message.pro" # include "misc1.pro" # include "misc2.pro" diff --git a/src/spell.c b/src/spell.c index cc2d4fbfd8..2a14da3150 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1332,13 +1332,15 @@ spell_load_lang(lang) else #endif p = (char_u *)"latin1"; - sprintf((char *)fname_enc, "spell/%s.%s.spl", lang, p); + vim_snprintf((char *)fname_enc, sizeof(fname_enc), + "spell/%s.%s.spl", lang, p); r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, lp); if (r == FAIL && !lp->sl_error) { /* Try loading the ASCII version. */ - sprintf((char *)fname_enc, "spell/%s.ascii.spl", lang); + vim_snprintf((char *)fname_enc, sizeof(fname_enc), + "spell/%s.ascii.spl", lang); r = do_in_runtimepath(fname_enc, TRUE, spell_load_file, lp); } @@ -4837,7 +4839,7 @@ ex_mkspell(eap) { /* Check for overwriting before doing things that may take a lot of * time. */ - sprintf((char *)wfname, "%s.%s.spl", fnames[0], + vim_snprintf((char *)wfname, sizeof(wfname), "%s.%s.spl", fnames[0], ascii ? (char_u *)"ascii" : p_enc); if (!eap->forceit && mch_stat((char *)wfname, &st) >= 0) { @@ -4887,12 +4889,12 @@ ex_mkspell(eap) { /* Read the .aff file. Will init "conv" based on the "SET" line. */ conv.vc_type = CONV_NONE; - sprintf((char *)fname, "%s.aff", fnames[i]); + vim_snprintf((char *)fname, sizeof(fname), "%s.aff", fnames[i]); if ((afile[i - 1] = spell_read_aff(fname, &conv, ascii)) == NULL) break; /* Read the .dic file. */ - sprintf((char *)fname, "%s.dic", fnames[i]); + vim_snprintf((char *)fname, sizeof(fname), "%s.dic", fnames[i]); if (spell_read_dic(&dfile[i - 1], fname, &conv, ascii) == FAIL) break;