Add -Fdumplocalisation arg to fteqcc to dump localisation stuff (in part to try to encourage more people to use this stuff).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5873 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-05-27 11:34:22 +00:00
parent 4d351b60f3
commit 08b5b09fd3
4 changed files with 237 additions and 101 deletions

View File

@ -582,6 +582,7 @@ tt_punct, // code punctuation
tt_immediate, // string, float, vector
} token_type_t;
extern char *pr_token_precomment;
extern char pr_token[8192];
extern token_type_t pr_token_type;
extern int pr_token_line;

View File

@ -7450,18 +7450,26 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f
}
if (!strcmp(funcname, "_"))
{
char *comment = pr_token_precomment;
func.sym->unused = true;
func.sym->referenced = true;
QCC_FreeTemp(func);
if (pr_token_type == tt_immediate && pr_immediate_type->type == ev_string)
{
d = QCC_MakeTranslateStringConst(pr_immediate_string);
d.sym->comment = comment;
QCC_PR_Lex();
if (!d.sym->comment)
d.sym->comment = pr_token_precomment;
if (QCC_PR_CheckTokenComment (")", &d.sym->comment))
return d;
}
else
{
QCC_PR_ParseErrorPrintSRef (ERR_TYPEMISMATCHPARM, func, "_() intrinsic accepts only a string immediate", 1);
d = nullsref;
}
QCC_PR_Expect(")");
return d;
@ -8370,6 +8378,9 @@ static QCC_sref_t QCC_MakeStringConstInternal(const char *value, size_t length,
cn->arraysize = 0;
cn->localscope = false;
cn->filen = s_filen;
cn->s_line = pr_source_line;
// copy the immediate to the global area
cn->ofs = 0;
cn->symbolheader = cn;

View File

@ -14,6 +14,7 @@ CompilerConstant_t *QCC_PR_CheckCompConstDefined(const char *def);
int QCC_PR_CheckCompConst(void);
pbool QCC_Include(const char *filename);
void QCC_FreeDef(QCC_def_t *def);
void QCC_PR_LexComment(char **comment);
extern pbool destfile_explicit;
extern char destfile[1024];
@ -36,6 +37,7 @@ char *pr_line_start; // start of current source line
int pr_bracelevel;
char *pr_token_precomment;
char pr_token[8192];
token_type_t pr_token_type;
int pr_token_line;
@ -1641,7 +1643,7 @@ void QCC_PR_LexString (void)
raw = 0;
texttype = 0;
QCC_PR_LexWhitespace(false);
QCC_PR_LexComment(&pr_token_precomment);
if (flag_qccx && *pr_file_p == ':')
{
@ -3819,7 +3821,9 @@ void QCC_PR_Lex (void)
return;
}
QCC_PR_LexWhitespace (false);
pr_token_precomment = NULL;
QCC_PR_LexComment(&pr_token_precomment);
// QCC_PR_LexWhitespace (false);
pr_token_line_last = pr_token_line;
pr_token_line = pr_source_line;
@ -4214,7 +4218,7 @@ void QCC_PR_Expect (const char *string)
}
#endif
pbool QCC_PR_CheckTokenComment(const char *string, char **comment)
void QCC_PR_LexComment(char **comment)
{
char c;
char *start;
@ -4224,6 +4228,108 @@ pbool QCC_PR_CheckTokenComment(const char *string, char **comment)
pbool replace = true;
pbool nextcomment = true;
// skip whitespace
nl = false;
while(nextcomment)
{
nextcomment = false;
while ((c = *pr_file_p) && qcc_iswhite(c))
{
if (qcc_islineending(c, pr_file_p[1])) //allow new lines, but only if there's whitespace before any tokens, and no double newlines.
{
if (nl)
{
pr_file_p++;
QCC_PR_NewLine(false);
break;
}
nl = true;
}
else
{
pr_file_p++;
nl = false;
}
}
if (nl)
break;
// parse // comments
if (c=='/' && pr_file_p[1] == '/')
{
pr_file_p += 2;
while (*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
start = pr_file_p;
while (*pr_file_p && *pr_file_p != '\n')
pr_file_p++;
if (*pr_file_p == '\n')
{
pr_file_p++;
QCC_PR_NewLine(false);
}
old = replace?NULL:*comment;
replace = false;
oldlen = old?strlen(old)+1:0;
*comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1);
if (oldlen)
{
memcpy(*comment, old, oldlen-1);
memcpy(*comment+oldlen-1, "\n", 1);
}
memcpy(*comment + oldlen, start, pr_file_p - start);
oldlen = oldlen+pr_file_p - start;
while(oldlen > 0 && ((*comment)[oldlen-1] == '\r' || (*comment)[oldlen-1] == '\n' || (*comment)[oldlen-1] == '\t' || (*comment)[oldlen-1] == ' '))
oldlen--;
(*comment)[oldlen] = 0;
nextcomment = true; //include the next // too
nl = true;
}
// parse /* comments
else if (c=='/' && pr_file_p[1] == '*' && replace)
{
pr_file_p+=1;
start = pr_file_p+1;
do
{
pr_file_p++;
if (pr_file_p[0]=='\n')
{
QCC_PR_NewLine(true);
}
else if (pr_file_p[1] == 0)
{
QCC_PR_ParseError(0, "EOF inside comment\n");
break;
}
if (pr_file_p[0] == '/' && pr_file_p[1] == '*')
QCC_PR_ParseWarning(WARN_NESTEDCOMMENT, "\"/*\" inside comment");
} while (pr_file_p[0] != '*' || pr_file_p[1] != '/');
if (pr_file_p[1] == 0)
break;
old = replace?NULL:*comment;
replace = false;
oldlen = old?strlen(old):0;
*comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1);
memcpy(*comment, old, oldlen);
memcpy(*comment + oldlen, start, pr_file_p - start);
(*comment)[oldlen+pr_file_p - start] = 0;
pr_file_p+=2;
}
}
QCC_PR_LexWhitespace(false);
}
pbool QCC_PR_CheckTokenComment(const char *string, char **comment)
{
if (pr_token_type != tt_punct)
return false;
@ -4231,104 +4337,7 @@ pbool QCC_PR_CheckTokenComment(const char *string, char **comment)
return false;
if (comment)
{
// skip whitespace
nl = false;
while(nextcomment)
{
nextcomment = false;
while ((c = *pr_file_p) && qcc_iswhite(c))
{
if (c=='\n') //allow new lines, but only if there's whitespace before any tokens, and no double newlines.
{
if (nl)
{
pr_file_p++;
QCC_PR_NewLine(false);
break;
}
nl = true;
}
else
{
pr_file_p++;
nl = false;
}
}
if (nl)
break;
// parse // comments
if (c=='/' && pr_file_p[1] == '/')
{
pr_file_p += 2;
while (*pr_file_p == ' ' || *pr_file_p == '\t')
pr_file_p++;
start = pr_file_p;
while (*pr_file_p && *pr_file_p != '\n')
pr_file_p++;
if (*pr_file_p == '\n')
{
pr_file_p++;
QCC_PR_NewLine(false);
}
old = replace?NULL:*comment;
replace = false;
oldlen = old?strlen(old)+1:0;
*comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1);
if (oldlen)
{
memcpy(*comment, old, oldlen-1);
memcpy(*comment+oldlen-1, "\n", 1);
}
memcpy(*comment + oldlen, start, pr_file_p - start);
oldlen = oldlen+pr_file_p - start;
while(oldlen > 0 && ((*comment)[oldlen-1] == '\r' || (*comment)[oldlen-1] == '\n' || (*comment)[oldlen-1] == '\t' || (*comment)[oldlen-1] == ' '))
oldlen--;
(*comment)[oldlen] = 0;
nextcomment = true; //include the next // too
nl = true;
}
// parse /* comments
else if (c=='/' && pr_file_p[1] == '*' && replace)
{
pr_file_p+=1;
start = pr_file_p+1;
do
{
pr_file_p++;
if (pr_file_p[0]=='\n')
{
QCC_PR_NewLine(true);
}
else if (pr_file_p[1] == 0)
{
QCC_PR_ParseError(0, "EOF inside comment\n");
break;
}
if (pr_file_p[0] == '/' && pr_file_p[1] == '*')
QCC_PR_ParseWarning(WARN_NESTEDCOMMENT, "\"/*\" inside comment");
} while (pr_file_p[0] != '*' || pr_file_p[1] != '/');
if (pr_file_p[1] == 0)
break;
old = replace?NULL:*comment;
replace = false;
oldlen = old?strlen(old):0;
*comment = qccHunkAlloc(oldlen + (pr_file_p-start)+1);
memcpy(*comment, old, oldlen);
memcpy(*comment + oldlen, start, pr_file_p - start);
(*comment)[oldlen+pr_file_p - start] = 0;
pr_file_p+=2;
}
}
}
QCC_PR_LexComment(comment);
//and then do the rest properly.
QCC_PR_Lex ();

View File

@ -142,6 +142,7 @@ static pbool flag_dumpfilenames;
static pbool flag_dumpfields;
static pbool flag_dumpsymbols;
static pbool flag_dumpautocvars;
static pbool flag_dumplocalisation;
struct {
@ -424,6 +425,7 @@ compiler_flag_t compiler_flag[] = {
{&flag_dumpfields, FLAG_MIDCOMPILE,"dumpfields", "Write a .fld file", "Writes a .fld file that shows which fields are defined, along with their offsets etc, for weird debugging."},
{&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."},
{NULL}
};
@ -724,6 +726,9 @@ static void QCC_DumpAutoCvars (const char *outputname)
QCC_def_t *def = QCC_PR_GetDef(NULL, n, NULL, false, 0, 0);
n += 9;
if (!def)
continue; //erk?
if (def->comment)
desc = def->comment;
else
@ -765,6 +770,114 @@ static void QCC_DumpAutoCvars (const char *outputname)
}
}
static void QCC_DumpLocalisation (const char *outputname)
{
char line[65536];
int h, o;
QCC_def_t *def;
char *n;
snprintf(line, sizeof(line), "%s.pot", outputname);
h = SafeOpenWrite (line, 2*1024*1024);
if (h >= 0)
{
for (def = pr.def_head.next ; def ; def = def->next)
{
if (!strncmp(def->name, "dotranslate_", 12))
{
const QCC_eval_t *val = (const QCC_eval_t*)def->symboldata;
if (def->type->type != ev_string)
continue;
if (def->comment)
{
n = def->comment;
snprintf(line, sizeof(line), "#. ");
for (o = strlen(line); *n && o < countof(line)-10; n++)
{
if (*n == '\n')
{
if (n[1])
{
line[o++] = '\n';
line[o++] = '#';
line[o++] = '.';
line[o++] = ' ';
continue;
}
else line[++o] = 'n';
}
else if (*n == '\\') line[++o] = '\\';
else if (*n == '\"') line[++o] = '\"';
else if (*n == '\n') line[++o] = 'n';
else if (*n == '\r') line[++o] = 'r';
else if (*n == '\t') line[++o] = 't';
else
{ //hopefully the programmer used utf-8...
line[o++] = *n;
continue;
}
line[o++-1] = '\\';
}
line[o++] = '\n';
line[o++] = 0;
SafeWrite(h, line, strlen(line));
}
if (def->filen)
{ //strip any extra macro info there...
char *c = strchr(def->filen, ':');
if (c && (c[1] < '0' || c[1] > '9')) //don't get fooled by windows paths...
c = strchr(c+1, ':');
if (c)
{
*c = 0;
snprintf(line, sizeof(line), "#: %s:%i\n", def->filen, def->s_line);
*c = ':';
}
else
snprintf(line, sizeof(line), "#: %s:%i\n", def->filen, def->s_line);
SafeWrite(h, line, strlen(line));
}
n = strings + val->_int;
snprintf(line, sizeof(line), "msgid \"");
for (o = strlen(line); *n && o < countof(line)-5; n++)
{
if (*n == '\n' && n[1] && o < countof(line)-10)
{ //split multi-line stuff onto multiple lines, becase we can.
line[o++] = '\\';
line[o++] = 'n';
line[o++] = '\"';
line[o++] = '\n';
line[o++] = '\"';
continue;
}
else if (*n == '\\') line[++o] = '\\';
else if (*n == '\"') line[++o] = '\"';
else if (*n == '\n') line[++o] = 'n';
else if (*n == '\r') line[++o] = 'r';
else if (*n == '\t') line[++o] = 't';
else
{ //hopefully the programmer used utf-8...
line[o++] = *n;
continue;
}
line[o++-1] = '\\';
}
line[o++] = '\"';
line[o++] = '\n';
line[o++] = 0;
SafeWrite(h, line, strlen(line));
snprintf(line, sizeof(line), "msgstr \"\"\n\n");
SafeWrite(h, line, strlen(line));
}
}
}
SafeClose(h);
}
static void QCC_DumpFiles (const char *outputname)
{
struct
@ -2285,6 +2398,8 @@ strofs = (strofs+3)&~3;
QCC_DumpSymbols(destfile);
if (flag_dumpautocvars)
QCC_DumpAutoCvars(destfile);
if (flag_dumplocalisation)
QCC_DumpLocalisation(destfile);
switch(outputsttype)
{