1636
* PRIVATE: cs_print_tags_priv
1638
* called from cs_manage_matches()
1635
/// Print cscope output that was converted into ctags style entries.
1637
/// Only called from cs_manage_matches().
1639
/// @param matches Array of cscope lines in ctags style. Every entry was
1640
// produced with a format string of the form
1641
// "%s\t%s\t%s;\"\t%s" or
1643
// by cs_make_vim_style_matches().
1644
/// @param cntxts Context for matches.
1645
/// @param num_matches Number of entries in matches/cntxts, always greater 0.
1640
1646
static void cs_print_tags_priv(char **matches, char **cntxts,
1647
size_t num_matches) FUNC_ATTR_NONNULL_ALL
1644
char *fname, *lno, *extra, *tbuf;
1646
char *globalcntx = "GLOBAL";
1648
char *cstag_msg = _("Cscope tag: %s");
1650
assert (num_matches > 0);
1652
tbuf = xmalloc(strlen(matches[0]) + 1);
1654
strcpy(tbuf, matches[0]);
1655
ptag = strtok(tbuf, "\t");
1657
size_t newsize = strlen(cstag_msg) + strlen(ptag);
1649
char *globalcntx = "GLOBAL";
1650
char *cstag_msg = _("Cscope tag: %s");
1652
assert(num_matches > 0);
1653
assert(strcnt(matches[0], '\t') >= 2);
1655
char *ptag = matches[0];
1656
char *ptag_end = strchr(ptag, '\t');
1657
assert(ptag_end >= ptag);
1658
// NUL terminate tag string in matches[0].
1661
// The "%s" in cstag_msg won't appear in the result string, so we don't need
1662
// extra memory for terminating NUL.
1663
size_t newsize = strlen(cstag_msg) + (size_t)(ptag_end - ptag);
1658
1664
char *buf = xmalloc(newsize);
1659
1665
size_t bufsize = newsize; // Track available bufsize
1660
(void)sprintf(buf, cstag_msg, ptag);
1666
(void)snprintf(buf, bufsize, cstag_msg, ptag);
1661
1667
MSG_PUTS_ATTR(buf, hl_attr(HLF_T));
1665
MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T)); /* strlen is 7 */
1670
// restore matches[0]
1673
// Column headers for match number, line number and filename.
1674
MSG_PUTS_ATTR(_("\n # line"), hl_attr(HLF_T));
1666
1675
msg_advance(msg_col + 2);
1667
1676
MSG_PUTS_ATTR(_("filename / context / line\n"), hl_attr(HLF_T));
1670
1678
for (size_t i = 0; i < num_matches; i++) {
1673
/* if we really wanted to, we could avoid this malloc and strcpy
1674
* by parsing matches[i] on the fly and placing stuff into buf
1675
* directly, but that's too much of a hassle
1677
tbuf = xmalloc(strlen(matches[idx]) + 1);
1678
(void)strcpy(tbuf, matches[idx]);
1680
if (strtok(tbuf, (const char *)"\t") == NULL)
1682
if ((fname = strtok(NULL, (const char *)"\t")) == NULL)
1684
if ((lno = strtok(NULL, (const char *)"\t")) == NULL)
1686
extra = strtok(NULL, (const char *)"\t");
1688
lno[strlen(lno)-2] = '\0'; /* ignore ;" at the end */
1679
assert(strcnt(matches[i], '\t') >= 2);
1681
// Parse filename, line number and optional part.
1682
char *fname = strchr(matches[i], '\t') + 1;
1683
char *fname_end = strchr(fname, '\t');
1684
// Replace second '\t' in matches[i] with NUL to terminate fname.
1687
char *lno = fname_end + 1;
1688
char *extra = xstrchrnul(lno, '\t');
1689
// Ignore ;" at the end of lno.
1690
char *lno_end = extra - 2;
1692
// Do we have an optional part?
1693
extra = *extra ? extra + 1 : NULL;
1690
1695
const char *csfmt_str = "%4zu %6s ";
1691
/* hopefully 'num' (num of matches) will be less than 10^16 */
1692
newsize = strlen(csfmt_str) + 16 + strlen(lno);
1696
// hopefully num_matches will be less than 10^16
1697
newsize = strlen(csfmt_str) + 16 + (size_t)(lno_end - lno);
1693
1698
if (bufsize < newsize) {
1694
1699
buf = xrealloc(buf, newsize);
1695
1700
bufsize = newsize;
1697
(void)sprintf(buf, csfmt_str, num, lno);
1702
(void)snprintf(buf, bufsize, csfmt_str, i + 1, lno);
1698
1703
MSG_PUTS_ATTR(buf, hl_attr(HLF_CM));
1699
1704
MSG_PUTS_LONG_ATTR(cs_pathcomponents(fname), hl_attr(HLF_CM));
1701
/* compute the required space for the context */
1702
if (cntxts[idx] != NULL)
1703
context = cntxts[idx];
1705
context = globalcntx;
1706
// compute the required space for the context
1707
char *context = cntxts[i] ? cntxts[i] : globalcntx;
1707
1709
const char *cntxformat = " <<%s>>";
1708
1710
// '%s' won't appear in result string, so: