From d723e7fd61d48b037a2b8360162efa1cddad64d2 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 29 Jun 2014 15:23:24 -0400 Subject: [PATCH 1/4] keep statusline within window width. @oni-link fix #858 PR #866 ref #858 --- src/nvim/screen.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 54dcaff39e..67e00d6a27 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -5099,7 +5099,7 @@ win_redr_custom ( curattr = attr; p = buf; for (n = 0; hltab[n].start != NULL; n++) { - len = (int)(hltab[n].start - p); + int len = (int)(hltab[n].start - p); screen_puts_len(p, len, row, col, curattr); col += vim_strnsize(p, len); p = hltab[n].start; @@ -5113,7 +5113,8 @@ win_redr_custom ( else curattr = highlight_user[hltab[n].userhl - 1]; } - screen_puts(p, row, col, curattr); + // Make sure to use an empty string instead of p, if p is beyond buf + len. + screen_puts(p >= buf + len ? (char_u *)"" : p, row, col, curattr); if (wp == NULL) { /* Fill the TabPageIdxs[] array for clicking in the tab pagesline. */ From be3a4b6ca81c4e9dd3faa81dc01f53468ceed3ad Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Mon, 9 Jun 2014 00:02:50 -0300 Subject: [PATCH 2/4] ga_growsize should be >= 1 I know it could be 0 sometimes. Running the tests with `assert(gap->ga_growsize > 0)` in ga_grow() crashes nvim while running the tests. - Add a setter for ga_growsize that checks whether the value passed is >=1 (log in case it's not) - log when ga_grow() tries to use a ga_growsize that's not >=1 - use GA_EMPTY_INIT_VALUE is many places --- src/nvim/ex_cmds2.c | 2 +- src/nvim/garray.c | 34 ++++++++++++++++++++++++++++------ src/nvim/garray.h | 2 +- src/nvim/globals.h | 2 +- src/nvim/hardcopy.c | 2 +- src/nvim/menu.c | 2 +- src/nvim/message.c | 4 ++-- src/nvim/misc1.c | 2 +- src/nvim/option.c | 2 +- src/nvim/regexp.c | 8 ++++---- src/nvim/syntax.c | 19 ++++++++++--------- 11 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 93822ebcfe..af6227d965 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2790,7 +2790,7 @@ char_u *getsourceline(int c, void *cookie, int indent) /* Adjust the growsize to the current length to speed up * concatenating many lines. */ if (ga.ga_len > 400) { - ga.ga_growsize = (ga.ga_len > 8000) ? 8000 : ga.ga_len; + ga_set_growsize(&ga, (ga.ga_len > 8000) ? 8000 : ga.ga_len); } ga_concat(&ga, p + 1); } diff --git a/src/nvim/garray.c b/src/nvim/garray.c index ac5f9155b1..aaf1b3bd2b 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -6,6 +6,7 @@ #include "nvim/vim.h" #include "nvim/ascii.h" +#include "nvim/log.h" #include "nvim/misc2.h" #include "nvim/memory.h" #include "nvim/path.h" @@ -52,7 +53,21 @@ void ga_init(garray_T *gap, int itemsize, int growsize) gap->ga_maxlen = 0; gap->ga_len = 0; gap->ga_itemsize = itemsize; - gap->ga_growsize = growsize; + ga_set_growsize(gap, growsize); +} + +/// A setter for the growsize that guarantees it will be at least 1. +/// +/// @param gap +/// @param growsize +void ga_set_growsize(garray_T *gap, int growsize) +{ + if (growsize < 1) { + WLOG("trying to set an invalid ga_growsize: %d", growsize); + gap->ga_growsize = 1; + } else { + gap->ga_growsize = growsize; + } } /// Make room in growing array "gap" for at least "n" items. @@ -66,17 +81,24 @@ void ga_grow(garray_T *gap, int n) return; } - // the garray grows by at least growsize (do we have a MIN macro somewhere?) - n = (n < gap->ga_growsize) ? gap->ga_growsize : n; + if (gap->ga_growsize < 1) { + WLOG("ga_growsize(%d) is less than 1", gap->ga_growsize); + } - size_t new_size = (size_t)(gap->ga_itemsize * (gap->ga_len + n)); + // the garray grows by at least growsize + if (n < gap->ga_growsize) { + n = gap->ga_growsize; + } + int new_maxlen = gap->ga_len + n; + + size_t new_size = (size_t)(gap->ga_itemsize * new_maxlen); size_t old_size = (size_t)(gap->ga_itemsize * gap->ga_maxlen); // reallocate and clear the new memory - char_u *pp = xrealloc(gap->ga_data, new_size); + char *pp = xrealloc(gap->ga_data, new_size); memset(pp + old_size, 0, new_size - old_size); - gap->ga_maxlen = gap->ga_len + n; + gap->ga_maxlen = new_maxlen; gap->ga_data = pp; } diff --git a/src/nvim/garray.h b/src/nvim/garray.h index 6e440039dd..df5740c553 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -12,7 +12,7 @@ typedef struct growarray { void *ga_data; // pointer to the first item } garray_T; -#define GA_EMPTY_INIT_VALUE { 0, 0, 0, 0, NULL } +#define GA_EMPTY_INIT_VALUE { 0, 0, 0, 1, NULL } #define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 8394f57f51..1035788d03 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -969,7 +969,7 @@ EXTERN int need_cursor_line_redraw INIT(= FALSE); /* Grow array to collect error messages in until they can be displayed. */ EXTERN garray_T error_ga # ifdef DO_INIT - = {0, 0, 0, 0, NULL} + = GA_EMPTY_INIT_VALUE # endif ; #endif diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index be6d8ee0ee..8db4c264b2 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -1285,7 +1285,7 @@ static int prt_collate; * Buffers used when generating PostScript output */ static char_u prt_line_buffer[257]; -static garray_T prt_ps_buffer; +static garray_T prt_ps_buffer = GA_EMPTY_INIT_VALUE; static int prt_do_conv; static vimconv_T prt_conv; diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 4d75bc1475..ad6bcc82da 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1434,7 +1434,7 @@ typedef struct { char_u *to; /* translated name */ } menutrans_T; -static garray_T menutrans_ga = {0, 0, 0, 0, NULL}; +static garray_T menutrans_ga = GA_EMPTY_INIT_VALUE; /* * ":menutrans". diff --git a/src/nvim/message.c b/src/nvim/message.c index 1571e8678f..1a42fba4a4 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2257,8 +2257,8 @@ void mch_errmsg(char *str) emsg_on_display = FALSE; len = (int)STRLEN(str) + 1; - if (error_ga.ga_growsize == 0) { - error_ga.ga_growsize = 80; + if (error_ga.ga_data == NULL) { + ga_set_growsize(&error_ga, 80); error_ga.ga_itemsize = 1; } ga_grow(&error_ga, len); diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index f025ff7f65..c4b2977435 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -58,7 +58,7 @@ # include "misc1.c.generated.h" #endif /* All user names (for ~user completion as done by shell). */ -static garray_T ga_users; +static garray_T ga_users = GA_EMPTY_INIT_VALUE; /* * open_line: Add a new line below or above the current line. diff --git a/src/nvim/option.c b/src/nvim/option.c index 8390efe979..9f9c9c279c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -7499,7 +7499,7 @@ typedef struct { int to; } langmap_entry_T; -static garray_T langmap_mapga; +static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE; /* * Search for an entry in "langmap_mapga" for "from". If found set the "to" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index ea61436e05..29f090c6b7 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3180,8 +3180,8 @@ static int reg_line_lbr; /* "\n" in string is line break */ * or regbehind_T. * "backpos_T" is a table with backpos_T for BACK */ -static garray_T regstack = {0, 0, 0, 0, NULL}; -static garray_T backpos = {0, 0, 0, 0, NULL}; +static garray_T regstack = GA_EMPTY_INIT_VALUE; +static garray_T backpos = GA_EMPTY_INIT_VALUE; /* * Both for regstack and backpos tables we use the following strategy of @@ -3319,13 +3319,13 @@ static long bt_regexec_both(char_u *line, * onto the regstack. */ ga_init(®stack, 1, REGSTACK_INITIAL); ga_grow(®stack, REGSTACK_INITIAL); - regstack.ga_growsize = REGSTACK_INITIAL * 8; + ga_set_growsize(®stack, REGSTACK_INITIAL * 8); } if (backpos.ga_data == NULL) { ga_init(&backpos, sizeof(backpos_T), BACKPOS_INITIAL); ga_grow(&backpos, BACKPOS_INITIAL); - backpos.ga_growsize = BACKPOS_INITIAL * 8; + ga_set_growsize(&backpos, BACKPOS_INITIAL * 8); } if (REG_MULTI) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 621c6f0d55..cb83bf650c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -75,7 +75,8 @@ struct hl_group { #define SG_GUI 4 /* gui has been set */ #define SG_LINK 8 /* link has been set */ -static garray_T highlight_ga; /* highlight groups for 'highlight' option */ +// highlight groups for 'highlight' option +static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data))) @@ -360,7 +361,7 @@ static int current_state_stored = 0; /* TRUE if stored current state * after setting current_finished */ static int current_finished = 0; /* current line has been finished */ static garray_T current_state /* current stack of state_items */ - = {0, 0, 0, 0, NULL}; + = GA_EMPTY_INIT_VALUE; static short *current_next_list = NULL; /* when non-zero, nextgroup list */ static int current_next_flags = 0; /* flags for current_next_list */ static int current_line_id = 0; /* unique number for current line */ @@ -1452,7 +1453,7 @@ static void invalidate_current_state(void) static void validate_current_state(void) { current_state.ga_itemsize = sizeof(stateitem_T); - current_state.ga_growsize = 3; + ga_set_growsize(¤t_state, 3); } /* @@ -4746,7 +4747,7 @@ static int syn_add_cluster(char_u *name) */ if (curwin->w_s->b_syn_clusters.ga_data == NULL) { curwin->w_s->b_syn_clusters.ga_itemsize = sizeof(syn_cluster_T); - curwin->w_s->b_syn_clusters.ga_growsize = 10; + ga_set_growsize(&curwin->w_s->b_syn_clusters, 10); } int len = curwin->w_s->b_syn_clusters.ga_len; @@ -4846,7 +4847,7 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing) static void init_syn_patterns(void) { curwin->w_s->b_syn_patterns.ga_itemsize = sizeof(synpat_T); - curwin->w_s->b_syn_patterns.ga_growsize = 10; + ga_set_growsize(&curwin->w_s->b_syn_patterns, 10); } /* @@ -6731,11 +6732,11 @@ static void highlight_clear(int idx) * Note that this table is used by ALL buffers. This is required because the * GUI can redraw at any time for any buffer. */ -static garray_T term_attr_table = {0, 0, 0, 0, NULL}; +static garray_T term_attr_table = GA_EMPTY_INIT_VALUE; #define TERM_ATTR_ENTRY(idx) ((attrentry_T *)term_attr_table.ga_data)[idx] -static garray_T cterm_attr_table = {0, 0, 0, 0, NULL}; +static garray_T cterm_attr_table = GA_EMPTY_INIT_VALUE; #define CTERM_ATTR_ENTRY(idx) ((attrentry_T *)cterm_attr_table.ga_data)[idx] @@ -6755,7 +6756,7 @@ static int get_attr_entry(garray_T *table, attrentry_T *aep) * Init the table, in case it wasn't done yet. */ table->ga_itemsize = sizeof(attrentry_T); - table->ga_growsize = 7; + ga_set_growsize(table, 7); /* * Try to find an entry with the same specifications. @@ -7311,7 +7312,7 @@ static int syn_add_group(char_u *name) */ if (highlight_ga.ga_data == NULL) { highlight_ga.ga_itemsize = sizeof(struct hl_group); - highlight_ga.ga_growsize = 10; + ga_set_growsize(&highlight_ga, 10); } if (highlight_ga.ga_len >= MAX_HL_ID) { From 45e7814e6aa8aacd8772056863d13770d4e30b48 Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Wed, 25 Jun 2014 22:03:58 -0300 Subject: [PATCH 3/4] Introduce GA_APPEND() This macro is used to append an element to a growable array. It replaces this common idiom: ga_grow(&ga, 1); ((item_type *)ga.ga_data)[ga.ga_len] = item; ++ga.ga_len; --- src/nvim/eval.c | 6 ++---- src/nvim/ex_cmds.c | 8 ++------ src/nvim/ex_cmds2.c | 8 +++----- src/nvim/ex_getln.c | 11 ++--------- src/nvim/garray.c | 5 +---- src/nvim/garray.h | 6 ++++++ src/nvim/os/users.c | 5 +---- src/nvim/path.c | 16 ++++------------ src/nvim/spell.c | 3 +-- src/nvim/syntax.c | 4 +--- src/nvim/tag.c | 3 +-- src/nvim/undo.c | 3 +-- 12 files changed, 25 insertions(+), 53 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3abc148e8f..4e0f5c9137 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14420,8 +14420,7 @@ error: } } - /* add a terminating NUL */ - ga_grow(&ga, 1); + // add a terminating NUL ga_append(&ga, NUL); rettv->vval.v_string = ga.ga_data; @@ -17640,8 +17639,7 @@ script_autoload ( else { /* Remember the name if it wasn't loaded already. */ if (i == ga_loaded.ga_len) { - ga_grow(&ga_loaded, 1); - ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname; + GA_APPEND(char_u *, &ga_loaded, scriptname); tofree = NULL; } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index fb6ec70f57..a04f93a851 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5446,11 +5446,9 @@ helptags_one ( ga_init(&ga, (int)sizeof(char_u *), 100); if (add_help_tags || path_full_compare((char_u *)"$VIMRUNTIME/doc", dir, FALSE) == kEqualFiles) { - ga_grow(&ga, 1); s = xmalloc(18 + STRLEN(tagfname)); sprintf((char *)s, "help-tags\t%s\t1\n", tagfname); - ((char_u **)ga.ga_data)[ga.ga_len] = s; - ++ga.ga_len; + GA_APPEND(char_u *, &ga, s); } /* @@ -5517,10 +5515,8 @@ helptags_one ( || s[1] == '\0')) { *p2 = '\0'; ++p1; - ga_grow(&ga, 1); s = xmalloc((p2 - p1) + STRLEN(fname) + 2); - ((char_u **)ga.ga_data)[ga.ga_len] = s; - ++ga.ga_len; + GA_APPEND(char_u *, &ga, s); sprintf((char *)s, "%s\t%s", p1, fname); /* find next '*' */ diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index af6227d965..0b0026829f 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1525,8 +1525,7 @@ void get_arglist(garray_T *gap, char_u *str) { ga_init(gap, (int)sizeof(char_u *), 20); while (*str != NUL) { - ga_grow(gap, 1); - ((char_u **)gap->ga_data)[gap->ga_len++] = str; + GA_APPEND(char_u *, gap, str); /* Isolate one argument, change it in-place, put a NUL after it. */ str = do_one_arg(str); @@ -3332,13 +3331,12 @@ static char_u **find_locales(void) loc = (char_u *)strtok((char *)locale_a, "\n"); while (loc != NULL) { - ga_grow(&locales_ga, 1); loc = vim_strsave(loc); - - ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc; + GA_APPEND(char_u *, &locales_ga, loc); loc = (char_u *)strtok(NULL, "\n"); } free(locale_a); + // Guarantee that .ga_data is NULL terminated ga_grow(&locales_ga, 1); ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL; return (char_u **)locales_ga.ga_data; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 9b09abb1b7..90430b3f6b 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4000,10 +4000,7 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, continue; } - ga_grow(&ga, 1); - - ((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, (int)(e - s)); - ++ga.ga_len; + GA_APPEND(char_u *, &ga, vim_strnsave(s, (int)(e - s))); *e = keep; if (*e != NUL) @@ -4034,11 +4031,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file) if (li->li_tv.v_type != VAR_STRING || li->li_tv.vval.v_string == NULL) continue; /* Skip non-string items and empty strings */ - ga_grow(&ga, 1); - - ((char_u **)ga.ga_data)[ga.ga_len] = - vim_strsave(li->li_tv.vval.v_string); - ++ga.ga_len; + GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string)); } list_unref(retlist); diff --git a/src/nvim/garray.c b/src/nvim/garray.c index aaf1b3bd2b..2cef08ef5f 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -197,10 +197,7 @@ void ga_concat(garray_T *gap, const char_u *restrict s) /// @param c void ga_append(garray_T *gap, char c) { - ga_grow(gap, 1); - char *str = gap->ga_data; - str[gap->ga_len] = c; - gap->ga_len++; + GA_APPEND(char, gap, c); } #if defined(UNIX) || defined(WIN3264) || defined(PROTO) diff --git a/src/nvim/garray.h b/src/nvim/garray.h index df5740c553..ed5e2dbada 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -16,6 +16,12 @@ typedef struct growarray { #define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0) +#define GA_APPEND(item_type, gap, item) \ + do { \ + ga_grow(gap, 1); \ + ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ + } while (0) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "garray.h.generated.h" #endif diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index e687ff3546..b6c013fa59 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -21,16 +21,13 @@ int os_get_usernames(garray_T *users) ga_init(users, sizeof(char *), 20); # if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H) - char *user; struct passwd *pw; setpwent(); while ((pw = getpwent()) != NULL) { // pw->pw_name shouldn't be NULL but just in case... if (pw->pw_name != NULL) { - ga_grow(users, 1); - user = xstrdup(pw->pw_name); - ((char **)(users->ga_data))[users->ga_len++] = user; + GA_APPEND(char *, users, xstrdup(pw->pw_name)); } } endpwent(); diff --git a/src/nvim/path.c b/src/nvim/path.c index 093a13db7b..1231d16ed8 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -625,7 +625,6 @@ static void expand_path_option(char_u *curdir, garray_T *gap) char_u *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char_u *buf; - char_u *p; int len; buf = xmalloc(MAXPATHL); @@ -639,7 +638,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap) * "/path/file" + "./subdir" -> "/path/subdir" */ if (curbuf->b_ffname == NULL) continue; - p = path_tail(curbuf->b_ffname); + char_u *p = path_tail(curbuf->b_ffname); len = (int)(p - curbuf->b_ffname); if (len + (int)STRLEN(buf) >= MAXPATHL) continue; @@ -666,10 +665,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap) simplify_filename(buf); } - ga_grow(gap, 1); - - p = vim_strsave(buf); - ((char_u **)gap->ga_data)[gap->ga_len++] = p; + GA_APPEND(char_u *, gap, vim_strsave(buf)); } free(buf); @@ -1194,7 +1190,6 @@ addfile ( int flags ) { - char_u *p; bool isdir; /* if the file/dir doesn't exist, may not add it */ @@ -1215,10 +1210,7 @@ addfile ( if (!isdir && (flags & EW_EXEC) && !os_can_exe(f)) return; - /* Make room for another item in the file list. */ - ga_grow(gap, 1); - - p = xmalloc(STRLEN(f) + 1 + isdir); + char_u *p = xmalloc(STRLEN(f) + 1 + isdir); STRCPY(p, f); #ifdef BACKSLASH_IN_FILENAME @@ -1231,7 +1223,7 @@ addfile ( if (isdir && (flags & EW_ADDSLASH)) add_pathsep(p); #endif - ((char_u **)gap->ga_data)[gap->ga_len++] = p; + GA_APPEND(char_u *, gap, p); } #endif /* !NO_EXPANDPATH */ diff --git a/src/nvim/spell.c b/src/nvim/spell.c index ca522191b9..711f892d16 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -9138,8 +9138,7 @@ someerror: if (c < 0) { goto someerror; } - ga_grow(&ga, 1); - ((char_u *)ga.ga_data)[ga.ga_len++] = c; + GA_APPEND(char_u, &ga, c); if (c == NUL) break; } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index cb83bf650c..945172564b 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -1963,9 +1963,7 @@ syn_current_attr ( /* Add the index to a list, so that we can check * later that we don't match it again (and cause an * endless loop). */ - ga_grow(&zero_width_next_ga, 1); - ((int *)(zero_width_next_ga.ga_data)) - [zero_width_next_ga.ga_len++] = next_match_idx; + GA_APPEND(int, &zero_width_next_ga, next_match_idx); next_match_idx = -1; } else cur_si = push_next_match(cur_si); diff --git a/src/nvim/tag.c b/src/nvim/tag.c index c9a065391b..8c873283f0 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1995,8 +1995,7 @@ static garray_T tag_fnames = GA_EMPTY_INIT_VALUE; */ static void found_tagfile_cb(char_u *fname, void *cookie) { - ga_grow(&tag_fnames, 1); - ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = vim_strsave(fname); + GA_APPEND(char_u *, &tag_fnames, vim_strsave(fname)); } #if defined(EXITFREE) || defined(PROTO) diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 37fa150aee..8fe05290c2 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2249,7 +2249,6 @@ void ex_undolist(exarg_T *eap) while (uhp != NULL) { if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark && uhp->uh_walk != mark) { - ga_grow(&ga, 1); vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ", uhp->uh_seq, changes); u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), @@ -2260,7 +2259,7 @@ void ex_undolist(exarg_T *eap) vim_snprintf_add((char *)IObuff, IOSIZE, " %3ld", uhp->uh_save_nr); } - ((char_u **)(ga.ga_data))[ga.ga_len++] = vim_strsave(IObuff); + GA_APPEND(char_u *, &ga, vim_strsave(IObuff)); } uhp->uh_walk = mark; From 5ed74cfb7c67f79441343ec90548f333dad1729b Mon Sep 17 00:00:00 2001 From: Felipe Oliveira Carvalho Date: Wed, 11 Jun 2014 03:01:46 -0300 Subject: [PATCH 4/4] Introduce ga_append_via_ptr() and GA_APPEND_VIA_PTR() Similar to GA_APPEND(). Replaces this pattern: ga_grow(&ga, 1); item_type *p = ((item_type *)ga.ga_data) + ga.ga_len; p->field1 = v1; p->field2 = v2; ga.ga_len++; --- src/nvim/digraph.c | 11 ++----- src/nvim/eval.c | 11 +++---- src/nvim/ex_docmd.c | 7 ++--- src/nvim/garray.h | 15 +++++++++ src/nvim/menu.c | 13 +++----- src/nvim/regexp.c | 11 ++----- src/nvim/spell.c | 48 +++++++++++----------------- src/nvim/syntax.c | 77 ++++++++++++++++++--------------------------- 8 files changed, 82 insertions(+), 111 deletions(-) diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index a0834e9da9..396aac3ba9 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1619,12 +1619,10 @@ void putdigraph(char_u *str) // Add a new digraph to the table. if (i == user_digraphs.ga_len) { - ga_grow(&user_digraphs, 1); - dp = (digr_T *)user_digraphs.ga_data + user_digraphs.ga_len; + dp = GA_APPEND_VIA_PTR(digr_T, &user_digraphs); dp->char1 = char1; dp->char2 = char2; dp->result = n; - ++user_digraphs.ga_len; } } } @@ -1772,7 +1770,6 @@ void ex_loadkeymap(exarg_T *eap) char_u *line; char_u *p; char_u *s; - kmap_T *kp; #define KMAP_LLEN 200 // max length of "to" and "from" together char_u buf[KMAP_LLEN + 11]; @@ -1803,8 +1800,7 @@ void ex_loadkeymap(exarg_T *eap) p = skipwhite(line); if ((*p != '"') && (*p != NUL)) { - ga_grow(&curbuf->b_kmap_ga, 1); - kp = (kmap_T *)curbuf->b_kmap_ga.ga_data + curbuf->b_kmap_ga.ga_len; + kmap_T *kp = GA_APPEND_VIA_PTR(kmap_T, &curbuf->b_kmap_ga); s = skiptowhite(p); kp->from = vim_strnsave(p, (int)(s - p)); p = skipwhite(s); @@ -1819,8 +1815,7 @@ void ex_loadkeymap(exarg_T *eap) } free(kp->from); free(kp->to); - } else { - ++curbuf->b_kmap_ga.ga_len; + --curbuf->b_kmap_ga.ga_len; } } free(line); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 4e0f5c9137..15967f484b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5290,8 +5290,7 @@ list_join_inner ( len = (int)STRLEN(s); sumlen += len; - ga_grow(join_gap, 1); - p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); + p = GA_APPEND_VIA_PTR(join_T, join_gap); if (tofree != NULL || s != numbuf) { p->s = s; p->tofree = tofree; @@ -10218,11 +10217,9 @@ static void f_inputrestore(typval_T *argvars, typval_T *rettv) */ static void f_inputsave(typval_T *argvars, typval_T *rettv) { - /* Add an entry to the stack of typeahead storage. */ - ga_grow(&ga_userinput, 1); - save_typeahead((tasave_T *)(ga_userinput.ga_data) - + ga_userinput.ga_len); - ++ga_userinput.ga_len; + // Add an entry to the stack of typeahead storage. + tasave_T *p = GA_APPEND_VIA_PTR(tasave_T, &ga_userinput); + save_typeahead(p); } /* diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 701a51799f..963fd33371 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1037,10 +1037,9 @@ static char_u *get_loop_line(int c, void *cookie, int indent) */ static void store_loop_line(garray_T *gap, char_u *line) { - ga_grow(gap, 1); - ((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line); - ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum; - ++gap->ga_len; + wcmd_T *p = GA_APPEND_VIA_PTR(wcmd_T, gap); + p->line = vim_strsave(line); + p->lnum = sourcing_lnum; } /* diff --git a/src/nvim/garray.h b/src/nvim/garray.h index ed5e2dbada..5a90da21c2 100644 --- a/src/nvim/garray.h +++ b/src/nvim/garray.h @@ -1,6 +1,8 @@ #ifndef NVIM_GARRAY_H #define NVIM_GARRAY_H +#include "nvim/log.h" + /// Structure used for growing arrays. /// This is used to store information that only grows, is deleted all at /// once, and needs to be accessed by index. See ga_clear() and ga_grow(). @@ -22,7 +24,20 @@ typedef struct growarray { ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ } while (0) +#define GA_APPEND_VIA_PTR(item_type, gap) \ + ga_append_via_ptr(gap, sizeof(item_type)) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "garray.h.generated.h" #endif + +static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size) +{ + if ((int)item_size != gap->ga_itemsize) { + ELOG("wrong item size in garray(%d), should be %d", item_size); + } + ga_grow(gap, 1); + return ((char *)gap->ga_data) + (item_size * (size_t)gap->ga_len++); +} + #endif // NVIM_GARRAY_H diff --git a/src/nvim/menu.c b/src/nvim/menu.c index ad6bcc82da..ab5c1569dc 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1444,7 +1444,6 @@ static garray_T menutrans_ga = GA_EMPTY_INIT_VALUE; void ex_menutranslate(exarg_T *eap) { char_u *arg = eap->arg; - menutrans_T *tp; char_u *from, *from_noamp, *to; if (menutrans_ga.ga_itemsize == 0) @@ -1454,7 +1453,7 @@ void ex_menutranslate(exarg_T *eap) * ":menutrans clear": clear all translations. */ if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) { - tp = (menutrans_T *)menutrans_ga.ga_data; + menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data; for (int i = 0; i < menutrans_ga.ga_len; ++i) { free(tp[i].from); free(tp[i].from_noamp); @@ -1473,8 +1472,6 @@ void ex_menutranslate(exarg_T *eap) if (arg == to) EMSG(_(e_invarg)); else { - ga_grow(&menutrans_ga, 1); - tp = (menutrans_T *)menutrans_ga.ga_data; from = vim_strsave(from); from_noamp = menu_text(from, NULL, NULL); to = vim_strnsave(to, (int)(arg - to)); @@ -1483,10 +1480,10 @@ void ex_menutranslate(exarg_T *eap) menu_translate_tab_and_shift(to); menu_unescape_name(from); menu_unescape_name(to); - tp[menutrans_ga.ga_len].from = from; - tp[menutrans_ga.ga_len].from_noamp = from_noamp; - tp[menutrans_ga.ga_len].to = to; - ++menutrans_ga.ga_len; + menutrans_T* tp = GA_APPEND_VIA_PTR(menutrans_T, &menutrans_ga); + tp->from = from; + tp->from_noamp = from_noamp; + tp->to = to; } else { free(from); free(from_noamp); diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 29f090c6b7..0ead83e0d4 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -4177,7 +4177,6 @@ regmatch ( case BACK: { int i; - backpos_T *bp; /* * When we run into BACK we need to check if we don't keep @@ -4187,17 +4186,13 @@ regmatch ( * The positions are stored in "backpos" and found by the * current value of "scan", the position in the RE program. */ - bp = (backpos_T *)backpos.ga_data; + backpos_T *bp = (backpos_T *)backpos.ga_data; for (i = 0; i < backpos.ga_len; ++i) if (bp[i].bp_scan == scan) break; if (i == backpos.ga_len) { - /* First time at this BACK, make room to store the pos. */ - ga_grow(&backpos, 1); - /* get "ga_data" again, it may have changed */ - bp = (backpos_T *)backpos.ga_data; - bp[i].bp_scan = scan; - ++backpos.ga_len; + backpos_T *p = GA_APPEND_VIA_PTR(backpos_T, &backpos); + p->bp_scan = scan; } else if (reg_save_equal(&bp[i].bp_pos)) /* Still at same position as last time, fail. */ status = RA_NOMATCH; diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 711f892d16..2f88c2d523 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -3335,7 +3335,6 @@ static int init_syl_tab(slang_T *slang) char_u *p; char_u *s; int l; - syl_item_T *syl; ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4); p = vim_strchr(slang->sl_syllable, '/'); @@ -3351,9 +3350,8 @@ static int init_syl_tab(slang_T *slang) l = (int)(p - s); if (l >= SY_MAXLEN) return SP_FORMERROR; - ga_grow(&slang->sl_syl_items, 1); - syl = ((syl_item_T *)slang->sl_syl_items.ga_data) - + slang->sl_syl_items.ga_len++; + + syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items); STRLCPY(syl->sy_chars, s, l + 1); syl->sy_len = l; } @@ -3835,10 +3833,10 @@ char_u *did_set_spelllang(win_T *wp) } if (region_mask != 0) { - ga_grow(&ga, 1); - LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang; - LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask; - ++ga.ga_len; + langp_T *p = GA_APPEND_VIA_PTR(langp_T, &ga); + p->lp_slang = slang; + p->lp_region = region_mask; + use_midword(slang, wp); if (slang->sl_nobreak) nobreak = TRUE; @@ -3896,7 +3894,6 @@ char_u *did_set_spelllang(win_T *wp) slang->sl_nobreak = TRUE; } if (slang != NULL) { - ga_grow(&ga, 1); region_mask = REGION_ALL; if (use_region != NULL && !dont_use_region) { // find region in sl_regions @@ -3909,11 +3906,12 @@ char_u *did_set_spelllang(win_T *wp) } if (region_mask != 0) { - LANGP_ENTRY(ga, ga.ga_len)->lp_slang = slang; - LANGP_ENTRY(ga, ga.ga_len)->lp_sallang = NULL; - LANGP_ENTRY(ga, ga.ga_len)->lp_replang = NULL; - LANGP_ENTRY(ga, ga.ga_len)->lp_region = region_mask; - ++ga.ga_len; + langp_T *p = GA_APPEND_VIA_PTR(langp_T, &ga); + p->lp_slang = slang; + p->lp_sallang = NULL; + p->lp_replang = NULL; + p->lp_region = region_mask; + use_midword(slang, wp); } } @@ -4851,16 +4849,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname) break; } if (idx < 0) { - ga_grow(&spin->si_prefcond, 1); // Not found, add a new condition. - idx = spin->si_prefcond.ga_len++; - pp = ((char_u **)spin->si_prefcond.ga_data) - + idx; - if (aff_entry->ae_cond == NULL) - *pp = NULL; - else - *pp = getroom_save(spin, - aff_entry->ae_cond); + idx = spin->si_prefcond.ga_len; + pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond); + *pp = (aff_entry->ae_cond == NULL) ? + NULL : getroom_save(spin, aff_entry->ae_cond); } // Add the prefix to the prefix tree. @@ -5328,16 +5321,13 @@ static int str_equal(char_u *s1, char_u *s2) // They are stored case-folded. static void add_fromto(spellinfo_T *spin, garray_T *gap, char_u *from, char_u *to) { - fromto_T *ftp; char_u word[MAXWLEN]; - ga_grow(gap, 1); - ftp = ((fromto_T *)gap->ga_data) + gap->ga_len; + fromto_T *ftp = GA_APPEND_VIA_PTR(fromto_T, gap); (void)spell_casefold(from, (int)STRLEN(from), word, MAXWLEN); ftp->ft_from = getroom_save(spin, word); (void)spell_casefold(to, (int)STRLEN(to), word, MAXWLEN); ftp->ft_to = getroom_save(spin, word); - ++gap->ga_len; } // Convert a boolean argument in a SAL line to TRUE or FALSE; @@ -11503,9 +11493,8 @@ add_suggestion ( } if (i < 0) { - ga_grow(gap, 1); // Add a suggestion. - stp = &SUG(*gap, gap->ga_len); + stp = GA_APPEND_VIA_PTR(suggest_T, gap); stp->st_word = vim_strnsave(goodword, goodlen); stp->st_wordlen = goodlen; stp->st_score = score; @@ -11513,7 +11502,6 @@ add_suggestion ( stp->st_had_bonus = had_bonus; stp->st_orglen = badlen; stp->st_slang = slang; - ++gap->ga_len; // If we have too many suggestions now, sort the list and keep // the best suggestions. diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 945172564b..0ce8d6e16f 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -2485,10 +2485,9 @@ update_si_end ( */ static void push_current_state(int idx) { - ga_grow(¤t_state, 1); - memset(&CUR_STATE(current_state.ga_len), 0, sizeof(stateitem_T)); - CUR_STATE(current_state.ga_len).si_idx = idx; - ++current_state.ga_len; + stateitem_T *p = GA_APPEND_VIA_PTR(stateitem_T, ¤t_state); + memset(p, 0, sizeof(*p)); + p->si_idx = idx; } /* @@ -4279,28 +4278,26 @@ syn_cmd_match ( if (!ends_excmd(*rest) || eap->skip) rest = NULL; else { - ga_grow(&curwin->w_s->b_syn_patterns, 1); if ((syn_id = syn_check_group(arg, (int)(group_name_end - arg))) != 0) { syn_incl_toplevel(syn_id, &syn_opt_arg.flags); /* * Store the pattern in the syn_items list */ - int idx = curwin->w_s->b_syn_patterns.ga_len; - SYN_ITEMS(curwin->w_s)[idx] = item; - SYN_ITEMS(curwin->w_s)[idx].sp_syncing = syncing; - SYN_ITEMS(curwin->w_s)[idx].sp_type = SPTYPE_MATCH; - SYN_ITEMS(curwin->w_s)[idx].sp_syn.id = syn_id; - SYN_ITEMS(curwin->w_s)[idx].sp_syn.inc_tag = current_syn_inc_tag; - SYN_ITEMS(curwin->w_s)[idx].sp_flags = syn_opt_arg.flags; - SYN_ITEMS(curwin->w_s)[idx].sp_sync_idx = sync_idx; - SYN_ITEMS(curwin->w_s)[idx].sp_cont_list = syn_opt_arg.cont_list; - SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list = - syn_opt_arg.cont_in_list; - SYN_ITEMS(curwin->w_s)[idx].sp_cchar = conceal_char; + synpat_T *spp = GA_APPEND_VIA_PTR(synpat_T, + &curwin->w_s->b_syn_patterns); + *spp = item; + spp->sp_syncing = syncing; + spp->sp_type = SPTYPE_MATCH; + spp->sp_syn.id = syn_id; + spp->sp_syn.inc_tag = current_syn_inc_tag; + spp->sp_flags = syn_opt_arg.flags; + spp->sp_sync_idx = sync_idx; + spp->sp_cont_list = syn_opt_arg.cont_list; + spp->sp_syn.cont_in_list = syn_opt_arg.cont_in_list; + spp->sp_cchar = conceal_char; if (syn_opt_arg.cont_in_list != NULL) curwin->w_s->b_syn_containedin = TRUE; - SYN_ITEMS(curwin->w_s)[idx].sp_next_list = syn_opt_arg.next_list; - ++curwin->w_s->b_syn_patterns.ga_len; + spp->sp_next_list = syn_opt_arg.next_list; /* remember that we found a match for syncing on */ if (syn_opt_arg.flags & (HL_SYNC_HERE|HL_SYNC_THERE)) @@ -4755,16 +4752,12 @@ static int syn_add_cluster(char_u *name) return 0; } - /* - * Make room for at least one other cluster entry. - */ - ga_grow(&curwin->w_s->b_syn_clusters, 1); - - memset(&(SYN_CLSTR(curwin->w_s)[len]), 0, sizeof(syn_cluster_T)); - SYN_CLSTR(curwin->w_s)[len].scl_name = name; - SYN_CLSTR(curwin->w_s)[len].scl_name_u = vim_strsave_up(name); - SYN_CLSTR(curwin->w_s)[len].scl_list = NULL; - ++curwin->w_s->b_syn_clusters.ga_len; + syn_cluster_T *scp = GA_APPEND_VIA_PTR(syn_cluster_T, + &curwin->w_s->b_syn_clusters); + memset(scp, 0, sizeof(*scp)); + scp->scl_name = name; + scp->scl_name_u = vim_strsave_up(name); + scp->scl_list = NULL; if (STRICMP(name, "Spell") == 0) curwin->w_s->b_spell_cluster_id = len + SYNID_CLUSTER; @@ -5701,8 +5694,7 @@ static void syntime_report(void) for (int idx = 0; idx < curwin->w_s->b_syn_patterns.ga_len; ++idx) { spp = &(SYN_ITEMS(curwin->w_s)[idx]); if (spp->sp_time.count > 0) { - ga_grow(&ga, 1); - p = ((time_entry_T *)ga.ga_data) + ga.ga_len; + p = GA_APPEND_VIA_PTR(time_entry_T, &ga); p->total = spp->sp_time.total; profile_add(&total_total, &spp->sp_time.total); p->count = spp->sp_time.count; @@ -5713,7 +5705,6 @@ static void syntime_report(void) p->average = tm; p->id = spp->sp_syn.id; p->pattern = spp->sp_pattern; - ++ga.ga_len; } } @@ -6810,10 +6801,8 @@ static int get_attr_entry(garray_T *table, attrentry_T *aep) /* * This is a new combination of colors and font, add an entry. */ - ga_grow(table, 1); - - taep = &(((attrentry_T *)table->ga_data)[table->ga_len]); - memset(taep, 0, sizeof(attrentry_T)); + taep = GA_APPEND_VIA_PTR(attrentry_T, table); + memset(taep, 0, sizeof(*taep)); taep->ae_attr = aep->ae_attr; if (table == &term_attr_table) { if (aep->ae_u.term.start == NULL) @@ -6828,7 +6817,7 @@ static int get_attr_entry(garray_T *table, attrentry_T *aep) taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color; taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color; } - ++table->ga_len; + return table->ga_len - 1 + ATTR_OFF; } @@ -7319,15 +7308,11 @@ static int syn_add_group(char_u *name) return 0; } - /* - * Make room for at least one other syntax_highlight entry. - */ - ga_grow(&highlight_ga, 1); - - memset(&(HL_TABLE()[highlight_ga.ga_len]), 0, sizeof(struct hl_group)); - HL_TABLE()[highlight_ga.ga_len].sg_name = name; - HL_TABLE()[highlight_ga.ga_len].sg_name_u = vim_strsave_up(name); - ++highlight_ga.ga_len; + // Append another syntax_highlight entry. + struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga); + memset(hlgp, 0, sizeof(*hlgp)); + hlgp->sg_name = name; + hlgp->sg_name_u = vim_strsave_up(name); return highlight_ga.ga_len; /* ID is index plus one */ }