[BACK]Return to quickfix.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/quickfix.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved       by Bram Moolenaar
                      5:  *
                      6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      7:  * Do ":help credits" in Vim to see a list of people who contributed.
                      8:  */
                      9:
                     10: /*
                     11:  * quickfix.c: functions for quickfix mode, using a file with error messages
                     12:  */
                     13:
                     14: #include "vim.h"
                     15: #include "globals.h"
                     16: #include "proto.h"
                     17: #include "option.h"
                     18:
                     19: static void qf_free __ARGS((void));
                     20: static char_u *qf_types __ARGS((int, int));
                     21:
                     22: /*
                     23:  * for each error the next struct is allocated and linked in a list
                     24:  */
                     25: struct qf_line
                     26: {
                     27:    struct qf_line  *qf_next;   /* pointer to next error in the list */
                     28:    struct qf_line  *qf_prev;   /* pointer to previous error in the list */
                     29:    linenr_t         qf_lnum;   /* line number where the error occurred */
                     30:    int              qf_fnum;   /* file number for the line */
                     31:    int              qf_col;    /* column where the error occurred */
                     32:    int              qf_nr;     /* error number */
                     33:    char_u          *qf_text;   /* description of the error */
                     34:    char_u           qf_cleared;/* set to TRUE if line has been deleted */
                     35:    char_u           qf_type;   /* type of the error (mostly 'E') */
                     36:    char_u           qf_valid;  /* valid error message detected */
                     37: };
                     38:
                     39: static struct qf_line *qf_start;       /* pointer to the first error */
                     40: static struct qf_line *qf_ptr;         /* pointer to the current error */
                     41:
                     42: static int qf_count = 0;       /* number of errors (0 means no error list) */
                     43: static int qf_index;           /* current index in the error list */
                     44: static int qf_nonevalid;       /* set to TRUE if not a single valid entry found */
                     45:
                     46: #define MAX_ADDR   7           /* maximum number of % recognized, also adjust
                     47:                                    sscanf() below */
                     48:
                     49: /*
                     50:  * Structure used to hold the info of one part of 'errorformat'
                     51:  */
                     52: struct eformat
                     53: {
                     54:    char_u          *fmtstr;        /* pre-formatted part of 'errorformat' */
                     55: #ifdef UTS2
                     56:    char_u          *(adr[MAX_ADDR]);   /* addresses used */
                     57: #else
                     58:    void            *(adr[MAX_ADDR]);
                     59: #endif
                     60:    int             adr_cnt;        /* number of addresses used */
                     61:    struct eformat  *next;          /* pointer to next (NULL if last) */
                     62: };
                     63:
                     64: /*
                     65:  * Read the errorfile into memory, line by line, building the error list.
                     66:  * Return FAIL for error, OK for success.
                     67:  */
                     68:    int
                     69: qf_init()
                     70: {
                     71:    char_u          *namebuf;
                     72:    char_u          *errmsg;
                     73:    int             col;
                     74:    int             type;
                     75:    int             valid;
                     76:    long            lnum;
                     77:    int             enr;
                     78:    FILE            *fd;
                     79:    struct qf_line  *qfp = NULL;
                     80:    struct qf_line  *qfprev = NULL;     /* init to make SASC shut up */
                     81:    char_u          *efmp;
                     82:    struct eformat  *fmt_first = NULL;
                     83:    struct eformat  *fmt_last = NULL;
                     84:    struct eformat  *fmt_ptr;
                     85:    char_u          *efm;
                     86:    int             maxlen;
                     87:    int             len;
                     88:    int             i, j;
                     89:    int             retval = FAIL;
                     90:
                     91:    if (*p_ef == NUL)
                     92:    {
                     93:        emsg(e_errorf);
                     94:        return FAIL;
                     95:    }
                     96:
                     97:    namebuf = alloc(CMDBUFFSIZE + 1);
                     98:    errmsg = alloc(CMDBUFFSIZE + 1);
                     99:    if (namebuf == NULL || errmsg == NULL)
                    100:        goto qf_init_end;
                    101:
                    102:    if ((fd = fopen((char *)p_ef, "r")) == NULL)
                    103:    {
                    104:        emsg2(e_openerrf, p_ef);
                    105:        goto qf_init_end;
                    106:    }
                    107:    qf_free();
                    108:    qf_index = 0;
                    109:
                    110: /*
                    111:  * Each part of the format string is copied and modified from p_efm to fmtstr.
                    112:  * Only a few % characters are allowed.
                    113:  */
                    114:    efm = p_efm;
                    115:    while (efm[0])
                    116:    {
                    117:        /*
                    118:         * Allocate a new eformat structure and put it at the end of the list
                    119:         */
                    120:        fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat));
                    121:        if (fmt_ptr == NULL)
                    122:            goto error2;
                    123:        if (fmt_first == NULL)      /* first one */
                    124:            fmt_first = fmt_ptr;
                    125:        else
                    126:            fmt_last->next = fmt_ptr;
                    127:        fmt_last = fmt_ptr;
                    128:        fmt_ptr->next = NULL;
                    129:        fmt_ptr->adr_cnt = 0;
                    130:
                    131:        /*
                    132:         * Isolate one part in the 'errorformat' option
                    133:         */
                    134:        for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
                    135:            if (efm[len] == '\\' && efm[len + 1] != NUL)
                    136:                ++len;
                    137:
                    138:        /*
                    139:         * Get some space to modify the format string into.
                    140:         * Must be able to do the largest expansion (x3) MAX_ADDR times.
                    141:         */
                    142:        maxlen = len + MAX_ADDR * 3 + 4;
                    143:        if ((fmt_ptr->fmtstr = alloc(maxlen)) == NULL)
                    144:            goto error2;
                    145:
                    146:        for (i = 0; i < MAX_ADDR; ++i)
                    147:            fmt_ptr->adr[i] = NULL;
                    148:
                    149:        for (efmp = efm, i = 0; efmp < efm + len; ++efmp, ++i)
                    150:        {
                    151:            if (efmp[0] != '%')             /* copy normal character */
                    152:            {
                    153:                if (efmp[0] == '\\' && efmp + 1 < efm + len)
                    154:                    ++efmp;
                    155:                fmt_ptr->fmtstr[i] = efmp[0];
                    156:            }
                    157:            else
                    158:            {
                    159:                fmt_ptr->fmtstr[i++] = '%';
                    160:                switch (efmp[1])
                    161:                {
                    162:                case 'f':       /* filename */
                    163:                        fmt_ptr->adr[fmt_ptr->adr_cnt++] = namebuf;
                    164:                        /* FALLTHROUGH */
                    165:
                    166:                case 'm':       /* message */
                    167:                        if (efmp[1] == 'm')
                    168:                            fmt_ptr->adr[fmt_ptr->adr_cnt++] = errmsg;
                    169:                        fmt_ptr->fmtstr[i++] = '[';
                    170:                        fmt_ptr->fmtstr[i++] = '^';
                    171: #ifdef __EMX__
                    172:                        /* don't allow spaces in filename. This fixes
                    173:                         * the broken sscanf() where an empty message
                    174:                         * is accepted as a valid conversion.
                    175:                         */
                    176:                        if (efmp[1] == 'f')
                    177:                            fmt_ptr->fmtstr[i++] = ' ';
                    178: #endif
                    179:                        if (efmp[2] == '\\')        /* could be "%m\," */
                    180:                            j = 3;
                    181:                        else
                    182:                            j = 2;
                    183:                        if (efmp + j < efm + len)
                    184:                            fmt_ptr->fmtstr[i++] = efmp[j];
                    185:                        else
                    186:                        {
                    187:                            /*
                    188:                             * The %f or %m is the last one in the format,
                    189:                             * stop at the CR of NL at the end of the line.
                    190:                             */
                    191: #ifdef USE_CRNL
                    192:                            fmt_ptr->fmtstr[i++] = '\r';
                    193: #endif
                    194:                            fmt_ptr->fmtstr[i++] = '\n';
                    195:                        }
                    196:                        fmt_ptr->fmtstr[i] = ']';
                    197:                        break;
                    198:                case 'c':       /* column */
                    199:                        fmt_ptr->adr[fmt_ptr->adr_cnt++] = &col;
                    200:                        fmt_ptr->fmtstr[i] = 'd';
                    201:                        break;
                    202:                case 'l':       /* line */
                    203:                        fmt_ptr->adr[fmt_ptr->adr_cnt++] = &lnum;
                    204:                        fmt_ptr->fmtstr[i++] = 'l';
                    205:                        fmt_ptr->fmtstr[i] = 'd';
                    206:                        break;
                    207:                case 'n':       /* error number */
                    208:                        fmt_ptr->adr[fmt_ptr->adr_cnt++] = &enr;
                    209:                        fmt_ptr->fmtstr[i] = 'd';
                    210:                        break;
                    211:                case 't':       /* error type */
                    212:                        fmt_ptr->adr[fmt_ptr->adr_cnt++] = &type;
                    213:                        fmt_ptr->fmtstr[i] = 'c';
                    214:                        break;
                    215:                case '%':       /* %% */
                    216:                case '*':       /* %*: no assignment */
                    217:                        fmt_ptr->fmtstr[i] = efmp[1];
                    218:                        break;
                    219:                default:
                    220:                        EMSG("invalid % in format string");
                    221:                        goto error2;
                    222:                }
                    223:                if (fmt_ptr->adr_cnt == MAX_ADDR)
                    224:                {
                    225:                    EMSG("too many % in format string");
                    226:                    goto error2;
                    227:                }
                    228:                ++efmp;
                    229:            }
                    230:            if (i >= maxlen - 6)
                    231:            {
                    232:                EMSG("invalid format string");
                    233:                goto error2;
                    234:            }
                    235:        }
                    236:        fmt_ptr->fmtstr[i] = NUL;
                    237:
                    238:        /*
                    239:         * Advance to next part
                    240:         */
                    241:        efm = skip_to_option_part(efm + len);   /* skip comma and spaces */
                    242:    }
                    243:    if (fmt_first == NULL)      /* nothing found */
                    244:    {
                    245:        EMSG("'errorformat' contains no pattern");
                    246:        goto error2;
                    247:    }
                    248:
                    249:    /*
                    250:     * Read the lines in the error file one by one.
                    251:     * Try to recognize one of the error formats in each line.
                    252:     */
                    253:    while (fgets((char *)IObuff, CMDBUFFSIZE, fd) != NULL && !got_int)
                    254:    {
                    255:        if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line)))
                    256:                                                                      == NULL)
                    257:            goto error2;
                    258:
                    259:        IObuff[CMDBUFFSIZE] = NUL;  /* for very long lines */
                    260:
                    261:        /*
                    262:         * Try to match each part of 'errorformat' until we find a complete
                    263:         * match or none matches.
                    264:         */
                    265:        valid = TRUE;
                    266:        for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
                    267:        {
                    268:            namebuf[0] = NUL;
                    269:            errmsg[0] = NUL;
                    270:            lnum = 0;
                    271:            col = 0;
                    272:            enr = -1;
                    273:            type = 0;
                    274:
                    275:            /*
                    276:             * If first char of the format and message don't match, there is
                    277:             * no need to try sscanf() on it... Somehow I believe there are
                    278:             * very slow implementations of sscanf().
                    279:             * -- Paul Slootman
                    280:             */
                    281:            if (fmt_ptr->fmtstr[0] != '%' && fmt_ptr->fmtstr[0] != IObuff[0])
                    282:                continue;
                    283:
                    284:            if (sscanf((char *)IObuff, (char *)fmt_ptr->fmtstr,
                    285:                        fmt_ptr->adr[0], fmt_ptr->adr[1], fmt_ptr->adr[2],
                    286:                        fmt_ptr->adr[3], fmt_ptr->adr[4], fmt_ptr->adr[5],
                    287:                        fmt_ptr->adr[6]) == fmt_ptr->adr_cnt)
                    288:                break;
                    289:        }
                    290:        if (fmt_ptr == NULL)
                    291:        {
                    292:            namebuf[0] = NUL;           /* no match found, remove file name */
                    293:            lnum = 0;                   /* don't jump to this line */
                    294:            valid = FALSE;
                    295:            STRCPY(errmsg, IObuff);     /* copy whole line to error message */
                    296:            if ((efmp = vim_strrchr(errmsg, '\n')) != NULL)
                    297:                *efmp = NUL;
                    298: #ifdef USE_CRNL
                    299:            if ((efmp = vim_strrchr(errmsg, '\r')) != NULL)
                    300:                *efmp = NUL;
                    301: #endif
                    302:        }
                    303:
                    304:        if (namebuf[0] == NUL)          /* no file name */
                    305:            qfp->qf_fnum = 0;
                    306:        else
                    307:            qfp->qf_fnum = buflist_add(namebuf);
                    308:        if ((qfp->qf_text = strsave(errmsg)) == NULL)
                    309:            goto error1;
                    310:        qfp->qf_lnum = lnum;
                    311:        qfp->qf_col = col;
                    312:        qfp->qf_nr = enr;
                    313:        qfp->qf_type = type;
                    314:        qfp->qf_valid = valid;
                    315:
                    316:        if (qf_count == 0)      /* first element in the list */
                    317:        {
                    318:            qf_start = qfp;
                    319:            qfp->qf_prev = qfp; /* first element points to itself */
                    320:        }
                    321:        else
                    322:        {
                    323:            qfp->qf_prev = qfprev;
                    324:            qfprev->qf_next = qfp;
                    325:        }
                    326:        qfp->qf_next = qfp;     /* last element points to itself */
                    327:        qfp->qf_cleared = FALSE;
                    328:        qfprev = qfp;
                    329:        ++qf_count;
                    330:        if (qf_index == 0 && qfp->qf_valid)     /* first valid entry */
                    331:        {
                    332:            qf_index = qf_count;
                    333:            qf_ptr = qfp;
                    334:        }
                    335:        line_breakcheck();
                    336:    }
                    337:    if (!ferror(fd))
                    338:    {
                    339:        if (qf_index == 0)      /* no valid entry found */
                    340:        {
                    341:            qf_ptr = qf_start;
                    342:            qf_index = 1;
                    343:            qf_nonevalid = TRUE;
                    344:        }
                    345:        else
                    346:            qf_nonevalid = FALSE;
                    347:        retval = OK;
                    348:        goto qf_init_ok;
                    349:    }
                    350:    emsg(e_readerrf);
                    351: error1:
                    352:    vim_free(qfp);
                    353: error2:
                    354:    qf_free();
                    355: qf_init_ok:
                    356:    fclose(fd);
                    357:    for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
                    358:    {
                    359:        fmt_first = fmt_ptr->next;
                    360:        vim_free(fmt_ptr->fmtstr);
                    361:        vim_free(fmt_ptr);
                    362:    }
                    363: qf_init_end:
                    364:    vim_free(namebuf);
                    365:    vim_free(errmsg);
                    366:    return retval;
                    367: }
                    368:
                    369: /*
                    370:  * jump to a quickfix line
                    371:  * if dir == FORWARD go "errornr" valid entries forward
                    372:  * if dir == BACKWARD go "errornr" valid entries backward
                    373:  * else if "errornr" is zero, redisplay the same line
                    374:  * else go to entry "errornr"
                    375:  */
                    376:    void
                    377: qf_jump(dir, errornr)
                    378:    int     dir;
                    379:    int     errornr;
                    380: {
                    381:    struct qf_line  *old_qf_ptr;
                    382:    int             old_qf_index;
                    383:    static char_u   *e_no_more_errors = (char_u *)"No more errors";
                    384:    char_u          *err = e_no_more_errors;
                    385:    linenr_t        i;
                    386:
                    387:    if (qf_count == 0)
                    388:    {
                    389:        emsg(e_quickfix);
                    390:        return;
                    391:    }
                    392:
                    393:    old_qf_ptr = qf_ptr;
                    394:    old_qf_index = qf_index;
                    395:    if (dir == FORWARD)     /* next valid entry */
                    396:    {
                    397:        while (errornr--)
                    398:        {
                    399:            old_qf_ptr = qf_ptr;
                    400:            old_qf_index = qf_index;
                    401:            do
                    402:            {
                    403:                if (qf_index == qf_count || qf_ptr->qf_next == NULL)
                    404:                {
                    405:                    qf_ptr = old_qf_ptr;
                    406:                    qf_index = old_qf_index;
                    407:                    if (err != NULL)
                    408:                    {
                    409:                        emsg(err);
                    410:                        return;
                    411:                    }
                    412:                    errornr = 0;
                    413:                    break;
                    414:                }
                    415:                ++qf_index;
                    416:                qf_ptr = qf_ptr->qf_next;
                    417:            } while (!qf_nonevalid && !qf_ptr->qf_valid);
                    418:            err = NULL;
                    419:        }
                    420:    }
                    421:    else if (dir == BACKWARD)       /* previous valid entry */
                    422:    {
                    423:        while (errornr--)
                    424:        {
                    425:            old_qf_ptr = qf_ptr;
                    426:            old_qf_index = qf_index;
                    427:            do
                    428:            {
                    429:                if (qf_index == 1 || qf_ptr->qf_prev == NULL)
                    430:                {
                    431:                    qf_ptr = old_qf_ptr;
                    432:                    qf_index = old_qf_index;
                    433:                    if (err != NULL)
                    434:                    {
                    435:                        emsg(err);
                    436:                        return;
                    437:                    }
                    438:                    errornr = 0;
                    439:                    break;
                    440:                }
                    441:                --qf_index;
                    442:                qf_ptr = qf_ptr->qf_prev;
                    443:            } while (!qf_nonevalid && !qf_ptr->qf_valid);
                    444:            err = NULL;
                    445:        }
                    446:    }
                    447:    else if (errornr != 0)      /* go to specified number */
                    448:    {
                    449:        while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL)
                    450:        {
                    451:            --qf_index;
                    452:            qf_ptr = qf_ptr->qf_prev;
                    453:        }
                    454:        while (errornr > qf_index && qf_index < qf_count && qf_ptr->qf_next != NULL)
                    455:        {
                    456:            ++qf_index;
                    457:            qf_ptr = qf_ptr->qf_next;
                    458:        }
                    459:    }
                    460:
                    461:    /*
                    462:     * If there is a file name,
                    463:     * read the wanted file if needed, and check autowrite etc.
                    464:     */
                    465:    if (qf_ptr->qf_fnum == 0 || buflist_getfile(qf_ptr->qf_fnum,
                    466:                                             (linenr_t)1, GETF_SETMARK) == OK)
                    467:    {
                    468:        /*
                    469:         * Go to line with error, unless qf_lnum is 0.
                    470:         */
                    471:        i = qf_ptr->qf_lnum;
                    472:        if (i > 0)
                    473:        {
                    474:            if (i > curbuf->b_ml.ml_line_count)
                    475:                i = curbuf->b_ml.ml_line_count;
                    476:            curwin->w_cursor.lnum = i;
                    477:        }
                    478:        if (qf_ptr->qf_col > 0)
                    479:        {
                    480:            curwin->w_cursor.col = qf_ptr->qf_col - 1;
                    481:            adjust_cursor();
                    482:        }
                    483:        else
                    484:            beginline(TRUE);
                    485:        cursupdate();
                    486:        smsg((char_u *)"(%d of %d)%s%s: %s", qf_index, qf_count,
                    487:                    qf_ptr->qf_cleared ? (char_u *)" (line deleted)" : (char_u *)"",
                    488:                    qf_types(qf_ptr->qf_type, qf_ptr->qf_nr), qf_ptr->qf_text);
                    489:        /*
                    490:         * if the message is short, redisplay after redrawing the screen
                    491:         */
                    492:        if (linetabsize(IObuff) < ((int)p_ch - 1) * Columns + sc_col)
                    493:            keep_msg = IObuff;
                    494:    }
                    495:    else if (qf_ptr->qf_fnum != 0)
                    496:    {
                    497:        /*
                    498:         * Couldn't open file, so put index back where it was.  This could
                    499:         * happen if the file was readonly and we changed something - webb
                    500:         */
                    501:        qf_ptr = old_qf_ptr;
                    502:        qf_index = old_qf_index;
                    503:    }
                    504: }
                    505:
                    506: /*
                    507:  * list all errors
                    508:  */
                    509:    void
                    510: qf_list(all)
                    511:    int all;        /* If not :cl!, only show recognised errors */
                    512: {
                    513:    BUF             *buf;
                    514:    char_u          *fname;
                    515:    struct qf_line  *qfp;
                    516:    int             i;
                    517:
                    518:    if (qf_count == 0)
                    519:    {
                    520:        emsg(e_quickfix);
                    521:        return;
                    522:    }
                    523:
                    524:    if (qf_nonevalid)
                    525:        all = TRUE;
                    526:    qfp = qf_start;
                    527:    set_highlight('d');     /* Same as for directories */
                    528:    for (i = 1; !got_int && i <= qf_count; ++i)
                    529:    {
                    530:        if (qfp->qf_valid || all)
                    531:        {
                    532:            msg_outchar('\n');
                    533:            start_highlight();
                    534:            fname = NULL;
                    535:            if (qfp->qf_fnum != 0 &&
                    536:                                 (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
                    537:                fname = buf->b_xfilename;
                    538:            if (fname == NULL)
                    539:                sprintf((char *)IObuff, "%2d", i);
                    540:            else
                    541:                sprintf((char *)IObuff, "%2d %s", i, fname);
                    542:            msg_outtrans(IObuff);
                    543:            stop_highlight();
                    544:            if (qfp->qf_lnum == 0)
                    545:                IObuff[0] = NUL;
                    546:            else if (qfp->qf_col == 0)
                    547:                sprintf((char *)IObuff, ":%ld", qfp->qf_lnum);
                    548:            else
                    549:                sprintf((char *)IObuff, ":%ld, col %d",
                    550:                                                   qfp->qf_lnum, qfp->qf_col);
                    551:            sprintf((char *)IObuff + STRLEN(IObuff), "%s: ",
                    552:                                        qf_types(qfp->qf_type, qfp->qf_nr));
                    553:            msg_outstr(IObuff);
                    554:            msg_prt_line(qfp->qf_text);
                    555:            flushbuf();                 /* show one line at a time */
                    556:        }
                    557:        qfp = qfp->qf_next;
                    558:        mch_breakcheck();
                    559:    }
                    560: }
                    561:
                    562: /*
                    563:  * free the error list
                    564:  */
                    565:    static void
                    566: qf_free()
                    567: {
                    568:    struct qf_line *qfp;
                    569:
                    570:    while (qf_count)
                    571:    {
                    572:        qfp = qf_start->qf_next;
                    573:        vim_free(qf_start->qf_text);
                    574:        vim_free(qf_start);
                    575:        qf_start = qfp;
                    576:        --qf_count;
                    577:    }
                    578: }
                    579:
                    580: /*
                    581:  * qf_mark_adjust: adjust marks
                    582:  */
                    583:    void
                    584: qf_mark_adjust(line1, line2, amount, amount_after)
                    585:    linenr_t    line1;
                    586:    linenr_t    line2;
                    587:    long        amount;
                    588:    long        amount_after;
                    589: {
                    590:    register int i;
                    591:    struct qf_line *qfp;
                    592:
                    593:    if (qf_count)
                    594:        for (i = 0, qfp = qf_start; i < qf_count; ++i, qfp = qfp->qf_next)
                    595:            if (qfp->qf_fnum == curbuf->b_fnum)
                    596:            {
                    597:                if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
                    598:                {
                    599:                    if (amount == MAXLNUM)
                    600:                        qfp->qf_cleared = TRUE;
                    601:                    else
                    602:                        qfp->qf_lnum += amount;
                    603:                }
                    604:                if (amount_after && qfp->qf_lnum > line2)
                    605:                    qfp->qf_lnum += amount_after;
                    606:            }
                    607: }
                    608:
                    609: /*
                    610:  * Make a nice message out of the error character and the error number:
                    611:  * char    number      message
                    612:  *  e or E    0            "   error"
                    613:  *  w or W    0            " warning"
                    614:  *  other     0            ""
                    615:  *  w or W    n            " warning n"
                    616:  *  other     n            "   error n"
                    617:  */
                    618:    static char_u *
                    619: qf_types(c, nr)
                    620:    int c, nr;
                    621: {
                    622:    static char_u   buf[20];
                    623:    char_u      *p1;
                    624:
                    625:    p1 = (char_u *)"   error";
                    626:    if (c == 'W' || c == 'w')
                    627:        p1 =  (char_u *)" warning";
                    628:    else if (nr <= 0 && c != 'E' && c != 'e')
                    629:        p1 = (char_u *)"";
                    630:
                    631:    if (nr <= 0)
                    632:        return p1;
                    633:
                    634:    sprintf((char *)buf, "%s %3d", p1, nr);
                    635:    return buf;
                    636: }