stag: allow multiple tag patterns for each extension
[neatvi.git] / stag.c
blob760922f215127167926cb63efc1878a04e667bce
1 #include <stdio.h>
2 #include <string.h>
3 #include "regex.h"
5 #define LEN(a) (sizeof(a) / sizeof((a)[0]))
7 static struct tag {
8 char *ext; /* file extension */
9 int grp; /* tag group in pat */
10 char *pat; /* tag pattern */
11 char *loc; /* optional tag location; may reference groups in pat */
12 } tags[] = {
13 {".c", 1, "^[a-zA-Z_].*\\<([a-zA-Z_][a-zA-Z_0-9]*)\\(.*[^;]$", "/^[a-zA-Z_].*\\<\\1\\>\\(.*[^;]$/"},
14 {".c", 1, "^#define +\\<([a-zA-Z_0-9]+)\\>", "/^#define +\\<(\\1)\\>/"},
15 {".go", 3, "^(func|var|const|type)( +\\([^()]+\\))? +([a-zA-Z_0-9]+)\\>", "/^\\1( +\\(.*\\))? +\\3\\>/"},
16 {".sh", 2, "^(function +)?([a-zA-Z_][a-zA-Z_0-9]*)(\\(\\))? *\\{", "/^\\1\\2(\\(\\))? *\\{$/"},
17 {".py", 2, "^(def|class) +([a-zA-Z_][a-zA-Z_0-9]*)\\>", "/^\\1 +\\2\\>/"},
18 {".ex", 2, "^[ \t]*(def|defp|defmodule)[ \t]+([a-zA-Z_0-9]+\\>[?!]?)", "/^[ \\t]*\\1[ \\t]+\\2\\>[?!]?/"},
21 static int tags_match(int idx, char *path)
23 int len = strlen(tags[idx].ext);
24 if (strlen(path) > len && !strcmp(strchr(path, '\0') - len, tags[idx].ext))
25 return 0;
26 return 1;
29 static void replace(char *dst, char *rep, char *ln, regmatch_t *subs)
31 while (rep[0]) {
32 if (rep[0] == '\\' && rep[1]) {
33 if (rep[1] >= '0' && rep[1] <= '9') {
34 int grp = rep[1] - '0';
35 int beg = subs[grp].rm_so;
36 int end = subs[grp].rm_eo;
37 int len = end - beg;
38 memcpy(dst, ln + beg, len);
39 dst += len;
40 } else {
41 *dst++ = rep[0];
42 *dst++ = rep[1];
44 rep++;
45 } else {
46 *dst++ = rep[0];
48 rep++;
50 dst[0] = '\0';
53 static int mktags(char *path, regex_t *re, int grp, char *rep)
55 char ln[128];
56 char loc[256];
57 char tag[120];
58 int lnum = 0;
59 regmatch_t grps[32];
60 FILE *fp = fopen(path, "r");
61 if (fp == NULL)
62 return 1;
63 while (fgets(ln, sizeof(ln), fp) != NULL) {
64 if (regexec(re, ln, LEN(grps), grps, 0) == 0) {
65 int len = grps[grp].rm_eo - grps[grp].rm_so;
66 if (len + 1 > sizeof(tag))
67 len = sizeof(tag) - 1;
68 memcpy(tag, ln + grps[grp].rm_so, len);
69 tag[len] = '\0';
70 if (rep != NULL)
71 replace(loc, rep, ln, grps);
72 else
73 sprintf(loc, "%d", lnum + 1);
74 printf("%s\t%s\t%s\n", tag, path, loc);
76 lnum++;
78 fclose(fp);
79 return 0;
82 int main(int argc, char *argv[])
84 int i, j;
85 if (argc == 1) {
86 printf("usage: %s files >tags\n", argv[0]);
87 return 0;
89 for (i = 1; i < argc; i++) {
90 for (j = 0; j < LEN(tags); j++) {
91 regex_t re;
92 if (tags_match(j, argv[i]) != 0)
93 continue;
94 if (regcomp(&re, tags[j].pat, REG_EXTENDED) != 0) {
95 fprintf(stderr, "mktags: bad pattern %s\n", tags[j].pat);
96 continue;
98 if (mktags(argv[i], &re, tags[j].grp, tags[j].loc))
99 fprintf(stderr, "mktags: failed to read %s\n", argv[i]);
100 regfree(&re);
103 return 0;