From 0dc1b91ec62bd0e431fb5ef832cf7a3676d31452 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 6 Jul 2021 00:12:27 +0000 Subject: [PATCH] Add -ftags to generate tag info for vi and compatibles. Files will still need to be concatenated then sorted before use. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5954 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/qclib/qcc.h | 3 ++ engine/qclib/qcc_pr_lex.c | 11 +++- engine/qclib/qccguistuff.c | 2 + engine/qclib/qccmain.c | 100 +++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index c66daaccc..a4ef388a3 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -388,6 +388,9 @@ typedef struct QCC_type_s const char *name; const char *aname; + const char *filen; + unsigned int line; + struct accessor_s *accessors; struct QCC_type_s *ptrto; //(cache) this points to a type that is a pointer back to this type. yeah, weird. diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 70e169a3b..d1601a81e 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -5543,6 +5543,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) pbool setnotget; pbool isinline; + newt->filen = s_filen; + newt->line = pr_source_line; + do { isinline = QCC_PR_CheckName("inline"); @@ -5594,6 +5597,10 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) fieldtype = QCC_TypeForName(parentname); if (!fieldtype) QCC_PR_ParseError(ERR_NOTANAME, "Parent class %s was not yet defined", parentname); + + //FIXME: we should allow inheriting from 'object' too. + if (fieldtype->type != ev_entity) + QCC_PR_ParseError(ERR_NOTANAME, "Parent type %s is not a class/entity", parentname); forwarddeclaration = false; QCC_PR_Expect("{"); @@ -5612,7 +5619,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) if (!newt) { - newt = QCC_PR_NewType(classname, ev_entity, true); + newt = QCC_PR_NewType(classname, fieldtype->type, true); newt->size=type_entity->size; } @@ -5626,6 +5633,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) if (redeclaration && fieldtype != newt->parentclass) QCC_PR_ParseError(ERR_REDECLARATION, "Parent class changed on redeclaration of %s%s%s", col_type,classname,col_none); newt->parentclass = fieldtype; + newt->filen = s_filen; + newt->line = pr_source_line; if (QCC_PR_CheckToken(",")) QCC_PR_ParseError(ERR_NOTANAME, "member missing name"); diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index 4e599901e..3e8cce506 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -341,6 +341,8 @@ void GUI_SaveConfig(void) for (p = 0; compiler_flag[p].enabled; p++) { + if (p>0 && compiler_flag[p].enabled == compiler_flag[p-1].enabled) + continue; //don't list dupe names. if (!strncmp(compiler_flag[p].fullname, "Keyword: ", 9)) GUI_WriteConfigLine(file, "keyword", compiler_flag[p].abbrev, (compiler_flag[p].flags&FLAG_SETINGUI)?"true":"false", compiler_flag[p].description); else diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index 0c954f444..ac292530a 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -143,6 +143,7 @@ static pbool flag_dumpfields; static pbool flag_dumpsymbols; static pbool flag_dumpautocvars; static pbool flag_dumplocalisation; +static pbool flag_dumptags; struct { @@ -427,6 +428,8 @@ compiler_flag_t compiler_flag[] = { {&flag_dumpsymbols, FLAG_MIDCOMPILE,"dumpsymbols", "Write a .sym file", "Writes a .sym file alongside the dat which contains a list of all global symbols defined in the code (before stripping)"}, {&flag_dumpautocvars, FLAG_MIDCOMPILE,"dumpautocvars","Write a .cfg file", "Writes a .cfg file that contains a default value for each autocvar listed in the code"}, {&flag_dumplocalisation,FLAG_MIDCOMPILE,"dumplocalisation","Write a .pot file", "Writes a .po template file from your _("") strings that can be edited (with eg gettext's tools) for translations, resulting in eg csprogs.en_US.po vs csprogs.en.po and other various other dialects vs languages."}, + {&flag_dumptags, FLAG_MIDCOMPILE,"dumptags", "Write vi's tags file", "Writes a .tags file for text editors compatible with vi to locate symbols by name. This file is unsorted and per-module, so you will need to 'cat ../*.tags|LC_COLLATE=C sort>tags' for it to be used."}, + {&flag_dumptags, FLAG_MIDCOMPILE|FLAG_HIDDENINGUI,"tags","aka dumptags", "See dumptags"}, {NULL} }; @@ -921,6 +924,98 @@ static void QCC_DumpFiles (const char *outputname) } } +void QCC_DumpPreProcTags(void *ctx, void *data) +{ + char line[2048]; + int h = *(int*)ctx; + CompilerConstant_t *def = data; + if (def->fromfile) + { + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\td\n", def->name, def->fromfile, def->fromline); + SafeWrite(h, line, strlen(line)); + } +} +static void QCC_DumpTags(const char *outputname) +{ + char line[65536]; + char scope[2048]; + int h; + QCC_def_t *def; + QCC_function_t *fnc; + int i; + QCC_type_t *t; + + snprintf(line, sizeof(line), "%s.tags", outputname); + h = SafeOpenWrite (line, 2*1024*1024); + if (h >= 0) + { + Hash_Enumerate(&compconstantstable, QCC_DumpPreProcTags, &h); + + for (i = 0; i < numtypeinfos; i++) + { + t = &qcc_typeinfo[i]; + if (!t->line || !t->filen) + continue; //predefined type, not from any file. + if (!*t->name || strchr(t->name, '<')) + continue; //anonymous stuff happens. + if (t->typedefed) + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tt\n", t->name, t->filen, t->line); + else if (t->type == ev_struct) + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\ts\n", t->name, t->filen, t->line); + else if (t->type == ev_union) + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tu\n", t->name, t->filen, t->line); + else if (t->type == ev_enum) + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tg\n", t->name, t->filen, t->line); + else if ((t->type == ev_entity||t->type == ev_accessor) && t->parentclass) + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tc\n", t->name, t->filen, t->line); + else + continue; + SafeWrite(h, line, strlen(line)); + } + + for (def = pr.def_head.next; def; def = def->next) + { + //immediates are uninteresting... + if (!strcmp(def->name, "IMMEDIATE")) + continue; + if (strchr(def->name, '.') || strchr(def->name, '[') || strchr(def->name, '*')) + continue; //weird symbols, listed for savedgames only... + if (def->scope && !strchr(def->scope->name, ':')) + snprintf(scope, sizeof(scope), "\tfunction:%s\n", def->scope->name); + else if (def->isstatic) + snprintf(scope, sizeof(scope), "\file:\n"); //local scope + else + *scope = 0; + + if (def->type->type == ev_function && def->constant && !def->arraysize) + { + int fnum = def->symboldata[0].function; + + if (fnum > 0 && fnum < numfunctions) + { + fnc = &functions[fnum]; + if (fnc->code>=0 && fnc->filen) + { + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tf%s\n", def->name, fnc->filen, fnc->line, scope); + SafeWrite(h, line, strlen(line)); + } + } + if (def->filen) + { + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tp%s\n", def->name, def->filen, def->s_line, scope); + SafeWrite(h, line, strlen(line)); + } + } + else if (def->filen) + { + snprintf(line, sizeof(line), "%s\t%s\t%i;\"\tv%s\n", def->name, def->filen, def->s_line, scope); + SafeWrite(h, line, strlen(line)); + } + } + } + SafeClose(h); +} + int WriteSourceFiles(qcc_cachedsourcefile_t *filelist, int h, pbool sourceaswell, pbool legacyembed) { //helpers to deal with misaligned data. writes little-endian. @@ -2401,6 +2496,8 @@ strofs = (strofs+3)&~3; QCC_DumpAutoCvars(destfile); if (flag_dumplocalisation) QCC_DumpLocalisation(destfile); + if (flag_dumptags) + QCC_DumpTags(destfile); switch(outputsttype) { @@ -3371,6 +3468,9 @@ QCC_type_t *QCC_PR_NewType (const char *name, int basictype, pbool typedefed) qcc_typeinfo[numtypeinfos].size = type_size[basictype]; qcc_typeinfo[numtypeinfos].typedefed = typedefed; + qcc_typeinfo[numtypeinfos].filen = s_filen; + qcc_typeinfo[numtypeinfos].line = pr_source_line; + if (typedefed) pHash_Add(&typedeftable, name, &qcc_typeinfo[numtypeinfos], qccHunkAlloc(sizeof(bucket_t)));