To: vim_dev@googlegroups.com Subject: Patch 7.4.2046 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.2046 Problem: The qf_init_ext() function is too big. Solution: Refactor it. (Yegappan Lakshmanan) Files: src/quickfix.c *** ../vim-7.4.2045/src/quickfix.c 2016-07-10 22:11:11.870751341 +0200 --- src/quickfix.c 2016-07-15 22:28:26.189971916 +0200 *************** *** 187,217 **** */ #define LINE_MAXLEN 4096 - static char_u * - qf_grow_linebuf(char_u **growbuf, int *growbufsiz, int newsz, int *allocsz) - { - /* - * If the line exceeds LINE_MAXLEN exclude the last - * byte since it's not a NL character. - */ - *allocsz = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; - if (*growbuf == NULL) - { - *growbuf = alloc(*allocsz + 1); - if (*growbuf == NULL) - return NULL; - *growbufsiz = *allocsz; - } - else if (*allocsz > *growbufsiz) - { - *growbuf = vim_realloc(*growbuf, *allocsz + 1); - if (*growbuf == NULL) - return NULL; - *growbufsiz = *allocsz; - } - return *growbuf; - } - static struct fmtpattern { char_u convchar; --- 187,192 ---- *************** *** 496,501 **** --- 471,770 ---- return fmt_first; } + enum { + QF_FAIL = 0, + QF_OK = 1, + QF_END_OF_INPUT = 2, + QF_NOMEM = 3 + }; + + typedef struct { + char_u *linebuf; + int linelen; + char_u *growbuf; + int growbufsiz; + FILE *fd; + typval_T *tv; + char_u *p_str; + listitem_T *p_li; + buf_T *buf; + linenr_T buflnum; + linenr_T lnumlast; + } qfstate_T; + + static char_u * + qf_grow_linebuf(qfstate_T *state, int newsz) + { + /* + * If the line exceeds LINE_MAXLEN exclude the last + * byte since it's not a NL character. + */ + state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; + if (state->growbuf == NULL) + { + state->growbuf = alloc(state->linelen + 1); + if (state->growbuf == NULL) + return NULL; + state->growbufsiz = state->linelen; + } + else if (state->linelen > state->growbufsiz) + { + state->growbuf = vim_realloc(state->growbuf, state->linelen + 1); + if (state->growbuf == NULL) + return NULL; + state->growbufsiz = state->linelen; + } + return state->growbuf; + } + + /* + * Get the next string (separated by newline) from state->p_str. + */ + static int + qf_get_next_str_line(qfstate_T *state) + { + /* Get the next line from the supplied string */ + char_u *p_str = state->p_str; + char_u *p; + int len; + + if (*p_str == NUL) /* Reached the end of the string */ + return QF_END_OF_INPUT; + + p = vim_strchr(p_str, '\n'); + if (p != NULL) + len = (int)(p - p_str) + 1; + else + len = (int)STRLEN(p_str); + + if (len > IOSIZE - 2) + { + state->linebuf = qf_grow_linebuf(state, len); + if (state->linebuf == NULL) + return QF_NOMEM; + } + else + { + state->linebuf = IObuff; + state->linelen = len; + } + vim_strncpy(state->linebuf, p_str, state->linelen); + + /* + * Increment using len in order to discard the rest of the + * line if it exceeds LINE_MAXLEN. + */ + p_str += len; + state->p_str = p_str; + + return QF_OK; + } + + /* + * Get the next string from state->p_Li. + */ + static int + qf_get_next_list_line(qfstate_T *state) + { + listitem_T *p_li = state->p_li; + int len; + + while (p_li != NULL + && (p_li->li_tv.v_type != VAR_STRING + || p_li->li_tv.vval.v_string == NULL)) + p_li = p_li->li_next; /* Skip non-string items */ + + if (p_li == NULL) /* End of the list */ + { + state->p_li = NULL; + return QF_END_OF_INPUT; + } + + len = (int)STRLEN(p_li->li_tv.vval.v_string); + if (len > IOSIZE - 2) + { + state->linebuf = qf_grow_linebuf(state, len); + if (state->linebuf == NULL) + return QF_NOMEM; + } + else + { + state->linebuf = IObuff; + state->linelen = len; + } + + vim_strncpy(state->linebuf, p_li->li_tv.vval.v_string, state->linelen); + + state->p_li = p_li->li_next; /* next item */ + return QF_OK; + } + + /* + * Get the next string from state->buf. + */ + static int + qf_get_next_buf_line(qfstate_T *state) + { + char_u *p_buf = NULL; + int len; + + /* Get the next line from the supplied buffer */ + if (state->buflnum > state->lnumlast) + return QF_END_OF_INPUT; + + p_buf = ml_get_buf(state->buf, state->buflnum, FALSE); + state->buflnum += 1; + + len = (int)STRLEN(p_buf); + if (len > IOSIZE - 2) + { + state->linebuf = qf_grow_linebuf(state, len); + if (state->linebuf == NULL) + return QF_NOMEM; + } + else + { + state->linebuf = IObuff; + state->linelen = len; + } + vim_strncpy(state->linebuf, p_buf, state->linelen); + + return QF_OK; + } + + /* + * Get the next string from file state->fd. + */ + static int + qf_get_next_file_line(qfstate_T *state) + { + int discard; + int growbuflen; + + if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) + return QF_END_OF_INPUT; + + discard = FALSE; + state->linelen = (int)STRLEN(IObuff); + if (state->linelen == IOSIZE - 1 && !(IObuff[state->linelen - 1] == '\n' + #ifdef USE_CRNL + || IObuff[state->linelen - 1] == '\r' + #endif + )) + { + /* + * The current line exceeds IObuff, continue reading using + * growbuf until EOL or LINE_MAXLEN bytes is read. + */ + if (state->growbuf == NULL) + { + state->growbufsiz = 2 * (IOSIZE - 1); + state->growbuf = alloc(state->growbufsiz); + if (state->growbuf == NULL) + return QF_NOMEM; + } + + /* Copy the read part of the line, excluding null-terminator */ + memcpy(state->growbuf, IObuff, IOSIZE - 1); + growbuflen = state->linelen; + + for (;;) + { + if (fgets((char *)state->growbuf + growbuflen, + state->growbufsiz - growbuflen, state->fd) == NULL) + break; + state->linelen = (int)STRLEN(state->growbuf + growbuflen); + growbuflen += state->linelen; + if ((state->growbuf)[growbuflen - 1] == '\n' + #ifdef USE_CRNL + || (state->growbuf)[growbuflen - 1] == '\r' + #endif + ) + break; + if (state->growbufsiz == LINE_MAXLEN) + { + discard = TRUE; + break; + } + + state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN + ? 2 * state->growbufsiz : LINE_MAXLEN; + state->growbuf = vim_realloc(state->growbuf, state->growbufsiz); + if (state->growbuf == NULL) + return QF_NOMEM; + } + + while (discard) + { + /* + * The current line is longer than LINE_MAXLEN, continue + * reading but discard everything until EOL or EOF is + * reached. + */ + if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL + || (int)STRLEN(IObuff) < IOSIZE - 1 + || IObuff[IOSIZE - 1] == '\n' + #ifdef USE_CRNL + || IObuff[IOSIZE - 1] == '\r' + #endif + ) + break; + } + + state->linebuf = state->growbuf; + state->linelen = growbuflen; + } + else + state->linebuf = IObuff; + + return QF_OK; + } + + /* + * Get the next string from a file/buffer/list/string. + */ + static int + qf_get_nextline(qfstate_T *state) + { + int status = QF_FAIL; + + if (state->fd == NULL) + { + if (state->tv != NULL) + { + if (state->tv->v_type == VAR_STRING) + /* Get the next line from the supplied string */ + status = qf_get_next_str_line(state); + else if (state->tv->v_type == VAR_LIST) + /* Get the next line from the supplied list */ + status = qf_get_next_list_line(state); + } + else + /* Get the next line from the supplied buffer */ + status = qf_get_next_buf_line(state); + } + else + /* Get the next line from the supplied file */ + status = qf_get_next_file_line(state); + + if (status != QF_OK) + return status; + + /* remove newline/CR from the line */ + if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n') + state->linebuf[state->linelen - 1] = NUL; + #ifdef USE_CRNL + if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\r') + state->linebuf[state->linelen - 1] = NUL; + #endif + + #ifdef FEAT_MBYTE + remove_bom(state->linebuf); + #endif + + return QF_OK; + } + /* * Read the errorfile "efile" into memory, line by line, building the error * list. *************** *** 522,541 **** char_u *errmsg; int errmsglen; char_u *pattern; ! char_u *growbuf = NULL; ! int growbuflen; ! int growbufsiz = 0; ! char_u *linebuf = NULL; ! int linelen = 0; ! int discard; int col = 0; char_u use_viscol = FALSE; int type = 0; int valid; - linenr_T buflnum = lnumfirst; long lnum = 0L; int enr = 0; - FILE *fd = NULL; #ifdef FEAT_WINDOWS qfline_T *old_last = NULL; #endif --- 791,804 ---- char_u *errmsg; int errmsglen; char_u *pattern; ! qfstate_T state = {NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, ! NULL, lnumfirst, lnumlast}; int col = 0; char_u use_viscol = FALSE; int type = 0; int valid; long lnum = 0L; int enr = 0; #ifdef FEAT_WINDOWS qfline_T *old_last = NULL; #endif *************** *** 549,558 **** int i; int idx = 0; int retval = -1; /* default: return error flag */ char_u *tail = NULL; - char_u *p_buf = NULL; - char_u *p_str = NULL; - listitem_T *p_li = NULL; regmatch_T regmatch; namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); --- 812,819 ---- int i; int idx = 0; int retval = -1; /* default: return error flag */ + int status; char_u *tail = NULL; regmatch_T regmatch; namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); *************** *** 562,568 **** if (namebuf == NULL || errmsg == NULL || pattern == NULL) goto qf_init_end; ! if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) { EMSG2(_(e_openerrf), efile); goto qf_init_end; --- 823,829 ---- if (namebuf == NULL || errmsg == NULL || pattern == NULL) goto qf_init_end; ! if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) { EMSG2(_(e_openerrf), efile); goto qf_init_end; *************** *** 636,645 **** if (tv != NULL) { if (tv->v_type == VAR_STRING) ! p_str = tv->vval.v_string; else if (tv->v_type == VAR_LIST) ! p_li = tv->vval.v_list->lv_first; } /* * Read the lines in the error file one by one. --- 897,908 ---- if (tv != NULL) { if (tv->v_type == VAR_STRING) ! state.p_str = tv->vval.v_string; else if (tv->v_type == VAR_LIST) ! state.p_li = tv->vval.v_list->lv_first; ! state.tv = tv; } + state.buf = buf; /* * Read the lines in the error file one by one. *************** *** 647,832 **** */ while (!got_int) { ! /* Get the next line. */ ! if (fd == NULL) ! { ! if (tv != NULL) ! { ! if (tv->v_type == VAR_STRING) ! { ! /* Get the next line from the supplied string */ ! char_u *p; ! ! if (*p_str == NUL) /* Reached the end of the string */ ! break; ! ! p = vim_strchr(p_str, '\n'); ! if (p != NULL) ! len = (int)(p - p_str) + 1; ! else ! len = (int)STRLEN(p_str); ! ! if (len > IOSIZE - 2) ! { ! linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, ! &linelen); ! if (linebuf == NULL) ! goto qf_init_end; ! } ! else ! { ! linebuf = IObuff; ! linelen = len; ! } ! vim_strncpy(linebuf, p_str, linelen); ! ! /* ! * Increment using len in order to discard the rest of the ! * line if it exceeds LINE_MAXLEN. ! */ ! p_str += len; ! } ! else if (tv->v_type == VAR_LIST) ! { ! /* Get the next line from the supplied list */ ! while (p_li != NULL ! && (p_li->li_tv.v_type != VAR_STRING ! || p_li->li_tv.vval.v_string == NULL)) ! p_li = p_li->li_next; /* Skip non-string items */ ! ! if (p_li == NULL) /* End of the list */ ! break; ! ! len = (int)STRLEN(p_li->li_tv.vval.v_string); ! if (len > IOSIZE - 2) ! { ! linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, ! &linelen); ! if (linebuf == NULL) ! goto qf_init_end; ! } ! else ! { ! linebuf = IObuff; ! linelen = len; ! } ! ! vim_strncpy(linebuf, p_li->li_tv.vval.v_string, linelen); ! ! p_li = p_li->li_next; /* next item */ ! } ! } ! else ! { ! /* Get the next line from the supplied buffer */ ! if (buflnum > lnumlast) ! break; ! p_buf = ml_get_buf(buf, buflnum++, FALSE); ! len = (int)STRLEN(p_buf); ! if (len > IOSIZE - 2) ! { ! linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, ! &linelen); ! if (linebuf == NULL) ! goto qf_init_end; ! } ! else ! { ! linebuf = IObuff; ! linelen = len; ! } ! vim_strncpy(linebuf, p_buf, linelen); ! } ! } ! else ! { ! if (fgets((char *)IObuff, IOSIZE, fd) == NULL) ! break; ! ! discard = FALSE; ! linelen = (int)STRLEN(IObuff); ! if (linelen == IOSIZE - 1 && !(IObuff[linelen - 1] == '\n' ! #ifdef USE_CRNL ! || IObuff[linelen - 1] == '\r' ! #endif ! )) ! { ! /* ! * The current line exceeds IObuff, continue reading using ! * growbuf until EOL or LINE_MAXLEN bytes is read. ! */ ! if (growbuf == NULL) ! { ! growbufsiz = 2 * (IOSIZE - 1); ! growbuf = alloc(growbufsiz); ! if (growbuf == NULL) ! goto qf_init_end; ! } ! ! /* Copy the read part of the line, excluding null-terminator */ ! memcpy(growbuf, IObuff, IOSIZE - 1); ! growbuflen = linelen; ! ! for (;;) ! { ! if (fgets((char *)growbuf + growbuflen, ! growbufsiz - growbuflen, fd) == NULL) ! break; ! linelen = (int)STRLEN(growbuf + growbuflen); ! growbuflen += linelen; ! if (growbuf[growbuflen - 1] == '\n' ! #ifdef USE_CRNL ! || growbuf[growbuflen - 1] == '\r' ! #endif ! ) ! break; ! if (growbufsiz == LINE_MAXLEN) ! { ! discard = TRUE; ! break; ! } ! ! growbufsiz = 2 * growbufsiz < LINE_MAXLEN ! ? 2 * growbufsiz : LINE_MAXLEN; ! growbuf = vim_realloc(growbuf, 2 * growbufsiz); ! if (growbuf == NULL) ! goto qf_init_end; ! } ! ! while (discard) ! { ! /* ! * The current line is longer than LINE_MAXLEN, continue ! * reading but discard everything until EOL or EOF is ! * reached. ! */ ! if (fgets((char *)IObuff, IOSIZE, fd) == NULL ! || (int)STRLEN(IObuff) < IOSIZE - 1 ! || IObuff[IOSIZE - 1] == '\n' ! #ifdef USE_CRNL ! || IObuff[IOSIZE - 1] == '\r' ! #endif ! ) ! break; ! } ! ! linebuf = growbuf; ! linelen = growbuflen; ! } ! else ! linebuf = IObuff; ! } ! ! if (linelen > 0 && linebuf[linelen - 1] == '\n') ! linebuf[linelen - 1] = NUL; ! #ifdef USE_CRNL ! if (linelen > 0 && linebuf[linelen - 1] == '\r') ! linebuf[linelen - 1] = NUL; ! #endif ! ! #ifdef FEAT_MBYTE ! remove_bom(linebuf); ! #endif /* If there was no %> item start at the first pattern */ if (fmt_start == NULL) --- 910,921 ---- */ while (!got_int) { ! /* Get the next line from a file/buffer/list/string */ ! status = qf_get_nextline(&state); ! if (status == QF_NOMEM) /* memory alloc failure */ ! goto qf_init_end; ! if (status == QF_END_OF_INPUT) /* end of input */ ! break; /* If there was no %> item start at the first pattern */ if (fmt_start == NULL) *************** *** 862,868 **** tail = NULL; regmatch.regprog = fmt_ptr->prog; ! r = vim_regexec(®match, linebuf, (colnr_T)0); fmt_ptr->prog = regmatch.regprog; if (r) { --- 951,957 ---- tail = NULL; regmatch.regprog = fmt_ptr->prog; ! r = vim_regexec(®match, state.linebuf, (colnr_T)0); fmt_ptr->prog = regmatch.regprog; if (r) { *************** *** 920,932 **** } if (fmt_ptr->flags == '+' && !qi->qf_multiscan) /* %+ */ { ! if (linelen > errmsglen) { /* linelen + null terminator */ ! if ((errmsg = vim_realloc(errmsg, linelen + 1)) == NULL) goto qf_init_end; ! errmsglen = linelen + 1; } ! vim_strncpy(errmsg, linebuf, linelen); } else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ { --- 1009,1022 ---- } if (fmt_ptr->flags == '+' && !qi->qf_multiscan) /* %+ */ { ! if (state.linelen > errmsglen) { /* linelen + null terminator */ ! if ((errmsg = vim_realloc(errmsg, ! state.linelen + 1)) == NULL) goto qf_init_end; ! errmsglen = state.linelen + 1; } ! vim_strncpy(errmsg, state.linebuf, state.linelen); } else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ { *************** *** 1015,1028 **** namebuf[0] = NUL; /* no match found, remove file name */ lnum = 0; /* don't jump to this line */ valid = FALSE; ! if (linelen > errmsglen) { /* linelen + null terminator */ ! if ((errmsg = vim_realloc(errmsg, linelen + 1)) == NULL) goto qf_init_end; ! errmsglen = linelen + 1; } /* copy whole line to error message */ ! vim_strncpy(errmsg, linebuf, linelen); if (fmt_ptr == NULL) qi->qf_multiline = qi->qf_multiignore = FALSE; } --- 1105,1118 ---- namebuf[0] = NUL; /* no match found, remove file name */ lnum = 0; /* don't jump to this line */ valid = FALSE; ! if (state.linelen > errmsglen) { /* linelen + null terminator */ ! if ((errmsg = vim_realloc(errmsg, state.linelen + 1)) == NULL) goto qf_init_end; ! errmsglen = state.linelen + 1; } /* copy whole line to error message */ ! vim_strncpy(errmsg, state.linebuf, state.linelen); if (fmt_ptr == NULL) qi->qf_multiline = qi->qf_multiignore = FALSE; } *************** *** 1122,1128 **** goto error2; line_breakcheck(); } ! if (fd == NULL || !ferror(fd)) { if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { --- 1212,1218 ---- goto error2; line_breakcheck(); } ! if (state.fd == NULL || !ferror(state.fd)) { if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { *************** *** 1150,1161 **** if (qi->qf_curlist > 0) --qi->qf_curlist; qf_init_end: ! if (fd != NULL) ! fclose(fd); vim_free(namebuf); vim_free(errmsg); vim_free(pattern); ! vim_free(growbuf); #ifdef FEAT_WINDOWS qf_update_buffer(qi, old_last); --- 1240,1251 ---- if (qi->qf_curlist > 0) --qi->qf_curlist; qf_init_end: ! if (state.fd != NULL) ! fclose(state.fd); vim_free(namebuf); vim_free(errmsg); vim_free(pattern); ! vim_free(state.growbuf); #ifdef FEAT_WINDOWS qf_update_buffer(qi, old_last); *** ../vim-7.4.2045/src/version.c 2016-07-15 21:29:31.413268255 +0200 --- src/version.c 2016-07-15 21:46:06.438898009 +0200 *************** *** 760,761 **** --- 760,763 ---- { /* Add new patch number below this line */ + /**/ + 2046, /**/ -- FATHER: One day, lad, all this will be yours ... PRINCE: What - the curtains? "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///