Initial release of the message compiler.
This commit is contained in:
parent
13d74c5f0a
commit
3085591767
|
@ -58,6 +58,7 @@ BUILD = $(TOPOBJDIR)/tools/build@PROGEXT@
|
|||
MAKEDEP = $(TOPOBJDIR)/tools/makedep@PROGEXT@
|
||||
WRC = $(TOPOBJDIR)/tools/wrc/wrc@PROGEXT@
|
||||
WRCFLAGS = -c -s -p $*
|
||||
WMC = $(TOPOBJDIR)/tools/wmc/wmc@PROGEXT@
|
||||
DLLDIR = $(TOPOBJDIR)/dlls
|
||||
@SET_MAKE@
|
||||
|
||||
|
@ -200,6 +201,11 @@ all: Makefile
|
|||
$(WRC) check_wrc:
|
||||
cd $(TOPOBJDIR)/tools/wrc && $(MAKE) wrc@PROGEXT@
|
||||
|
||||
# Rule to rebuild the message compiler
|
||||
|
||||
$(WMC) check_wmc:
|
||||
cd $(TOPOBJDIR)/tools/wmc && $(MAKE) wmc@PROGEXT@
|
||||
|
||||
# Rule to rebuild the 'makedep' program
|
||||
|
||||
$(MAKEDEP) check_makedep:
|
||||
|
|
|
@ -6300,6 +6300,7 @@ server/Makefile
|
|||
tools/Makefile
|
||||
tools/cvdump/Makefile
|
||||
tools/wrc/Makefile
|
||||
tools/wmc/Makefile
|
||||
tsx11/Makefile
|
||||
unicode/Makefile
|
||||
win32/Makefile
|
||||
|
@ -6534,6 +6535,7 @@ server/Makefile
|
|||
tools/Makefile
|
||||
tools/cvdump/Makefile
|
||||
tools/wrc/Makefile
|
||||
tools/wmc/Makefile
|
||||
tsx11/Makefile
|
||||
unicode/Makefile
|
||||
win32/Makefile
|
||||
|
|
|
@ -1094,6 +1094,7 @@ server/Makefile
|
|||
tools/Makefile
|
||||
tools/cvdump/Makefile
|
||||
tools/wrc/Makefile
|
||||
tools/wmc/Makefile
|
||||
tsx11/Makefile
|
||||
unicode/Makefile
|
||||
win32/Makefile
|
||||
|
|
|
@ -11,6 +11,7 @@ C_SRCS = build.c makedep.c fnt2bdf.c bin2res.c
|
|||
|
||||
SUBDIRS = \
|
||||
cvdump \
|
||||
wmc \
|
||||
wrc
|
||||
|
||||
EXTRASUBDIRS = \
|
||||
|
@ -19,7 +20,7 @@ EXTRASUBDIRS = \
|
|||
winapi_check/win32 \
|
||||
wineconf.libs
|
||||
|
||||
all: $(PROGRAMS) wrc
|
||||
all: $(PROGRAMS) wmc wrc
|
||||
|
||||
@MAKE_RULES@
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Makefile
|
||||
wmc
|
||||
y.tab.c
|
||||
y.tab.h
|
|
@ -0,0 +1,5 @@
|
|||
---------------------------------------------------------------------------
|
||||
Version 1.0.0 (12-Jun-2000)
|
||||
|
||||
Bertho Stultiens <bertho@akhphd.au.dk>
|
||||
- Initial release
|
|
@ -0,0 +1,48 @@
|
|||
DEFS = -D__WINE__
|
||||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
YACCOPT = #-v
|
||||
|
||||
PROGRAMS = wmc@PROGEXT@
|
||||
MODULE = none
|
||||
|
||||
C_SRCS = \
|
||||
lang.c \
|
||||
mcl.c \
|
||||
utils.c \
|
||||
wmc.c \
|
||||
write.c
|
||||
|
||||
EXTRA_SRCS = mcy.y
|
||||
EXTRA_OBJS = y.tab.o
|
||||
|
||||
all: check_unicode $(PROGRAMS)
|
||||
|
||||
depend: y.tab.h
|
||||
|
||||
@MAKE_RULES@
|
||||
|
||||
wmc@PROGEXT@: $(OBJS) $(TOPOBJDIR)/unicode/unicode.o
|
||||
$(CC) $(CFLAGS) -o wmc@PROGEXT@ $(OBJS) $(TOPOBJDIR)/unicode/unicode.o $(LEXLIB)
|
||||
|
||||
$(TOPOBJDIR)/unicode/unicode.o check_unicode:
|
||||
cd $(TOPSRCDIR)/unicode && $(MAKE)
|
||||
|
||||
y.tab.c y.tab.h: mcy.y
|
||||
$(YACC) $(YACCOPT) -d -t $(SRCDIR)/mcy.y
|
||||
|
||||
clean::
|
||||
$(RM) y.tab.c y.tab.h y.output
|
||||
|
||||
install:: $(PROGRAMS)
|
||||
[ -d $(bindir) ] || $(MKDIR) $(bindir)
|
||||
[ -d $(mandir)/man$(prog_manext) ] || $(MKDIR) $(mandir)/man$(prog_manext)
|
||||
$(INSTALL_DATA) wmc.man $(mandir)/man$(prog_manext)/wmc.$(prog_manext)
|
||||
$(INSTALL_PROGRAM) wmc $(bindir)/wmc
|
||||
|
||||
uninstall::
|
||||
$(RM) $(bindir)/wmc $(mandir)/man$(prog_manext)/wmc.$(prog_manext)
|
||||
|
||||
### Dependencies:
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Wine Message Compiler language and codepage support
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wmc.h"
|
||||
#include "lang.h"
|
||||
|
||||
|
||||
/*
|
||||
* Languages supported
|
||||
*
|
||||
* MUST be sorting ascending on language ID
|
||||
*/
|
||||
static const language_t languages[] = {
|
||||
|
||||
{0x0402, 866, 1251, "Bulgarian", "Bulgaria"},
|
||||
{0x0403, 850, 1252, "Catalan", "Spain"},
|
||||
{0x0405, 852, 1250, "Czech", "Czech Republic"},
|
||||
{0x0406, 850, 1252, "Danish", "Denmark"},
|
||||
{0x0407, 850, 1252, "German", "Germany"},
|
||||
{0x0408, 737, 1253, "Greek", "Greece"},
|
||||
{0x0409, 437, 1252, "English", "United States"},
|
||||
{0x040A, 850, 1252, "Spanish - Traditional Sort", "Spain"},
|
||||
{0x040B, 850, 1252, "Finnish", "Finland"},
|
||||
{0x040C, 850, 1252, "French", "France"},
|
||||
{0x040E, 852, 1250, "Hungarian", "Hungary"},
|
||||
{0x040F, 850, 1252, "Icelandic", "Iceland"},
|
||||
{0x0410, 850, 1252, "Italian", "Italy"},
|
||||
{0x0411, 932, 932, "Japanese", "Japan"},
|
||||
{0x0412, 949, 949, "Korean", "Korea (south)"},
|
||||
{0x0413, 850, 1252, "Dutch", "Netherlands"},
|
||||
{0x0414, 850, 1252, "Norwegian (Bokmål)", "Norway"},
|
||||
{0x0415, 852, 1250, "Polish", "Poland"},
|
||||
{0x0416, 850, 1252, "Portuguese", "Brazil"},
|
||||
{0x0418, 852, 1250, "Romanian", "Romania"},
|
||||
{0x0419, 866, 1251, "Russian", "Russia"},
|
||||
{0x041A, 852, 1250, "Croatian", "Croatia"},
|
||||
{0x041B, 852, 1250, "Slovak", "Slovakia"},
|
||||
{0x041C, 852, 1250, "Albanian", "Albania"},
|
||||
{0x041D, 850, 1252, "Swedish", "Sweden"},
|
||||
{0x041F, 857, 1254, "Turkish", "Turkey"},
|
||||
{0x0421, 850, 1252, "Indonesian", "Indonesia"},
|
||||
{0x0422, 866, 1251, "Ukrainian", "Ukraine"},
|
||||
{0x0423, 866, 1251, "Belarusian", "Belarus"},
|
||||
{0x0424, 852, 1250, "Slovene", "Slovenia"},
|
||||
{0x0425, 775, 1257, "Estonian", "Estonia"},
|
||||
{0x0426, 775, 1257, "Latvian", "Latvia"},
|
||||
{0x0427, 775, 1257, "Lithuanian", "Lithuania"},
|
||||
/* {0x042A, ?, ?, "Vietnamese", "Vietnam"},*/
|
||||
{0x042D, 850, 1252, "Basque", "Spain"},
|
||||
{0x042F, 866, 1251, "Macedonian", "Former Yugoslav Republic of Macedonia"},
|
||||
{0x0436, 850, 1252, "Afrikaans", "South Africa"},
|
||||
/* {0x0438, 852, 1252, "Faroese", "Faroe Islands"}, FIXME: Not sure about codepages */
|
||||
{0x043C, 437, 1252, "Irish", "Ireland"},
|
||||
/* {0x048F, ?, ?, "Esperanto", "<none>"},*/
|
||||
/* {0x0804, ?, ?, "Chinese (People's replublic of China)", People's republic of China"},*/
|
||||
{0x0807, 850, 1252, "German", "Switzerland"},
|
||||
{0x0809, 850, 1252, "English", "United Kingdom"},
|
||||
{0x080A, 850, 1252, "Spanish", "Mexico"},
|
||||
{0x080C, 850, 1252, "French", "Belgium"},
|
||||
{0x0810, 850, 1252, "Italian", "Switzerland"},
|
||||
{0x0813, 850, 1252, "Dutch", "Belgium"},
|
||||
{0x0814, 850, 1252, "Norwegian (Nynorsk)", "Norway"},
|
||||
{0x0816, 850, 1252, "Portuguese", "Portugal"},
|
||||
/* {0x081A, ?, ?, "Serbian (latin)", "Yugoslavia"},*/
|
||||
{0x081D, 850, 1252, "Swedish (Finland)", "Finland"},
|
||||
{0x0C07, 850, 1252, "German", "Austria"},
|
||||
{0x0C09, 850, 1252, "English", "Australia"},
|
||||
{0x0C0A, 850, 1252, "Spanish - International Sort", "Spain"},
|
||||
{0x0C0C, 850, 1252, "French", "Canada"},
|
||||
{0x0C1A, 855, 1251, "Serbian (Cyrillic)", "Serbia"},
|
||||
{0x1007, 850, 1252, "German", "Luxembourg"},
|
||||
{0x1009, 850, 1252, "English", "Canada"},
|
||||
{0x100A, 850, 1252, "Spanish", "Guatemala"},
|
||||
{0x100C, 850, 1252, "French", "Switzerland"},
|
||||
{0x1407, 850, 1252, "German", "Liechtenstein"},
|
||||
{0x1409, 850, 1252, "English", "New Zealand"},
|
||||
{0x140A, 850, 1252, "Spanish", "Costa Rica"},
|
||||
{0x140C, 850, 1252, "French", "Luxembourg"},
|
||||
{0x1809, 850, 1252, "English", "Ireland"},
|
||||
{0x180A, 850, 1252, "Spanish", "Panama"},
|
||||
{0x1C09, 437, 1252, "English", "South Africa"},
|
||||
{0x1C0A, 850, 1252, "Spanish", "Dominican Republic"},
|
||||
{0x2009, 850, 1252, "English", "Jamaica"},
|
||||
{0x200A, 850, 1252, "Spanish", "Venezuela"},
|
||||
{0x2409, 850, 1252, "English", "Caribbean"},
|
||||
{0x240A, 850, 1252, "Spanish", "Colombia"},
|
||||
{0x2809, 850, 1252, "English", "Belize"},
|
||||
{0x280A, 850, 1252, "Spanish", "Peru"},
|
||||
{0x2C09, 437, 1252, "English", "Trinidad & Tobago"},
|
||||
{0x2C0A, 850, 1252, "Spanish", "Argentina"},
|
||||
{0x300A, 850, 1252, "Spanish", "Ecuador"},
|
||||
{0x340A, 850, 1252, "Spanish", "Chile"},
|
||||
{0x380A, 850, 1252, "Spanish", "Uruguay"},
|
||||
{0x3C0A, 850, 1252, "Spanish", "Paraguay"},
|
||||
{0x400A, 850, 1252, "Spanish", "Bolivia"},
|
||||
{0x440A, 850, 1252, "Spanish", "El Salvador"},
|
||||
{0x480A, 850, 1252, "Spanish", "Honduras"},
|
||||
{0x4C0A, 850, 1252, "Spanish", "Nicaragua"},
|
||||
{0x500A, 850, 1252, "Spanish", "Puerto Rico"}
|
||||
};
|
||||
|
||||
#define NLAN (sizeof(languages)/sizeof(languages[0]))
|
||||
|
||||
void show_languages(void)
|
||||
{
|
||||
int i;
|
||||
printf(" Code | DOS-cp | WIN-cp | Language | Country\n");
|
||||
printf("-------+--------+--------+--------------+---------\n");
|
||||
for(i = 0; i < NLAN; i++)
|
||||
printf("0x%04x | %5d | %5d | %-12s | %s\n",
|
||||
languages[i].id,
|
||||
languages[i].doscp,
|
||||
languages[i].wincp,
|
||||
languages[i].name,
|
||||
languages[i].country);
|
||||
}
|
||||
|
||||
static int langcmp(const void *p1, const void *p2)
|
||||
{
|
||||
return *(unsigned *)p1 - ((language_t *)p2)->id;
|
||||
}
|
||||
|
||||
const language_t *find_language(unsigned id)
|
||||
{
|
||||
return (const language_t *)bsearch(&id, languages, NLAN, sizeof(languages[0]), langcmp);
|
||||
}
|
||||
|
||||
void show_codepages(void)
|
||||
{
|
||||
unsigned i;
|
||||
const union cptable *cpp;
|
||||
printf("Codepages:\n");
|
||||
for(i = 0; (cpp = cp_enum_table(i)); i++)
|
||||
{
|
||||
printf("%-5d %s\n", cpp->info.codepage, cpp->info.name);
|
||||
}
|
||||
}
|
||||
|
||||
const union cptable *find_codepage(int id)
|
||||
{
|
||||
return cp_get_table(id);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Wine Message Compiler language and codepage support
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WMC_LANG_H
|
||||
#define __WMC_LANG_H
|
||||
|
||||
#include "wine/unicode.h"
|
||||
|
||||
typedef struct language {
|
||||
unsigned id;
|
||||
unsigned doscp;
|
||||
unsigned wincp;
|
||||
char *name;
|
||||
char *country;
|
||||
} language_t;
|
||||
|
||||
void show_languages(void);
|
||||
const language_t *find_language(unsigned id);
|
||||
void show_codepages(void);
|
||||
const union cptable *find_codepage(int id);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
{"South Africa", 0x0436, 1252},
|
||||
{"Saudi Arabia", 0x0401, 1256},
|
||||
{"Lebanon", 0x0401, 1256},
|
||||
{"Egypt", 0x0401, 1256},
|
||||
{"Algeria", 0x0401, 1256},
|
||||
{"Iraq", 0x0401, 1256},
|
||||
{"Kuwait", 0x0401, 1256},
|
||||
{"Marocco", 0x0401, 1256},
|
||||
{"Oman", 0x0401, 1256},
|
||||
{"Quatar", 0x0401, 1256},
|
||||
{"Syria", 0x0401, 1256},
|
||||
{"Tunisia", 0x0401, 1256},
|
||||
{"United Arab Emirates",0x0401, 1256},
|
||||
{"Belaruss", 0x0423, 1251},
|
||||
{"Bulgaria", 0x0402
|
||||
{"France", 0x040c, 1252},
|
||||
{"Spain", 0x0403, 1252},
|
||||
{"China (Taiwan)", 0x0404
|
||||
{"United Kingdom", 0x0409, 1252},
|
||||
{"Wales", 0x0409, 1252}, /* FIXME */
|
||||
{"Czech Republic", 0x0405, 1250},
|
||||
{"Denmark", 0x0406, 1252},
|
||||
{"Austria", 0x0407, 1252},
|
||||
{"Liechtenstein", 0x0407, 1252},
|
||||
{"Luxemburg", 0x0407, 1252},
|
||||
{"Switzerland", 0x0807, 1252},
|
||||
{"Germany", 0x0407, 1252},
|
||||
{"Australia", 0x0c09, 1252},
|
||||
{"Caribbean", 0x2409, 1252},
|
||||
{"Canada", 0x1009, 1252},
|
||||
{"United Kingdom", 0x0809, 1252},
|
||||
{"Ireland", 0x1809, 1252},
|
||||
{"Jamaica", 0x2009, 1252},
|
||||
{"Belize", 0x2809, 1252},
|
||||
{"South Africa", 0x1c09, 1252},
|
||||
{"Trinidad & Tobago", 0x2c09, 1252},
|
||||
{"United States", 0x0409, 1252},
|
||||
{"New Zealand", 0x1409, 1252},
|
||||
{"Panama", 0x040a, 1252},
|
||||
{"Bolivia", 0x040a, 1252},
|
||||
{"Costa Rica", 0x140a, 1252},
|
||||
{"Dominican Republic", 0x040a, 1252},
|
||||
{"El Salvador", 0x040a, 1252},
|
||||
{"Ecuador", 0x040a, 1252},
|
||||
{"Guatemala", 0x040a, 1252},
|
||||
{"Honduras", 0x040a, 1252},
|
||||
{"Nicaragua", 0x040a, 1252},
|
||||
{"Chile", 0x040a, 1252},
|
||||
{"Mexico", 0x040a, 1252},
|
||||
{"Spain", 0x040a, 1252},
|
||||
{"Colombia", 0x040a, 1252},
|
||||
{"Spain", 0x040a, 1252},
|
||||
{"Peru", 0x040a, 1252},
|
||||
{"Argentina", 0x040a, 1252},
|
||||
{"Estonia", 0x0425, 1252},
|
||||
{"Puerto Rico", 0x040a, 1252},
|
||||
{"Venezuela", 0x040a, 1252},
|
||||
{"Uruguay", 0x380a, 1252},
|
||||
{"Paraguay", 0x040a, 1252},
|
||||
{"Spain (Basque)", 0x04d2, 1252},
|
||||
{"Finland", 0x040b, 1252},
|
||||
{"Faroe Islands", 0x0438, 1252},
|
||||
{"France", 0x040c, 1252},
|
||||
{"Belgium", 0x040c, 1252},
|
||||
{"Canada", 0x040c, 1252},
|
||||
{"Luxemburg", 0x040c, 1252},
|
||||
{"Switzerland", 0x040c, 1252},
|
||||
{"Ireland", 0x0000, 1252},
|
||||
{"United Kingdom", 0x0409, 1252},
|
||||
{"Isle of Man", 0x0409, 1252},
|
||||
{"Greece", 0x0408, 1253},
|
||||
{"Croatia", 0x041a, 1250},
|
||||
{"Hungary", 0x040e, 1250},
|
||||
{"Indonesia", 0x0421, 1252},
|
||||
{"Iceland", 0x040f, 1252},
|
||||
{"Italy", 0x0410, 1252},
|
||||
{"Switzerand", 0x0410, 1252},
|
||||
{"Japan", 0x0411, 0},
|
||||
{"Korea", 0x0000, 0},
|
||||
{"Korea (South)", 0x0412, 0},
|
||||
{"Lithuania", 0x0427, 1257},
|
||||
{"Latvia", 0x0426, 1257},
|
||||
{"Belgium", 0x0413, 1252},
|
||||
{"Netherlands", 0x0413, 1252},
|
||||
{"Suriname", 0x0413, 1252},
|
||||
{"Norway", 0x0814, 1252},
|
||||
{"Norway", 0x0414, 1252},
|
||||
{"Poland", 0x0415, 1250},
|
||||
{"Brazil", 0x0416, 1252},
|
||||
{"Portugal", 0x0416, 1252},
|
||||
{"Romania", 0x0418, 1250},
|
||||
{"Russia", 0x0000, 1251},
|
||||
{"Slovakia", 0x041b, 1250},
|
||||
{"Slovenia", 0x0424, 1250},
|
||||
{"Albania", 0x041c, 0},
|
||||
{"Yugoslavia", 0x0c1a, 0},
|
||||
{"Yugoslavia", 0x081a, 1250},
|
||||
{"Sweden", 0x041d, 1252},
|
||||
{"Finland", 0x081d, 1252},
|
||||
{"Thailand", 0x041e, 0},
|
||||
{"Turkey", 0x041f, 1254},
|
||||
{"Ukrainia", 0x0422, 1251},
|
||||
{"Vietnam", 0x042a, 0},
|
||||
{"Belgium", 0x0490, 1252},
|
||||
{"Hong Kong", 0x0404, 0},
|
||||
{"People's republic of China", 0x0804, 0},
|
||||
{"Singapore", 0x0404, 0}
|
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
* Wine Message Compiler lexical scanner
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "wmc.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "y.tab.h"
|
||||
|
||||
/*
|
||||
* Keywords are case insenitive. All normal input is treated as
|
||||
* being in codepage iso-8859-1 for ascii input files (unicode
|
||||
* page 0) and as equivalent unicode if unicode input is selected.
|
||||
* All normal input, which is not part of a message text, is
|
||||
* enforced to be unicode page 0. Otherwise an error will be
|
||||
* generated. The normal file data should only be ASCII because
|
||||
* that is the basic definition of the grammar.
|
||||
*
|
||||
* Byteorder or unicode input is determined automatically by
|
||||
* reading the first 8 bytes and checking them against unicode
|
||||
* page 0 byteorder (hibyte must be 0).
|
||||
* -- FIXME --
|
||||
* Alternatively, the input is checked against a special byte
|
||||
* sequence to identify the file.
|
||||
* -- FIXME --
|
||||
*
|
||||
*
|
||||
* Keywords:
|
||||
* Codepages
|
||||
* Facility
|
||||
* FacilityNames
|
||||
* LanguageNames
|
||||
* MessageId
|
||||
* MessageIdTypedef
|
||||
* Severity
|
||||
* SeverityNames
|
||||
* SymbolicName
|
||||
*
|
||||
* Default added identifiers for classes:
|
||||
* SeverityNames:
|
||||
* Success = 0x0
|
||||
* Informational = 0x1
|
||||
* Warning = 0x2
|
||||
* Error = 0x3
|
||||
* FacilityNames:
|
||||
* System = 0x0FF
|
||||
* Application = 0xFFF
|
||||
*
|
||||
* The 'Codepages' keyword is a wmc extension.
|
||||
*/
|
||||
|
||||
static WCHAR ustr_application[] = { 'A', 'p', 'p', 'l', 'i', 'c', 'a', 't', 'i', 'o', 'n', 0 };
|
||||
static WCHAR ustr_codepages[] = { 'C', 'o', 'd', 'e', 'p', 'a', 'g', 'e', 's', 0 };
|
||||
static WCHAR ustr_english[] = { 'E', 'n', 'g', 'l', 'i', 's', 'h', 0 };
|
||||
static WCHAR ustr_error[] = { 'E', 'r', 'r', 'o', 'r', 0 };
|
||||
static WCHAR ustr_facility[] = { 'F', 'a', 'c', 'i', 'l', 'i', 't', 'y', 0 };
|
||||
static WCHAR ustr_facilitynames[] = { 'F', 'a', 'c', 'i', 'l', 'i', 't', 'y', 'N', 'a', 'm', 'e', 's', 0 };
|
||||
static WCHAR ustr_informational[] = { 'I', 'n', 'f', 'o', 'r', 'm', 'a', 't', 'i', 'o', 'n', 'a', 'l', 0 };
|
||||
static WCHAR ustr_language[] = { 'L', 'a', 'n', 'g', 'u', 'a', 'g', 'e', 0};
|
||||
static WCHAR ustr_languagenames[] = { 'L', 'a', 'n', 'g', 'u', 'a', 'g', 'e', 'N', 'a', 'm', 'e', 's', 0};
|
||||
static WCHAR ustr_messageid[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'I', 'd', 0 };
|
||||
static WCHAR ustr_messageidtypedef[] = { 'M', 'e', 's', 's', 'a', 'g', 'e', 'I', 'd', 'T', 'y', 'p', 'e', 'd', 'e', 'f', 0 };
|
||||
static WCHAR ustr_outputbase[] = { 'O', 'u', 't', 'p', 'u', 't', 'B', 'a', 's', 'e', 0 };
|
||||
static WCHAR ustr_severity[] = { 'S', 'e', 'v', 'e', 'r', 'i', 't', 'y', 0 };
|
||||
static WCHAR ustr_severitynames[] = { 'S', 'e', 'v', 'e', 'r', 'i', 't', 'y', 'N', 'a', 'm', 'e', 's', 0 };
|
||||
static WCHAR ustr_success[] = { 'S', 'u', 'c', 'c', 'e', 's', 's', 0 };
|
||||
static WCHAR ustr_symbolicname[] = { 'S', 'y', 'm', 'b', 'o', 'l', 'i', 'c', 'N', 'a', 'm', 'e', 0 };
|
||||
static WCHAR ustr_system[] = { 'S', 'y', 's', 't', 'e', 'm', 0 };
|
||||
static WCHAR ustr_warning[] = { 'W', 'a', 'r', 'n', 'i', 'n', 'g', 0 };
|
||||
static WCHAR ustr_msg00001[] = { 'm', 's', 'g', '0', '0', '0', '0', '1', 0 };
|
||||
/*
|
||||
* This table is to beat any form of "expression building" to check for
|
||||
* correct filename characters. It is also used for ident checks.
|
||||
* FIXME: use it more consistently.
|
||||
*/
|
||||
|
||||
#define CH_SHORTNAME 0x01
|
||||
#define CH_LONGNAME 0x02
|
||||
#define CH_IDENT 0x04
|
||||
#define CH_NUMBER 0x08
|
||||
/*#define CH_WILDCARD 0x10*/
|
||||
/*#define CH_DOT 0x20*/
|
||||
#define CH_PUNCT 0x40
|
||||
#define CH_INVALID 0x80
|
||||
|
||||
static const char char_table[256] = {
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* 0x00 - 0x07 */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* 0x08 - 0x0F */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* 0x10 - 0x17 */
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, /* 0x18 - 0x1F */
|
||||
0x80, 0x03, 0x80, 0x03, 0x03, 0x03, 0x03, 0x03, /* 0x20 - 0x27 " !"#$%&'" */
|
||||
0x43, 0x43, 0x10, 0x80, 0x03, 0x03, 0x22, 0x80, /* 0x28 - 0x2F "()*+,-./" */
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, /* 0x30 - 0x37 "01234567" */
|
||||
0x0b, 0x0b, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x10, /* 0x38 - 0x3F "89:;<=>?" */
|
||||
0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x40 - 0x47 "@ABCDEFG" */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x48 - 0x4F "HIJKLMNO" */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x50 - 0x57 "PQRSTUVW" */
|
||||
0x07, 0x07, 0x07, 0x80, 0x80, 0x80, 0x80, 0x07, /* 0x58 - 0x5F "XYZ[\]^_" */
|
||||
0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x60 - 0x67 "`abcdefg" */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x68 - 0x6F "hijklmno" */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* 0x70 - 0x77 "pqrstuvw" */
|
||||
0x07, 0x07, 0x07, 0x03, 0x80, 0x03, 0x03, 0x80, /* 0x78 - 0x7F "xyz{|}~ " */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0x80 - 0x87 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0x88 - 0x8F */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0x90 - 0x97 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0x98 - 0x9F */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xA0 - 0xA7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xA8 - 0xAF */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xB0 - 0xB7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xB8 - 0xBF */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xC0 - 0xC7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xC8 - 0xCF */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xD0 - 0xD7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xD8 - 0xDF */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xE0 - 0xE7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xE8 - 0xEF */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 0xF0 - 0xF7 */
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x80, /* 0xF8 - 0xFF */
|
||||
};
|
||||
|
||||
static int isisochar(int ch)
|
||||
{
|
||||
return !(ch & (~0xff));
|
||||
}
|
||||
|
||||
static int codepage;
|
||||
static const union cptable *codepage_def;
|
||||
|
||||
void set_codepage(int cp)
|
||||
{
|
||||
codepage = cp;
|
||||
codepage_def = find_codepage(codepage);
|
||||
if(!codepage_def)
|
||||
xyyerror("Codepage %d not found; cannot process", codepage);
|
||||
}
|
||||
|
||||
/*
|
||||
* Input functions
|
||||
*/
|
||||
static int nungetstack = 0;
|
||||
static int allocungetstack = 0;
|
||||
static char *ungetstack = NULL;
|
||||
static int ninputbuffer = 0;
|
||||
static WCHAR *inputbuffer = NULL;
|
||||
static char *xlatebuffer = NULL;
|
||||
|
||||
#define INPUTBUFFER_SIZE 2048 /* Must be larger than 4 and approx. large enough to hold a line */
|
||||
|
||||
/*
|
||||
* Fill the input buffer with *one* line of input.
|
||||
* The line is '\n' terminated so that scanning
|
||||
* messages with translation works as expected
|
||||
* (otherwise we cannot pre-translate because the
|
||||
* language is first known one line before the
|
||||
* actual message).
|
||||
*/
|
||||
static int fill_inputbuffer(void)
|
||||
{
|
||||
int n;
|
||||
static char err_fatalread[] = "Fatal: reading input failed";
|
||||
static int endian = -1;
|
||||
|
||||
if(!inputbuffer)
|
||||
{
|
||||
inputbuffer = xmalloc(INPUTBUFFER_SIZE);
|
||||
xlatebuffer = xmalloc(INPUTBUFFER_SIZE);
|
||||
}
|
||||
|
||||
try_again:
|
||||
if(!unicodein)
|
||||
{
|
||||
char *cptr;
|
||||
cptr = fgets(xlatebuffer, INPUTBUFFER_SIZE, yyin);
|
||||
if(!cptr && ferror(yyin))
|
||||
xyyerror(err_fatalread);
|
||||
else if(!cptr)
|
||||
return 0;
|
||||
assert(codepage_def != NULL);
|
||||
n = cp_mbstowcs(codepage_def, 0, xlatebuffer, strlen(xlatebuffer)+1, inputbuffer, INPUTBUFFER_SIZE);
|
||||
if(n < 0)
|
||||
internal_error(__FILE__, __LINE__, "Could not translate to unicode (%d)", n);
|
||||
if(n <= 1)
|
||||
goto try_again; /* Should not hapen */
|
||||
n--; /* Strip added conversion '\0' from input length */
|
||||
/*
|
||||
* FIXME:
|
||||
* Detect UTF-8 in the first time we read some bytes by
|
||||
* checking the special sequence "FE..." or something like
|
||||
* that. I need to check www.unicode.org for details.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if(endian == -1)
|
||||
{
|
||||
n = fread(inputbuffer, 1, 8, yyin);
|
||||
if(n != 8)
|
||||
{
|
||||
if(!n && ferror(yyin))
|
||||
xyyerror(err_fatalread);
|
||||
else
|
||||
xyyerror("Fatal: file to short to determine byteorder (should never happen)");
|
||||
}
|
||||
if(isisochar(inputbuffer[0]) &&
|
||||
isisochar(inputbuffer[1]) &&
|
||||
isisochar(inputbuffer[2]) &&
|
||||
isisochar(inputbuffer[3]))
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
endian = WMC_BO_BIG;
|
||||
#else
|
||||
endian = WMC_BO_LITTLE;
|
||||
#endif
|
||||
}
|
||||
else if(isisochar(BYTESWAP_WORD(inputbuffer[0])) &&
|
||||
isisochar(BYTESWAP_WORD(inputbuffer[1])) &&
|
||||
isisochar(BYTESWAP_WORD(inputbuffer[2])) &&
|
||||
isisochar(BYTESWAP_WORD(inputbuffer[3])))
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
endian = WMC_BO_LITTLE;
|
||||
#else
|
||||
endian = WMC_BO_BIG;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
xyyerror("Fatal: cannot determine file's byteorder");
|
||||
/* FIXME:
|
||||
* Determine the file-endian with the leader-bytes
|
||||
* "FF FE..."; can't remember the exact sequence.
|
||||
*/
|
||||
n /= 2;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if(endian == WMC_BO_LITTLE)
|
||||
#else
|
||||
if(endian == WMC_BO_BIG)
|
||||
#endif
|
||||
{
|
||||
inputbuffer[0] = BYTESWAP_WORD(inputbuffer[0]);
|
||||
inputbuffer[1] = BYTESWAP_WORD(inputbuffer[1]);
|
||||
inputbuffer[2] = BYTESWAP_WORD(inputbuffer[2]);
|
||||
inputbuffer[3] = BYTESWAP_WORD(inputbuffer[3]);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
n = 0;
|
||||
for(i = 0; i < INPUTBUFFER_SIZE; i++)
|
||||
{
|
||||
int t;
|
||||
t = fread(&inputbuffer[i], 2, 1, yyin);
|
||||
if(!t && ferror(yyin))
|
||||
xyyerror(err_fatalread);
|
||||
else if(!t && n)
|
||||
break;
|
||||
n++;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if(endian == WMC_BO_LITTLE)
|
||||
#else
|
||||
if(endian == WMC_BO_BIG)
|
||||
#endif
|
||||
{
|
||||
if((inputbuffer[i] = BYTESWAP_WORD(inputbuffer[i])) == '\n')
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inputbuffer[i] == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!n)
|
||||
{
|
||||
yywarning("Re-read line (input was or converted to zilch)");
|
||||
goto try_again; /* Should not happen, but could be due to stdin reading and a signal */
|
||||
}
|
||||
|
||||
ninputbuffer += n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_unichar(void)
|
||||
{
|
||||
static WCHAR *b = NULL;
|
||||
char_number++;
|
||||
|
||||
if(nungetstack)
|
||||
return ungetstack[--nungetstack];
|
||||
|
||||
if(!ninputbuffer)
|
||||
{
|
||||
if(!fill_inputbuffer())
|
||||
return EOF;
|
||||
b = inputbuffer;
|
||||
}
|
||||
|
||||
ninputbuffer--;
|
||||
return (int)(*b++ & 0xffff);
|
||||
}
|
||||
|
||||
static void unget_unichar(int ch)
|
||||
{
|
||||
if(ch == EOF)
|
||||
return;
|
||||
|
||||
char_number--;
|
||||
|
||||
if(nungetstack == allocungetstack)
|
||||
{
|
||||
allocungetstack += 32;
|
||||
ungetstack = xrealloc(ungetstack, allocungetstack * sizeof(*ungetstack));
|
||||
}
|
||||
|
||||
ungetstack[nungetstack++] = (WCHAR)ch;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Normal character stack.
|
||||
* Used for number scanning.
|
||||
*/
|
||||
static int ncharstack = 0;
|
||||
static int alloccharstack = 0;
|
||||
static char *charstack = NULL;
|
||||
|
||||
static void empty_char_stack(void)
|
||||
{
|
||||
ncharstack = 0;
|
||||
}
|
||||
|
||||
static void push_char(int ch)
|
||||
{
|
||||
if(ncharstack == alloccharstack)
|
||||
{
|
||||
alloccharstack += 32;
|
||||
charstack = xrealloc(charstack, alloccharstack * sizeof(*charstack));
|
||||
}
|
||||
charstack[ncharstack++] = (char)ch;
|
||||
}
|
||||
|
||||
static int tos_char_stack(void)
|
||||
{
|
||||
if(!ncharstack)
|
||||
return 0;
|
||||
else
|
||||
return (int)(charstack[ncharstack-1] & 0xff);
|
||||
}
|
||||
|
||||
static char *get_char_stack(void)
|
||||
{
|
||||
return charstack;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unicode character stack.
|
||||
* Used for general scanner.
|
||||
*/
|
||||
static int nunicharstack = 0;
|
||||
static int allocunicharstack = 0;
|
||||
static WCHAR *unicharstack = NULL;
|
||||
|
||||
static void empty_unichar_stack(void)
|
||||
{
|
||||
nunicharstack = 0;
|
||||
}
|
||||
|
||||
static void push_unichar(int ch)
|
||||
{
|
||||
if(nunicharstack == allocunicharstack)
|
||||
{
|
||||
allocunicharstack += 128;
|
||||
unicharstack = xrealloc(unicharstack, allocunicharstack * sizeof(*unicharstack));
|
||||
}
|
||||
unicharstack[nunicharstack++] = (WCHAR)ch;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int tos_unichar_stack(void)
|
||||
{
|
||||
if(!nunicharstack)
|
||||
return 0;
|
||||
else
|
||||
return (int)(unicharstack[nunicharstack-1] & 0xffff);
|
||||
}
|
||||
#endif
|
||||
|
||||
static WCHAR *get_unichar_stack(void)
|
||||
{
|
||||
return unicharstack;
|
||||
}
|
||||
|
||||
/*
|
||||
* Number scanner
|
||||
*
|
||||
* state | ch | next state
|
||||
* ------+-----------------+--------------------------
|
||||
* 0 | [0] | 1
|
||||
* 0 | [1-9] | 4
|
||||
* 0 | . | error (should never occur)
|
||||
* 1 | [xX] | 2
|
||||
* 1 | [0-7] | 3
|
||||
* 1 | [89a-wyzA-WYZ_] | error invalid digit
|
||||
* 1 | . | return 0
|
||||
* 2 | [0-9a-fA-F] | 2
|
||||
* 2 | [g-zG-Z_] | error invalid hex digit
|
||||
* 2 | . | return (hex-number) if TOS != [xX] else error
|
||||
* 3 | [0-7] | 3
|
||||
* 3 | [89a-zA-Z_] | error invalid octal digit
|
||||
* 3 | . | return (octal-number)
|
||||
* 4 | [0-9] | 4
|
||||
* 4 | [a-zA-Z_] | error invalid decimal digit
|
||||
* 4 | . | return (decimal-number)
|
||||
*
|
||||
* All non-identifier characters [^a-zA-Z_0-9] terminate the scan
|
||||
* and return the value. This is not entirely correct, but close
|
||||
* enough (should check punctuators as trailing context, but the
|
||||
* char_table is not adapted to that and it is questionable whether
|
||||
* it is worth the trouble).
|
||||
* All non-iso-8859-1 characters are an error.
|
||||
*/
|
||||
static int scan_number(int ch)
|
||||
{
|
||||
int state = 0;
|
||||
int base = 10;
|
||||
empty_char_stack();
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(!isisochar(ch))
|
||||
xyyerror("Invalid digit");
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case 0:
|
||||
if(isdigit(ch))
|
||||
{
|
||||
push_char(ch);
|
||||
if(ch == '0')
|
||||
state = 1;
|
||||
else
|
||||
state = 4;
|
||||
}
|
||||
else
|
||||
internal_error(__FILE__, __LINE__, "Non-digit in first number-scanner state");
|
||||
break;
|
||||
case 1:
|
||||
if(ch == 'x' || ch == 'X')
|
||||
{
|
||||
push_char(ch);
|
||||
state = 2;
|
||||
}
|
||||
else if(ch >= '0' && ch <= '7')
|
||||
{
|
||||
push_char(ch);
|
||||
state = 3;
|
||||
}
|
||||
else if(isalpha(ch) || ch == '_')
|
||||
xyyerror("Invalid number digit");
|
||||
else
|
||||
{
|
||||
unget_unichar(ch);
|
||||
yylval.num = 0;
|
||||
return tNUMBER;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(isxdigit(ch))
|
||||
push_char(ch);
|
||||
else if(isalpha(ch) || ch == '_' || !isxdigit(tos_char_stack()))
|
||||
xyyerror("Invalid hex digit");
|
||||
else
|
||||
{
|
||||
base = 16;
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(ch >= '0' && ch <= '7')
|
||||
push_char(ch);
|
||||
else if(isalnum(ch) || ch == '_')
|
||||
xyyerror("Invalid octal digit");
|
||||
else
|
||||
{
|
||||
base = 8;
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if(isdigit(ch))
|
||||
push_char(ch);
|
||||
else if(isalnum(ch) || ch == '_')
|
||||
xyyerror("Invalid decimal digit");
|
||||
else
|
||||
{
|
||||
base = 10;
|
||||
goto finish;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
internal_error(__FILE__, __LINE__, "Invalid state in number-scanner");
|
||||
}
|
||||
ch = get_unichar();
|
||||
}
|
||||
finish:
|
||||
unget_unichar(ch);
|
||||
push_char(0);
|
||||
yylval.num = strtoul(get_char_stack(), NULL, base);
|
||||
return tNUMBER;
|
||||
}
|
||||
|
||||
static void newline(void)
|
||||
{
|
||||
line_number++;
|
||||
char_number = 1;
|
||||
}
|
||||
|
||||
static int unisort(const void *p1, const void *p2)
|
||||
{
|
||||
return unistricmp(((token_t *)p1)->name, ((token_t *)p2)->name);
|
||||
}
|
||||
|
||||
static token_t *tokentable = NULL;
|
||||
static int ntokentable = 0;
|
||||
|
||||
token_t *lookup_token(const WCHAR *s)
|
||||
{
|
||||
token_t tok;
|
||||
|
||||
tok.name = s;
|
||||
return (token_t *)bsearch(&tok, tokentable, ntokentable, sizeof(*tokentable), unisort);
|
||||
}
|
||||
|
||||
void add_token(tok_e type, const WCHAR *name, int tok, int cp, const WCHAR *alias, int fix)
|
||||
{
|
||||
ntokentable++;
|
||||
tokentable = xrealloc(tokentable, ntokentable * sizeof(*tokentable));
|
||||
tokentable[ntokentable-1].type = type;
|
||||
tokentable[ntokentable-1].name = name;
|
||||
tokentable[ntokentable-1].token = tok;
|
||||
tokentable[ntokentable-1].codepage = cp;
|
||||
tokentable[ntokentable-1].alias = alias;
|
||||
tokentable[ntokentable-1].fixed = fix;
|
||||
qsort(tokentable, ntokentable, sizeof(*tokentable), unisort);
|
||||
}
|
||||
|
||||
void get_tokentable(token_t **tab, int *len)
|
||||
{
|
||||
assert(tab != NULL);
|
||||
assert(len != NULL);
|
||||
*tab = tokentable;
|
||||
*len = ntokentable;
|
||||
}
|
||||
|
||||
/*
|
||||
* The scanner
|
||||
*
|
||||
*/
|
||||
int yylex(void)
|
||||
{
|
||||
static WCHAR ustr_dot1[] = { '.', '\n', 0 };
|
||||
static WCHAR ustr_dot2[] = { '.', '\r', '\n', 0 };
|
||||
static int isinit = 0;
|
||||
int ch;
|
||||
|
||||
if(!isinit)
|
||||
{
|
||||
isinit++;
|
||||
set_codepage(WMC_DEFAULT_CODEPAGE);
|
||||
add_token(tok_keyword, ustr_codepages, tCODEPAGE, 0, NULL, 0);
|
||||
add_token(tok_keyword, ustr_facility, tFACILITY, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_facilitynames, tFACNAMES, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_language, tLANGUAGE, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_languagenames, tLANNAMES, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_messageid, tMSGID, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_messageidtypedef, tTYPEDEF, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_outputbase, tBASE, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_severity, tSEVERITY, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_severitynames, tSEVNAMES, 0, NULL, 1);
|
||||
add_token(tok_keyword, ustr_symbolicname, tSYMNAME, 0, NULL, 1);
|
||||
add_token(tok_severity, ustr_error, 0x03, 0, NULL, 0);
|
||||
add_token(tok_severity, ustr_warning, 0x02, 0, NULL, 0);
|
||||
add_token(tok_severity, ustr_informational, 0x01, 0, NULL, 0);
|
||||
add_token(tok_severity, ustr_success, 0x00, 0, NULL, 0);
|
||||
add_token(tok_facility, ustr_application, 0xFFF, 0, NULL, 0);
|
||||
add_token(tok_facility, ustr_system, 0x0FF, 0, NULL, 0);
|
||||
add_token(tok_language, ustr_english, 0x409, 437, ustr_msg00001, 0);
|
||||
}
|
||||
|
||||
empty_unichar_stack();
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(want_line)
|
||||
{
|
||||
while((ch = get_unichar()) != '\n')
|
||||
{
|
||||
if(ch == EOF)
|
||||
xyyerror("Unexpected EOF");
|
||||
push_unichar(ch);
|
||||
}
|
||||
newline();
|
||||
push_unichar(ch);
|
||||
push_unichar(0);
|
||||
if(!unistrcmp(ustr_dot1, get_unichar_stack()) || !unistrcmp(ustr_dot2, get_unichar_stack()))
|
||||
{
|
||||
want_line = 0;
|
||||
/* Reset the codepage to our default after each message */
|
||||
set_codepage(WMC_DEFAULT_CODEPAGE);
|
||||
return tMSGEND;
|
||||
}
|
||||
yylval.str = xunistrdup(get_unichar_stack());
|
||||
return tLINE;
|
||||
}
|
||||
|
||||
ch = get_unichar();
|
||||
|
||||
if(ch == EOF)
|
||||
return EOF;
|
||||
|
||||
if(ch == '\n')
|
||||
{
|
||||
newline();
|
||||
if(want_nl)
|
||||
{
|
||||
want_nl = 0;
|
||||
return tNL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(isisochar(ch))
|
||||
{
|
||||
if(want_file)
|
||||
{
|
||||
int n = 0;
|
||||
while(n < 8 && isisochar(ch))
|
||||
{
|
||||
int t = char_table[ch];
|
||||
if((t & CH_PUNCT) || !(t & CH_SHORTNAME))
|
||||
break;
|
||||
|
||||
push_unichar(ch);
|
||||
n++;
|
||||
ch = get_unichar();
|
||||
}
|
||||
unget_unichar(ch);
|
||||
push_unichar(0);
|
||||
want_file = 0;
|
||||
yylval.str = xunistrdup(get_unichar_stack());
|
||||
return tFILE;
|
||||
}
|
||||
|
||||
if(char_table[ch] & CH_IDENT)
|
||||
{
|
||||
token_t *tok;
|
||||
while(isisochar(ch) && (char_table[ch] & (CH_IDENT|CH_NUMBER)))
|
||||
{
|
||||
push_unichar(ch);
|
||||
ch = get_unichar();
|
||||
}
|
||||
unget_unichar(ch);
|
||||
push_unichar(0);
|
||||
if(!(tok = lookup_token(get_unichar_stack())))
|
||||
{
|
||||
yylval.str = xunistrdup(get_unichar_stack());
|
||||
return tIDENT;
|
||||
}
|
||||
switch(tok->type)
|
||||
{
|
||||
case tok_keyword:
|
||||
return tok->token;
|
||||
|
||||
case tok_language:
|
||||
codepage = tok->codepage;
|
||||
/* Fall through */
|
||||
case tok_severity:
|
||||
case tok_facility:
|
||||
yylval.tok = tok;
|
||||
return tTOKEN;
|
||||
|
||||
default:
|
||||
internal_error(__FILE__, __LINE__, "Invalid token type encountered");
|
||||
}
|
||||
}
|
||||
|
||||
if(isspace(ch)) /* Ignore space */
|
||||
continue;
|
||||
|
||||
if(isdigit(ch))
|
||||
return scan_number(ch);
|
||||
}
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case ':':
|
||||
case '=':
|
||||
case '+':
|
||||
case '(':
|
||||
case ')':
|
||||
return ch;
|
||||
case ';':
|
||||
while(ch != '\n' && ch != EOF)
|
||||
{
|
||||
push_unichar(ch);
|
||||
ch = get_unichar();
|
||||
}
|
||||
newline();
|
||||
push_unichar(ch); /* Include the newline */
|
||||
push_unichar(0);
|
||||
yylval.str = xunistrdup(get_unichar_stack());
|
||||
return tCOMMENT;
|
||||
default:
|
||||
xyyerror("Invalid character '%c' (0x%04x)", isisochar(ch) && isprint(ch) ? ch : '.', ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
* Wine Message Compiler parser
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
* The basic grammar of the file is yet another example of, humpf,
|
||||
* design. There is is mix of context-insensitive and -sentitive
|
||||
* stuff, which makes it rather complicated.
|
||||
* The header definitions are all context-insensitive because they have
|
||||
* delimited arguments, whereas the message headers are (semi-) context-
|
||||
* sensitive and the messages themselves are, well, RFC82[12] delimited.
|
||||
* This mixture seems to originate from the time that ms and ibm were
|
||||
* good friends and developing os/2 according to the "compatibility"
|
||||
* switch and reading some comments here and there.
|
||||
*
|
||||
* I'll ignore most of the complications and concentrate on the concept
|
||||
* which allows me to use yacc. Basically, everything is context-
|
||||
* insensitive now, with the exception of the message-text itself and
|
||||
* the preceding language declaration.
|
||||
*
|
||||
*/
|
||||
|
||||
%{
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "wmc.h"
|
||||
#include "lang.h"
|
||||
|
||||
static const char err_syntax[] = "Syntax error";
|
||||
static const char err_number[] = "Number expected";
|
||||
static const char err_ident[] = "Identifier expected";
|
||||
static const char err_assign[] = "'=' expected";
|
||||
static const char err_popen[] = "'(' expected";
|
||||
static const char err_pclose[] = "')' expected";
|
||||
static const char err_colon[] = "':' expected";
|
||||
static const char err_msg[] = "Message expected";
|
||||
|
||||
/* Scanner switches */
|
||||
int want_nl = 0; /* Request next newlinw */
|
||||
int want_line = 0; /* Request next complete line */
|
||||
int want_file = 0; /* Request next ident as filename */
|
||||
|
||||
node_t *nodehead = NULL; /* The list of all parsed elements */
|
||||
static node_t *nodetail = NULL;
|
||||
lan_blk_t *lanblockhead; /* List of parsed elements transposed */
|
||||
|
||||
static int base = 16; /* Current printout base to use (8, 10 or 16) */
|
||||
static WCHAR *cast = NULL; /* Current typecast to use */
|
||||
|
||||
static int last_id = 0; /* The last message ID parsed */
|
||||
static int last_sev = 0; /* Last severity code parsed */
|
||||
static int last_fac = 0; /* Last facility code parsed */
|
||||
static WCHAR *last_sym = NULL;/* Last alias symbol parsed */
|
||||
static int have_sev; /* Set if severity parsed for current message */
|
||||
static int have_fac; /* Set if facility parsed for current message */
|
||||
static int have_sym; /* Set is symbol parsed for current message */
|
||||
|
||||
static cp_xlat_t *cpxlattab = NULL; /* Codepage translation table */
|
||||
static int ncpxlattab = 0;
|
||||
|
||||
/* Prototypes */
|
||||
static WCHAR *merge(WCHAR *s1, WCHAR *s2);
|
||||
static lanmsg_t *new_lanmsg(lan_cp_t *lcp, WCHAR *msg);
|
||||
static msg_t *add_lanmsg(msg_t *msg, lanmsg_t *lanmsg);
|
||||
static msg_t *complete_msg(msg_t *msg, int id);
|
||||
static void add_node(node_e type, void *p);
|
||||
static void do_add_token(tok_e type, token_t *tok, const char *code);
|
||||
static void test_id(int id);
|
||||
static int check_languages(node_t *head);
|
||||
static lan_blk_t *block_messages(node_t *head);
|
||||
static void add_cpxlat(int lan, int cpin, int cpout);
|
||||
cp_xlat_t *find_cpxlat(int lan);
|
||||
|
||||
%}
|
||||
|
||||
|
||||
%union {
|
||||
WCHAR *str;
|
||||
unsigned num;
|
||||
token_t *tok;
|
||||
lanmsg_t *lmp;
|
||||
msg_t *msg;
|
||||
lan_cp_t lcp;
|
||||
}
|
||||
|
||||
|
||||
%token tSEVNAMES tFACNAMES tLANNAMES tBASE tCODEPAGE
|
||||
%token tTYPEDEF tNL tSYMNAME tMSGEND
|
||||
%token tSEVERITY tFACILITY tLANGUAGE tMSGID
|
||||
%token <str> tIDENT tLINE tFILE tCOMMENT
|
||||
%token <num> tNUMBER
|
||||
%token <tok> tTOKEN
|
||||
|
||||
%type <str> alias lines
|
||||
%type <num> optcp id msgid clan
|
||||
%type <tok> token
|
||||
%type <lmp> body
|
||||
%type <msg> bodies msg
|
||||
%type <lcp> lang
|
||||
|
||||
%%
|
||||
file : items {
|
||||
if(!check_languages(nodehead))
|
||||
xyyerror("No messages defined");
|
||||
lanblockhead = block_messages(nodehead);
|
||||
}
|
||||
;
|
||||
|
||||
items : decl
|
||||
| items decl
|
||||
;
|
||||
|
||||
decl : global
|
||||
| msg { add_node(nd_msg, $1); }
|
||||
| tCOMMENT { add_node(nd_comment, $1); }
|
||||
| error { xyyerror(err_syntax); /* `Catch all' error */ }
|
||||
;
|
||||
|
||||
global : tSEVNAMES '=' '(' smaps ')'
|
||||
| tSEVNAMES '=' '(' smaps error { xyyerror(err_pclose); }
|
||||
| tSEVNAMES '=' error { xyyerror(err_popen); }
|
||||
| tSEVNAMES error { xyyerror(err_assign); }
|
||||
| tFACNAMES '=' '(' fmaps ')'
|
||||
| tFACNAMES '=' '(' fmaps error { xyyerror(err_pclose); }
|
||||
| tFACNAMES '=' error { xyyerror(err_popen); }
|
||||
| tFACNAMES error { xyyerror(err_assign); }
|
||||
| tLANNAMES '=' '(' lmaps ')'
|
||||
| tLANNAMES '=' '(' lmaps error { xyyerror(err_pclose); }
|
||||
| tLANNAMES '=' error { xyyerror(err_popen); }
|
||||
| tLANNAMES error { xyyerror(err_assign); }
|
||||
| tCODEPAGE '=' '(' cmaps ')'
|
||||
| tCODEPAGE '=' '(' cmaps error { xyyerror(err_pclose); }
|
||||
| tCODEPAGE '=' error { xyyerror(err_popen); }
|
||||
| tCODEPAGE error { xyyerror(err_assign); }
|
||||
| tTYPEDEF '=' tIDENT { cast = $3; }
|
||||
| tTYPEDEF '=' error { xyyerror(err_number); }
|
||||
| tTYPEDEF error { xyyerror(err_assign); }
|
||||
| tBASE '=' tNUMBER {
|
||||
switch(base)
|
||||
{
|
||||
case 8:
|
||||
case 10:
|
||||
case 16:
|
||||
base = $3;
|
||||
break;
|
||||
default:
|
||||
xyyerror("Numberbase must be 8, 10 or 16");
|
||||
}
|
||||
}
|
||||
| tBASE '=' error { xyyerror(err_number); }
|
||||
| tBASE error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* SeverityNames mapping
|
||||
*/
|
||||
smaps : smap
|
||||
| smaps smap
|
||||
| error { xyyerror(err_ident); }
|
||||
;
|
||||
|
||||
smap : token '=' tNUMBER alias {
|
||||
$1->token = $3;
|
||||
$1->alias = $4;
|
||||
if($3 & (~0x3))
|
||||
xyyerror("Severity value out of range (0x%08x > 0x3)", $3);
|
||||
do_add_token(tok_severity, $1, "severity");
|
||||
}
|
||||
| token '=' error { xyyerror(err_number); }
|
||||
| token error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* FacilityNames mapping
|
||||
*/
|
||||
fmaps : fmap
|
||||
| fmaps fmap
|
||||
| error { xyyerror(err_ident); }
|
||||
;
|
||||
|
||||
fmap : token '=' tNUMBER alias {
|
||||
$1->token = $3;
|
||||
$1->alias = $4;
|
||||
if($3 & (~0xfff))
|
||||
xyyerror("Facility value out of range (0x%08x > 0xfff)", $3);
|
||||
do_add_token(tok_facility, $1, "facility");
|
||||
}
|
||||
| token '=' error { xyyerror(err_number); }
|
||||
| token error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
alias : /* Empty */ { $$ = NULL; }
|
||||
| ':' tIDENT { $$ = $2; }
|
||||
| ':' error { xyyerror(err_ident); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* LanguageNames mapping
|
||||
*/
|
||||
lmaps : lmap
|
||||
| lmaps lmap
|
||||
| error { xyyerror(err_ident); }
|
||||
;
|
||||
|
||||
lmap : token '=' tNUMBER setfile ':' tFILE optcp {
|
||||
$1->token = $3;
|
||||
$1->alias = $6;
|
||||
$1->codepage = $7;
|
||||
do_add_token(tok_language, $1, "language");
|
||||
if(!find_language($1->token) && !find_cpxlat($1->token))
|
||||
yywarning("Language 0x%x not built-in, using codepage %d; use explicit codepage to override", $1->token, WMC_DEFAULT_CODEPAGE);
|
||||
}
|
||||
| token '=' tNUMBER setfile ':' error { xyyerror("Filename expected"); }
|
||||
| token '=' tNUMBER error { xyyerror(err_colon); }
|
||||
| token '=' error { xyyerror(err_number); }
|
||||
| token error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
optcp : /* Empty */ { $$ = 0; }
|
||||
| ':' tNUMBER { $$ = $2; }
|
||||
| ':' error { xyyerror("Codepage-number expected"); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Codepages mapping
|
||||
*/
|
||||
cmaps : cmap
|
||||
| cmaps cmap
|
||||
| error { xyyerror(err_ident); }
|
||||
;
|
||||
|
||||
cmap : clan '=' tNUMBER ':' tNUMBER {
|
||||
static const char err_nocp[] = "Codepage %d not builtin; cannot convert";
|
||||
if(find_cpxlat($1))
|
||||
xyyerror("Codepage translation already defined for language 0x%x", $1);
|
||||
if($3 && !find_codepage($3))
|
||||
xyyerror(err_nocp, $3);
|
||||
if($5 && !find_codepage($5))
|
||||
xyyerror(err_nocp, $5);
|
||||
add_cpxlat($1, $3, $5);
|
||||
}
|
||||
| clan '=' tNUMBER ':' error { xyyerror(err_number); }
|
||||
| clan '=' tNUMBER error { xyyerror(err_colon); }
|
||||
| clan '=' error { xyyerror(err_number); }
|
||||
| clan error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
clan : tNUMBER { $$ = $1; }
|
||||
| tTOKEN {
|
||||
if($1->type != tok_language)
|
||||
xyyerror("Language name or code expected");
|
||||
$$ = $1->token;
|
||||
}
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Message-definition parsing
|
||||
*/
|
||||
msg : msgid sevfacsym { test_id($1); } bodies { $$ = complete_msg($4, $1); }
|
||||
;
|
||||
|
||||
msgid : tMSGID '=' id {
|
||||
if($3 & (~0xffff))
|
||||
xyyerror("Message ID value out of range (0x%08x > 0xffff)", $3);
|
||||
$$ = $3;
|
||||
}
|
||||
| tMSGID error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
id : /* Empty */ { $$ = ++last_id; }
|
||||
| tNUMBER { $$ = last_id = $1; }
|
||||
| '+' tNUMBER { $$ = last_id += $2; }
|
||||
| '+' error { xyyerror(err_number); }
|
||||
;
|
||||
|
||||
sevfacsym: /* Empty */ { have_sev = have_fac = have_sym = 0; }
|
||||
| sevfacsym sev { if(have_sev) xyyerror("Severity already defined"); have_sev = 1; }
|
||||
| sevfacsym fac { if(have_fac) xyyerror("Facility already defined"); have_fac = 1; }
|
||||
| sevfacsym sym { if(have_sym) xyyerror("Symbolname already defined"); have_sym = 1; }
|
||||
;
|
||||
|
||||
sym : tSYMNAME '=' tIDENT { last_sym = $3; }
|
||||
| tSYMNAME '=' error { xyyerror(err_ident); }
|
||||
| tSYMNAME error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
sev : tSEVERITY '=' token {
|
||||
token_t *tok = lookup_token($3->name);
|
||||
if(!tok)
|
||||
xyyerror("Undefined severityname");
|
||||
if(tok->type != tok_severity)
|
||||
xyyerror("Identifier is not of class 'severity'");
|
||||
last_sev = tok->token;
|
||||
}
|
||||
| tSEVERITY '=' error { xyyerror(err_ident); }
|
||||
| tSEVERITY error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
fac : tFACILITY '=' token {
|
||||
token_t *tok = lookup_token($3->name);
|
||||
if(!tok)
|
||||
xyyerror("Undefined facilityname");
|
||||
if(tok->type != tok_facility)
|
||||
xyyerror("Identifier is not of class 'facility'");
|
||||
last_fac = tok->token;
|
||||
}
|
||||
| tFACILITY '=' error { xyyerror(err_ident); }
|
||||
| tFACILITY error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Message-text parsing
|
||||
*/
|
||||
bodies : body { $$ = add_lanmsg(NULL, $1); }
|
||||
| bodies body { $$ = add_lanmsg($1, $2); }
|
||||
| error { xyyerror("'Language=...' (start of message text-definition) expected"); }
|
||||
;
|
||||
|
||||
body : lang setline lines tMSGEND { $$ = new_lanmsg(&$1, $3); }
|
||||
;
|
||||
|
||||
/*
|
||||
* The newline is to be able to set the codepage
|
||||
* to the language based codepage for the next
|
||||
* message to be parsed.
|
||||
*/
|
||||
lang : tLANGUAGE setnl '=' token tNL {
|
||||
token_t *tok = lookup_token($4->name);
|
||||
cp_xlat_t *cpx;
|
||||
if(!tok)
|
||||
xyyerror("Undefined language");
|
||||
if(tok->type != tok_language)
|
||||
xyyerror("Identifier is not of class 'language'");
|
||||
if((cpx = find_cpxlat(tok->token)))
|
||||
{
|
||||
set_codepage($$.codepage = cpx->cpin);
|
||||
}
|
||||
else if(!tok->codepage)
|
||||
{
|
||||
const language_t *lan = find_language(tok->token);
|
||||
if(!lan)
|
||||
{
|
||||
/* Just set default; warning was given while parsing languagenames */
|
||||
set_codepage($$.codepage = WMC_DEFAULT_CODEPAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The default seems to be to use the DOS codepage... */
|
||||
set_codepage($$.codepage = lan->doscp);
|
||||
}
|
||||
}
|
||||
else
|
||||
set_codepage($$.codepage = tok->codepage);
|
||||
$$.language = tok->token;
|
||||
}
|
||||
| tLANGUAGE setnl '=' token error { xyyerror("Missing newline"); }
|
||||
| tLANGUAGE setnl '=' error { xyyerror(err_ident); }
|
||||
| tLANGUAGE error { xyyerror(err_assign); }
|
||||
;
|
||||
|
||||
lines : tLINE { $$ = $1; }
|
||||
| lines tLINE { $$ = merge($1, $2); }
|
||||
| error { xyyerror(err_msg); }
|
||||
| lines error { xyyerror(err_msg); }
|
||||
;
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Helper rules
|
||||
*/
|
||||
token : tIDENT { $$ = xmalloc(sizeof(token_t)); $$->name = $1; }
|
||||
| tTOKEN { $$ = $1; }
|
||||
;
|
||||
|
||||
setnl : /* Empty */ { want_nl = 1; }
|
||||
;
|
||||
|
||||
setline : /* Empty */ { want_line = 1; }
|
||||
;
|
||||
|
||||
setfile : /* Empty */ { want_file = 1; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
static WCHAR *merge(WCHAR *s1, WCHAR *s2)
|
||||
{
|
||||
int l1 = unistrlen(s1);
|
||||
int l2 = unistrlen(s2);
|
||||
s1 = xrealloc(s1, (l1 + l2 + 1) * sizeof(*s1));
|
||||
unistrcpy(s1+l1, s2);
|
||||
free(s2);
|
||||
return s1;
|
||||
}
|
||||
|
||||
static void do_add_token(tok_e type, token_t *tok, const char *code)
|
||||
{
|
||||
token_t *tp = lookup_token(tok->name);
|
||||
if(tp)
|
||||
{
|
||||
if(tok->type != type)
|
||||
yywarning("Type change in token");
|
||||
if(tp != tok)
|
||||
xyyerror("Overlapping token not the same");
|
||||
/* else its already defined and changed */
|
||||
if(tok->fixed)
|
||||
xyyerror("Redefinition of %s", code);
|
||||
tok->fixed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
add_token(type, tok->name, tok->token, tok->codepage, tok->alias, 1);
|
||||
free(tok);
|
||||
}
|
||||
}
|
||||
|
||||
static lanmsg_t *new_lanmsg(lan_cp_t *lcp, WCHAR *msg)
|
||||
{
|
||||
lanmsg_t *lmp = (lanmsg_t *)xmalloc(sizeof(lanmsg_t));
|
||||
lmp->lan = lcp->language;
|
||||
lmp->cp = lcp->codepage;
|
||||
lmp->msg = msg;
|
||||
lmp->len = unistrlen(msg) + 1; /* Include termination */
|
||||
if(lmp->len > 4096)
|
||||
yywarning("Message exceptionally long; might be a missing termination");
|
||||
return lmp;
|
||||
}
|
||||
|
||||
static msg_t *add_lanmsg(msg_t *msg, lanmsg_t *lanmsg)
|
||||
{
|
||||
int i;
|
||||
if(!msg)
|
||||
msg = xmalloc(sizeof(msg_t));
|
||||
msg->msgs = xrealloc(msg->msgs, (msg->nmsgs+1) * sizeof(*(msg->msgs)));
|
||||
msg->msgs[msg->nmsgs] = lanmsg;
|
||||
msg->nmsgs++;
|
||||
for(i = 0; i < msg->nmsgs-1; i++)
|
||||
{
|
||||
if(msg->msgs[i]->lan == lanmsg->lan)
|
||||
xyyerror("Message for language 0x%x already defined", lanmsg->lan);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int sort_lanmsg(const void *p1, const void *p2)
|
||||
{
|
||||
return (*(lanmsg_t **)p1)->lan - (*(lanmsg_t **)p2)->lan;
|
||||
}
|
||||
|
||||
static msg_t *complete_msg(msg_t *mp, int id)
|
||||
{
|
||||
assert(mp != NULL);
|
||||
mp->id = id;
|
||||
if(have_sym)
|
||||
mp->sym = last_sym;
|
||||
else
|
||||
xyyerror("No symbolic name defined for message id %d", id);
|
||||
mp->sev = last_sev;
|
||||
mp->fac = last_fac;
|
||||
qsort(mp->msgs, mp->nmsgs, sizeof(*(mp->msgs)), sort_lanmsg);
|
||||
mp->realid = id | (last_sev << 30) | (last_fac << 16);
|
||||
if(custombit)
|
||||
mp->realid |= 1 << 29;
|
||||
mp->base = base;
|
||||
mp->cast = cast;
|
||||
return mp;
|
||||
}
|
||||
|
||||
static void add_node(node_e type, void *p)
|
||||
{
|
||||
node_t *ndp = (node_t *)xmalloc(sizeof(node_t));
|
||||
ndp->type = type;
|
||||
ndp->u.all = p;
|
||||
|
||||
if(nodetail)
|
||||
{
|
||||
ndp->prev = nodetail;
|
||||
nodetail->next = ndp;
|
||||
nodetail = ndp;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodehead = nodetail = ndp;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_id(int id)
|
||||
{
|
||||
node_t *ndp;
|
||||
for(ndp = nodehead; ndp; ndp = ndp->next)
|
||||
{
|
||||
if(ndp->type != nd_msg)
|
||||
continue;
|
||||
if(ndp->u.msg->id == id && ndp->u.msg->sev == last_sev && ndp->u.msg->fac == last_fac)
|
||||
xyyerror("MessageId %d with facility 0x%x and severity 0x%x already defined", id, last_fac, last_sev);
|
||||
}
|
||||
}
|
||||
|
||||
static int check_languages(node_t *head)
|
||||
{
|
||||
static char err_missing[] = "Missing definition for language 0x%x; MessageID %d, facility 0x%x, severity 0x%x";
|
||||
node_t *ndp;
|
||||
int nm = 0;
|
||||
msg_t *msg = NULL;
|
||||
|
||||
for(ndp = head; ndp; ndp = ndp->next)
|
||||
{
|
||||
if(ndp->type != nd_msg)
|
||||
continue;
|
||||
if(!nm)
|
||||
{
|
||||
msg = ndp->u.msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
msg_t *m1;
|
||||
msg_t *m2;
|
||||
if(ndp->u.msg->nmsgs > msg->nmsgs)
|
||||
{
|
||||
m1 = ndp->u.msg;
|
||||
m2 = msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
m1 = msg;
|
||||
m2 = ndp->u.msg;
|
||||
}
|
||||
|
||||
for(i = 0; i < m1->nmsgs; i++)
|
||||
{
|
||||
if(i > m2->nmsgs)
|
||||
error(err_missing, m1->msgs[i]->lan, m2->id, m2->fac, m2->sev);
|
||||
else if(m1->msgs[i]->lan < m2->msgs[i]->lan)
|
||||
error(err_missing, m1->msgs[i]->lan, m2->id, m2->fac, m2->sev);
|
||||
else if(m1->msgs[i]->lan > m2->msgs[i]->lan)
|
||||
error(err_missing, m2->msgs[i]->lan, m1->id, m1->fac, m1->sev);
|
||||
}
|
||||
}
|
||||
nm++;
|
||||
}
|
||||
return nm;
|
||||
}
|
||||
|
||||
#define MSGRID(x) ((*(msg_t **)(x))->realid)
|
||||
static int sort_msg(const void *p1, const void *p2)
|
||||
{
|
||||
return MSGRID(p1) > MSGRID(p2) ? 1 : (MSGRID(p1) == MSGRID(p2) ? 0 : -1);
|
||||
/* return (*(msg_t **)p1)->realid - (*(msg_t **)p1)->realid; */
|
||||
}
|
||||
|
||||
/*
|
||||
* block_messages() basically transposes the messages
|
||||
* from ID/language based list to a language/ID
|
||||
* based list.
|
||||
*/
|
||||
static lan_blk_t *block_messages(node_t *head)
|
||||
{
|
||||
lan_blk_t *lbp;
|
||||
lan_blk_t *lblktail = NULL;
|
||||
lan_blk_t *lblkhead = NULL;
|
||||
msg_t **msgtab = NULL;
|
||||
node_t *ndp;
|
||||
int nmsg = 0;
|
||||
int i;
|
||||
int nl;
|
||||
int factor = unicodeout ? 2 : 1;
|
||||
|
||||
for(ndp = head; ndp; ndp = ndp->next)
|
||||
{
|
||||
if(ndp->type != nd_msg)
|
||||
continue;
|
||||
msgtab = xrealloc(msgtab, (nmsg+1) * sizeof(*msgtab));
|
||||
msgtab[nmsg++] = ndp->u.msg;
|
||||
}
|
||||
|
||||
assert(nmsg != 0);
|
||||
qsort(msgtab, nmsg, sizeof(*msgtab), sort_msg);
|
||||
|
||||
for(nl = 0; nl < msgtab[0]->nmsgs; nl++) /* This should be equal for all after check_languages() */
|
||||
{
|
||||
lbp = xmalloc(sizeof(lan_blk_t));
|
||||
|
||||
if(!lblktail)
|
||||
{
|
||||
lblkhead = lblktail = lbp;
|
||||
}
|
||||
else
|
||||
{
|
||||
lblktail->next = lbp;
|
||||
lbp->prev = lblktail;
|
||||
lblktail = lbp;
|
||||
}
|
||||
lbp->nblk = 1;
|
||||
lbp->blks = xmalloc(sizeof(*lbp->blks));
|
||||
lbp->blks[0].idlo = msgtab[0]->realid;
|
||||
lbp->blks[0].idhi = msgtab[0]->realid;
|
||||
/* The plus 4 is the entry header; (+3)&~3 is DWORD alignment */
|
||||
lbp->blks[0].size = ((factor * msgtab[0]->msgs[nl]->len + 3) & ~3) + 4;
|
||||
lbp->blks[0].msgs = xmalloc(sizeof(*lbp->blks[0].msgs));
|
||||
lbp->blks[0].nmsg = 1;
|
||||
lbp->blks[0].msgs[0] = msgtab[0]->msgs[nl];
|
||||
lbp->lan = msgtab[0]->msgs[nl]->lan;
|
||||
|
||||
for(i = 1; i < nmsg; i++)
|
||||
{
|
||||
block_t *blk = &(lbp->blks[lbp->nblk-1]);
|
||||
if(msgtab[i]->realid == blk->idhi+1)
|
||||
{
|
||||
blk->size += ((factor * msgtab[i]->msgs[nl]->len + 3) & ~3) + 4;
|
||||
blk->idhi++;
|
||||
blk->msgs = xrealloc(blk->msgs, (blk->nmsg+1) * sizeof(*blk->msgs));
|
||||
blk->msgs[blk->nmsg++] = msgtab[i]->msgs[nl];
|
||||
}
|
||||
else
|
||||
{
|
||||
lbp->nblk++;
|
||||
lbp->blks = xrealloc(lbp->blks, lbp->nblk * sizeof(*lbp->blks));
|
||||
blk = &(lbp->blks[lbp->nblk-1]);
|
||||
blk->idlo = msgtab[i]->realid;
|
||||
blk->idhi = msgtab[i]->realid;
|
||||
blk->size = ((factor * msgtab[i]->msgs[nl]->len + 3) & ~3) + 4;
|
||||
blk->msgs = xmalloc(sizeof(*blk->msgs));
|
||||
blk->nmsg = 1;
|
||||
blk->msgs[0] = msgtab[i]->msgs[nl];
|
||||
}
|
||||
}
|
||||
}
|
||||
free(msgtab);
|
||||
return lblkhead;
|
||||
}
|
||||
|
||||
static int sc_xlat(const void *p1, const void *p2)
|
||||
{
|
||||
return ((cp_xlat_t *)p1)->lan - ((cp_xlat_t *)p2)->lan;
|
||||
}
|
||||
|
||||
static void add_cpxlat(int lan, int cpin, int cpout)
|
||||
{
|
||||
cpxlattab = xrealloc(cpxlattab, (ncpxlattab+1) * sizeof(*cpxlattab));
|
||||
cpxlattab[ncpxlattab].lan = lan;
|
||||
cpxlattab[ncpxlattab].cpin = cpin;
|
||||
cpxlattab[ncpxlattab].cpout = cpout;
|
||||
ncpxlattab++;
|
||||
qsort(cpxlattab, ncpxlattab, sizeof(*cpxlattab), sc_xlat);
|
||||
}
|
||||
|
||||
cp_xlat_t *find_cpxlat(int lan)
|
||||
{
|
||||
cp_xlat_t t;
|
||||
t.lan = lan;
|
||||
return (cp_xlat_t *)bsearch(&t, cpxlattab, ncpxlattab, sizeof(*cpxlattab), sc_xlat);
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Utility routines
|
||||
*
|
||||
* Copyright 1998,2000 Bertho A. Stultiens
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "wmctypes.h"
|
||||
#include "utils.h"
|
||||
#include "wmc.h"
|
||||
|
||||
#define SUPPRESS_YACC_ERROR_MESSAGE
|
||||
|
||||
static void generic_msg(const char *s, const char *t, va_list ap)
|
||||
{
|
||||
fprintf(stderr, "%s %s: %d, %d: ", t, input_name ? input_name : "stdin", line_number, char_number);
|
||||
vfprintf(stderr, s, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The yyerror routine should not exit because we use the error-token
|
||||
* to determine the syntactic error in the source. However, YACC
|
||||
* uses the same routine to print an error just before the error
|
||||
* token is reduced.
|
||||
* The extra routine 'xyyerror' is used to exit after giving a real
|
||||
* message.
|
||||
*/
|
||||
int yyerror(const char *s, ...)
|
||||
{
|
||||
#ifndef SUPPRESS_YACC_ERROR_MESSAGE
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
generic_msg(s, "Yacc error", ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xyyerror(const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
generic_msg(s, "Error", ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yywarning(const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
generic_msg(s, "Warning", ap);
|
||||
va_end(ap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void internal_error(const char *file, int line, const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
|
||||
vfprintf(stderr, s, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
void error(const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
fprintf(stderr, "Error: ");
|
||||
vfprintf(stderr, s, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
void warning(const char *s, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
fprintf(stderr, "Warning: ");
|
||||
vfprintf(stderr, s, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
char *dup_basename(const char *name, const char *ext)
|
||||
{
|
||||
int namelen;
|
||||
int extlen = strlen(ext);
|
||||
char *base;
|
||||
char *slash;
|
||||
|
||||
if(!name)
|
||||
name = "wmc.tab";
|
||||
|
||||
slash = strrchr(name, '/');
|
||||
if (slash)
|
||||
name = slash + 1;
|
||||
|
||||
namelen = strlen(name);
|
||||
|
||||
/* +4 for later extension and +1 for '\0' */
|
||||
base = (char *)xmalloc(namelen +4 +1);
|
||||
strcpy(base, name);
|
||||
if(!strcasecmp(name + namelen-extlen, ext))
|
||||
{
|
||||
base[namelen - extlen] = '\0';
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void *res;
|
||||
|
||||
assert(size > 0);
|
||||
assert(size < 102400);
|
||||
res = malloc(size);
|
||||
if(res == NULL)
|
||||
{
|
||||
error("Virtual memory exhausted.\n");
|
||||
}
|
||||
/*
|
||||
* We set it to 0.
|
||||
* This is *paramount* because we depend on it
|
||||
* just about everywhere in the rest of the code.
|
||||
*/
|
||||
memset(res, 0, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void *xrealloc(void *p, size_t size)
|
||||
{
|
||||
void *res;
|
||||
|
||||
assert(size > 0);
|
||||
assert(size < 102400);
|
||||
res = realloc(p, size);
|
||||
if(res == NULL)
|
||||
{
|
||||
error("Virtual memory exhausted.\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
char *xstrdup(const char *str)
|
||||
{
|
||||
char *s;
|
||||
|
||||
assert(str != NULL);
|
||||
s = (char *)xmalloc(strlen(str)+1);
|
||||
return strcpy(s, str);
|
||||
}
|
||||
|
||||
int unistrlen(const WCHAR *s)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; *s; n++, s++)
|
||||
;
|
||||
return n;
|
||||
}
|
||||
|
||||
WCHAR *unistrcpy(WCHAR *dst, const WCHAR *src)
|
||||
{
|
||||
WCHAR *t = dst;
|
||||
while(*src)
|
||||
*t++ = *src++;
|
||||
*t = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
WCHAR *xunistrdup(const WCHAR * str)
|
||||
{
|
||||
WCHAR *s;
|
||||
|
||||
assert(str != NULL);
|
||||
s = (WCHAR *)xmalloc((unistrlen(str)+1) * sizeof(WCHAR));
|
||||
return unistrcpy(s, str);
|
||||
}
|
||||
|
||||
int unistricmp(const WCHAR *s1, const WCHAR *s2)
|
||||
{
|
||||
int i;
|
||||
int once = 0;
|
||||
static char warn[] = "Don't know the uppercase equivalent of non acsii characters;"
|
||||
"comparison might yield wrong results";
|
||||
while(*s1 && *s2)
|
||||
{
|
||||
if((*s1 & 0xffff) > 0x7f || (*s2 & 0xffff) > 0x7f)
|
||||
{
|
||||
if(!once)
|
||||
{
|
||||
once++;
|
||||
yywarning(warn);
|
||||
}
|
||||
i = *s1++ - *s2++;
|
||||
}
|
||||
else
|
||||
i = toupper(*s1++) - toupper(*s2++);
|
||||
if(i)
|
||||
return i;
|
||||
}
|
||||
|
||||
if((*s1 & 0xffff) > 0x7f || (*s2 & 0xffff) > 0x7f)
|
||||
{
|
||||
if(!once)
|
||||
yywarning(warn);
|
||||
return *s1 - *s2;
|
||||
}
|
||||
else
|
||||
return toupper(*s1) - toupper(*s2);
|
||||
}
|
||||
|
||||
int unistrcmp(const WCHAR *s1, const WCHAR *s2)
|
||||
{
|
||||
int i;
|
||||
while(*s1 && *s2)
|
||||
{
|
||||
i = *s1++ - *s2++;
|
||||
if(i)
|
||||
return i;
|
||||
}
|
||||
|
||||
return *s1 - *s2;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Utility routines' prototypes etc.
|
||||
*
|
||||
* Copyright 1998,2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WMC_UTILS_H
|
||||
#define __WMC_UTILS_H
|
||||
|
||||
#ifndef __WMC_WMCTYPES_H
|
||||
#include "wmctypes.h"
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
void *xmalloc(size_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
char *xstrdup(const char *str);
|
||||
|
||||
int yyerror(const char *s, ...) __attribute__((format (printf, 1, 2)));
|
||||
int xyyerror(const char *s, ...) __attribute__((format (printf, 1, 2)));
|
||||
int yywarning(const char *s, ...) __attribute__((format (printf, 1, 2)));
|
||||
void internal_error(const char *file, int line, const char *s, ...) __attribute__((format (printf, 3, 4)));
|
||||
void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
|
||||
void warning(const char *s, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
char *dup_basename(const char *name, const char *ext);
|
||||
|
||||
WCHAR *xunistrdup(const WCHAR * str);
|
||||
WCHAR *unistrcpy(WCHAR *dst, const WCHAR *src);
|
||||
int unistrlen(const WCHAR *s);
|
||||
int unistricmp(const WCHAR *s1, const WCHAR *s2);
|
||||
int unistrcmp(const WCHAR *s1, const WCHAR *s2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Wine Message Compiler main program
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "wmc.h"
|
||||
#include "utils.h"
|
||||
#include "lang.h"
|
||||
#include "write.h"
|
||||
|
||||
static char usage[] =
|
||||
"Usage: wmc [options...] [inputfile.mc]\n"
|
||||
" -B x Set output byte-order x={n[ative], l[ittle], b[ig]}\n"
|
||||
" (default is n[ative] which equals "
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
"big"
|
||||
#else
|
||||
"little"
|
||||
#endif
|
||||
"-endian)\n"
|
||||
" -c Set 'custom-bit' in values\n"
|
||||
" -d Use decimal values in output\n"
|
||||
" -D Set debug flag\n"
|
||||
" -h This message\n"
|
||||
" -H file Write headerfile to file (default is inputfile.h)\n"
|
||||
" -i Inline messagetable(s)\n"
|
||||
" -o file Output to file (default is inputfile.rc)\n"
|
||||
" -u Inputfile is in unicode\n"
|
||||
" -U Output unicode messagetable(s)\n"
|
||||
" -v Show supported codepages and languages\n"
|
||||
" -V Print version end exit\n"
|
||||
" -W Enable pedantic warnings\n"
|
||||
"Input is taken from stdin if no inputfile is specified.\n"
|
||||
"Byteorder of unicode input is based upon the first couple of\n"
|
||||
"bytes read, which should be 0x0000..0x00ff.\n"
|
||||
;
|
||||
|
||||
static char version_string[] =
|
||||
"Wine Message Compiler Version " WMC_FULLVERSION "\n"
|
||||
"Copyright 2000 Bertho A. Stultiens\n"
|
||||
;
|
||||
|
||||
/*
|
||||
* The output byte-order of resources (set with -B)
|
||||
*/
|
||||
int byteorder = WMC_BO_NATIVE;
|
||||
|
||||
/*
|
||||
* Custom bit (bit 29) in output values must be set (-c option)
|
||||
*/
|
||||
int custombit = 0;
|
||||
|
||||
/*
|
||||
* Output decimal values (-d option)
|
||||
*/
|
||||
int decimal = 0;
|
||||
|
||||
/*
|
||||
* Enable pedantic warnings; check arg references (-W option)
|
||||
*/
|
||||
int pedantic = 0;
|
||||
|
||||
/*
|
||||
* Unicode input (-u option)
|
||||
*/
|
||||
int unicodein = 0;
|
||||
|
||||
/*
|
||||
* Unicode output (-U option)
|
||||
*/
|
||||
int unicodeout = 0;
|
||||
|
||||
/*
|
||||
* Inline the messagetables (don't write *.bin files; -i option)
|
||||
*/
|
||||
int rcinline = 0;
|
||||
|
||||
/*
|
||||
* Debugging flag (-D option)
|
||||
*/
|
||||
int dodebug = 0;
|
||||
|
||||
char *output_name = NULL; /* The name given by the -o option */
|
||||
char *input_name = NULL; /* The name given on the command-line */
|
||||
char *header_name = NULL; /* The name given by the -H option */
|
||||
|
||||
int line_number = 1; /* The current line */
|
||||
int char_number = 1; /* The current char pos within the line */
|
||||
|
||||
char *cmdline; /* The entire commandline */
|
||||
time_t now; /* The time of start of wmc */
|
||||
|
||||
int getopt (int argc, char *const *argv, const char *optstring);
|
||||
static void segvhandler(int sig);
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern char* optarg;
|
||||
extern int optind;
|
||||
int optc;
|
||||
int lose = 0;
|
||||
int ret;
|
||||
int i;
|
||||
int cmdlen;
|
||||
|
||||
signal(SIGSEGV, segvhandler);
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
/* First rebuild the commandline to put in destination */
|
||||
/* Could be done through env[], but not all OS-es support it */
|
||||
cmdlen = 4; /* for "wmc " */
|
||||
for(i = 1; i < argc; i++)
|
||||
cmdlen += strlen(argv[i]) + 1;
|
||||
cmdline = (char *)xmalloc(cmdlen);
|
||||
strcpy(cmdline, "wmc ");
|
||||
for(i = 1; i < argc; i++)
|
||||
{
|
||||
strcat(cmdline, argv[i]);
|
||||
if(i < argc-1)
|
||||
strcat(cmdline, " ");
|
||||
}
|
||||
|
||||
while((optc = getopt(argc, argv, "B:cdDhH:io:p:uUvVW")) != EOF)
|
||||
{
|
||||
switch(optc)
|
||||
{
|
||||
case 'B':
|
||||
switch(optarg[0])
|
||||
{
|
||||
case 'n':
|
||||
case 'N':
|
||||
byteorder = WMC_BO_NATIVE;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
byteorder = WMC_BO_LITTLE;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
byteorder = WMC_BO_BIG;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Byteordering must be n[ative], l[ittle] or b[ig]\n");
|
||||
lose++;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
custombit = 1;
|
||||
break;
|
||||
case 'd':
|
||||
decimal = 1;
|
||||
break;
|
||||
case 'D':
|
||||
dodebug = 1;
|
||||
break;
|
||||
case 'h':
|
||||
printf("%s", usage);
|
||||
exit(0);
|
||||
/* No return */
|
||||
case 'H':
|
||||
header_name = xstrdup(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
rcinline = 1;
|
||||
break;
|
||||
case 'o':
|
||||
output_name = xstrdup(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
unicodein = 1;
|
||||
break;
|
||||
case 'U':
|
||||
unicodeout = 1;
|
||||
break;
|
||||
case 'v':
|
||||
show_languages();
|
||||
show_codepages();
|
||||
exit(0);
|
||||
/* No return */
|
||||
case 'V':
|
||||
printf(version_string);
|
||||
exit(0);
|
||||
/* No return */
|
||||
case 'W':
|
||||
pedantic = 1;
|
||||
break;
|
||||
default:
|
||||
lose++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lose)
|
||||
{
|
||||
fprintf(stderr, "%s", usage);
|
||||
return 1;
|
||||
}
|
||||
|
||||
yydebug = dodebug;
|
||||
if(dodebug)
|
||||
{
|
||||
setbuf(stdout, 0);
|
||||
setbuf(stderr, 0);
|
||||
}
|
||||
|
||||
/* Check for input file on command-line */
|
||||
if(optind < argc)
|
||||
{
|
||||
input_name = argv[optind];
|
||||
}
|
||||
|
||||
/* Generate appropriate outfile names */
|
||||
if(!output_name)
|
||||
{
|
||||
output_name = dup_basename(input_name, ".mc");
|
||||
strcat(output_name, ".rc");
|
||||
}
|
||||
|
||||
if(!header_name)
|
||||
{
|
||||
header_name = dup_basename(input_name, ".mc");
|
||||
strcat(header_name, ".h");
|
||||
}
|
||||
|
||||
if(input_name)
|
||||
{
|
||||
if(!(yyin = fopen(input_name, "rb")))
|
||||
error("Could not open %s for input\n", input_name);
|
||||
}
|
||||
else
|
||||
yyin = stdin;
|
||||
|
||||
ret = yyparse();
|
||||
|
||||
if(input_name)
|
||||
fclose(yyin);
|
||||
|
||||
if(ret)
|
||||
{
|
||||
/* Error during parse */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
write_h_file(header_name);
|
||||
write_rc_file(output_name);
|
||||
if(!rcinline)
|
||||
write_bin_files();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void segvhandler(int sig)
|
||||
{
|
||||
fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Main definitions and externals
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WMC_WMC_H
|
||||
#define __WMC_WMC_H
|
||||
|
||||
#ifndef __WMC_WMCTYPES_H
|
||||
#include "wmctypes.h"
|
||||
#endif
|
||||
|
||||
#include <time.h> /* For time_t */
|
||||
|
||||
#define WMC_MAJOR_VERSION 1
|
||||
#define WMC_MINOR_VERSION 0
|
||||
#define WMC_MICRO_VERSION 0
|
||||
#define WMC_RELEASEDATE "(12-Jun-2000)"
|
||||
|
||||
#define WMC_STRINGIZE(a) #a
|
||||
#define WMC_VERSIONIZE(a,b,c) WMC_STRINGIZE(a) "." WMC_STRINGIZE(b) "." WMC_STRINGIZE(c)
|
||||
#define WMC_VERSION WMC_VERSIONIZE(WMC_MAJOR_VERSION, WMC_MINOR_VERSION, WMC_MICRO_VERSION)
|
||||
#define WMC_FULLVERSION WMC_VERSION " " WMC_RELEASEDATE
|
||||
|
||||
/*
|
||||
* The default codepage setting is only to
|
||||
* read and convert input which is non-message
|
||||
* text. It doesn't really matter that much because
|
||||
* all codepages map 0x00-0x7f to 0x0000-0x007f from
|
||||
* char to unicode and all non-message text should
|
||||
* be plain ASCII.
|
||||
* However, we do implement iso-8859-1 for 1-to-1
|
||||
* mapping for all other chars, so this is very close
|
||||
* to what we really want.
|
||||
*/
|
||||
#define WMC_DEFAULT_CODEPAGE 28591
|
||||
|
||||
extern int pedantic;
|
||||
extern int leave_case;
|
||||
extern int byteorder;
|
||||
extern int decimal;
|
||||
extern int custombit;
|
||||
extern int unicodein;
|
||||
extern int unicodeout;
|
||||
extern int rcinline;
|
||||
|
||||
extern char *output_name;
|
||||
extern char *input_name;
|
||||
extern char *header_name;
|
||||
extern char *cmdline;
|
||||
extern time_t now;
|
||||
|
||||
extern int line_number;
|
||||
extern int char_number;
|
||||
|
||||
int yyparse(void);
|
||||
extern int yydebug;
|
||||
extern int want_nl;
|
||||
extern int want_line;
|
||||
extern int want_file;
|
||||
extern node_t *nodehead;
|
||||
extern lan_blk_t *lanblockhead;
|
||||
|
||||
int yylex(void);
|
||||
FILE *yyin;
|
||||
void set_codepage(int cp);
|
||||
|
||||
void add_token(tok_e type, const WCHAR *name, int tok, int cp, const WCHAR *alias, int fix);
|
||||
token_t *lookup_token(const WCHAR *s);
|
||||
void get_tokentable(token_t **tab, int *len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
.TH WMC 1 "June 12, 2000" "Version 1.0.0" "Wine Message Compiler"
|
||||
.SH NAME
|
||||
wrc \- Wine Message Compiler
|
||||
.SH SYNOPSIS
|
||||
.BI "wmc " "[options] " "[inputfile]"
|
||||
.SH DESCRIPTION
|
||||
.B wmc
|
||||
compiles messages from
|
||||
.B inputfile
|
||||
into FormatMessage[AW] compatible format encapsulated in a resourcescript
|
||||
format.
|
||||
.B wmc
|
||||
outputs the data either in a standard \fB.bin\fR formatted binary
|
||||
file, or can generated inline resource data.
|
||||
.PP
|
||||
.B wmc
|
||||
takes only one \fBinputfile\fR as argument (see \fBBUGS\fR). The
|
||||
\fBinputfile\fR normally has extension \fB.mc\fR. The messages are read from
|
||||
standard input if no inputfile is given. If the outputfile is not specified
|
||||
with \fI-o\fR, then \fBwmc\fR will write the output to \fBinputfile.{rc,h}\fR.
|
||||
The outputfile is named \fBwmc.tab.{rc,h}\fR if no inputfile was given.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.I \-B x
|
||||
Set output byte-order x={n[ative], l[ittle], b[ig]}. Default is n[ative].
|
||||
.TP
|
||||
.I \-c
|
||||
Set 'custom-bit' in message-code values.
|
||||
.TP
|
||||
.I \-d
|
||||
NON-FUNCTIONAL; Use decimal values in output
|
||||
.TP
|
||||
.I \-D
|
||||
Set debug flag. This results is a parser trace and a lot of extra messages.
|
||||
.TP
|
||||
.I \-h
|
||||
Print an informative usage message.
|
||||
.TP
|
||||
.I \-H file
|
||||
Write headerfile to \fIfile\fR. Default is \fIinputfile.h\fR.
|
||||
.TP
|
||||
.I \-i
|
||||
Inline messagetable(s). This option skips the generation of all \fI.bin\fR files
|
||||
and writes all output into the \fI.rc\fR file. This encoding is parsable with
|
||||
wrc(1).
|
||||
.TP
|
||||
.I \-o file
|
||||
Output to \fIfile\fR. Default is \fIinputfile.rc\fR.
|
||||
.TP
|
||||
.I \-u
|
||||
Assume that the inputfile is in unicode.
|
||||
.TP
|
||||
.I \-U
|
||||
Write resource output in unicode formatted messagetable(s).
|
||||
.TP
|
||||
.I \-v
|
||||
Show all supported codepages and languages.
|
||||
.TP
|
||||
.I \-V
|
||||
Print version end exit.
|
||||
.TP
|
||||
.I \-W
|
||||
Enable pedantic warnings.
|
||||
.SH EXTENSIONS
|
||||
The original syntax is extended to support codepages more smoothly. Normally,
|
||||
codepages are based on the DOS\-codepage from the language setting. The
|
||||
original syntax only allows the destination codepage to be set. However, this
|
||||
is not enough for non\-DOS systems which do not use unicode source-files.
|
||||
.PP
|
||||
A new keyword \fICodepages\fR is introduced to set both input and output
|
||||
codepages to anything one wants for each language. The syntax is similar to
|
||||
the other constructs:
|
||||
.PP
|
||||
Codepages '=' '(' language '=' cpin ':' cpout ... ')'
|
||||
.PP
|
||||
The \fIlanguage\fR is the numerical language\-ID or the alias set with
|
||||
LanguageNames. The input\-codepage \fIcpin\fR and output\-codepage
|
||||
\fIcpout\fR are the numerical codepage\-IDs. There can be multiple mapping
|
||||
within the definition and the definition may occur more than once.
|
||||
.SH AUTHORS
|
||||
.B wmc
|
||||
was written by Bertho A. Stultiens.
|
||||
.SH BUGS
|
||||
The message compiler should be able to have multiple inputfiles and combine
|
||||
them into one outputfile. This would enable the splitting of languages into
|
||||
separate files.
|
||||
.PP
|
||||
Unicode detection of the input is suboptimal, to say the least. It should
|
||||
recognize byte\-order\-marks (BOM) and decide what to do.
|
||||
.PP
|
||||
Decimal output is completely lacking. Don't know whether it should be
|
||||
implemented because it is a, well, non-informative format change. It is
|
||||
recognized on the commandline for some form of compatibility.
|
||||
.SH AVAILABILITY
|
||||
.B wmc
|
||||
is part of the wine distribution, which is available through
|
||||
WineHQ, the
|
||||
.B wine
|
||||
development headquarters, at
|
||||
.I http://www.winehq.com/.
|
||||
.SH "SEE ALSO"
|
||||
.BR wine (1),
|
||||
.BR wrc (1)
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Main definitions and externals
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __WMC_WMCTYPES_H
|
||||
#define __WMC_WMCTYPES_H
|
||||
|
||||
#ifndef __WINE_WINDEF_H
|
||||
#include "windef.h"
|
||||
#endif
|
||||
|
||||
/* Byteordering defines */
|
||||
#define WMC_BO_NATIVE 0x00
|
||||
#define WMC_BO_LITTLE 0x01
|
||||
#define WMC_BO_BIG 0x02
|
||||
|
||||
#define WMC_LOBYTE(w) ((WORD)(w) & 0xff)
|
||||
#define WMC_HIBYTE(w) (((WORD)(w) >> 8) & 0xff)
|
||||
#define WMC_LOWORD(d) ((DWORD)(d) & 0xffff)
|
||||
#define WMC_HIWORD(d) (((DWORD)(d) >> 16) & 0xffff)
|
||||
#define BYTESWAP_WORD(w) ((WORD)(((WORD)WMC_LOBYTE(w) << 8) + (WORD)WMC_HIBYTE(w)))
|
||||
#define BYTESWAP_DWORD(d) ((DWORD)(((DWORD)BYTESWAP_WORD(WMC_LOWORD(d)) << 16) + ((DWORD)BYTESWAP_WORD(WMC_HIWORD(d)))))
|
||||
|
||||
/*
|
||||
* Tokenizer types
|
||||
*/
|
||||
typedef enum tok_enum {
|
||||
tok_null = 0,
|
||||
tok_keyword,
|
||||
tok_severity,
|
||||
tok_facility,
|
||||
tok_language
|
||||
} tok_e;
|
||||
|
||||
typedef struct token {
|
||||
tok_e type;
|
||||
const WCHAR *name; /* Parsed name of token */
|
||||
int token; /* Tokenvalue or language code */
|
||||
int codepage;
|
||||
const WCHAR *alias; /* Alias or filename */
|
||||
int fixed; /* Cleared if token may change */
|
||||
} token_t;
|
||||
|
||||
typedef struct lan_cp {
|
||||
int language;
|
||||
int codepage;
|
||||
} lan_cp_t;
|
||||
|
||||
typedef struct cp_xlat {
|
||||
int lan;
|
||||
int cpin;
|
||||
int cpout;
|
||||
} cp_xlat_t;
|
||||
|
||||
typedef struct lanmsg {
|
||||
int lan; /* Language code of message */
|
||||
int cp; /* Codepage of message */
|
||||
WCHAR *msg; /* Message text */
|
||||
int len; /* Message length including trailing '\0' */
|
||||
} lanmsg_t;
|
||||
|
||||
typedef struct msg {
|
||||
int id; /* Message ID */
|
||||
unsigned realid; /* Combined message ID */
|
||||
WCHAR *sym; /* Symbolic name */
|
||||
int sev; /* Severity code */
|
||||
int fac; /* Facility code */
|
||||
lanmsg_t **msgs; /* Array message texts */
|
||||
int nmsgs; /* Number of message texts in array */
|
||||
int base; /* Base of number to print */
|
||||
WCHAR *cast; /* Typecase to use */
|
||||
} msg_t;
|
||||
|
||||
typedef enum {
|
||||
nd_msg,
|
||||
nd_comment
|
||||
} node_e;
|
||||
|
||||
typedef struct node {
|
||||
struct node *next;
|
||||
struct node *prev;
|
||||
node_e type;
|
||||
union {
|
||||
void *all;
|
||||
WCHAR *comment;
|
||||
msg_t *msg;
|
||||
} u;
|
||||
} node_t;
|
||||
|
||||
typedef struct block {
|
||||
unsigned idlo; /* Lowest ID in this set */
|
||||
unsigned idhi; /* Highest ID in this set */
|
||||
int size; /* Size of this set */
|
||||
lanmsg_t **msgs; /* Array of messages in this set */
|
||||
int nmsg; /* Number of array entries */
|
||||
} block_t;
|
||||
|
||||
typedef struct lan_blk {
|
||||
struct lan_blk *next; /* Linkage for languages */
|
||||
struct lan_blk *prev;
|
||||
int lan; /* The language of this block */
|
||||
block_t *blks; /* Array of blocks for this language */
|
||||
int nblk; /* Nr of blocks in array */
|
||||
} lan_blk_t;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* Wine Message Compiler output generation
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "wmc.h"
|
||||
#include "utils.h"
|
||||
#include "lang.h"
|
||||
#include "write.h"
|
||||
|
||||
/*
|
||||
* The binary resource layout is as follows:
|
||||
*
|
||||
* +===============+
|
||||
* Header | NBlocks |
|
||||
* +===============+
|
||||
* Block 0 | Low ID |
|
||||
* +---------------+
|
||||
* | High ID |
|
||||
* +---------------+
|
||||
* | Offset |---+
|
||||
* +===============+ |
|
||||
* Block 1 | Low ID | |
|
||||
* +---------------+ |
|
||||
* | High ID | |
|
||||
* +---------------+ |
|
||||
* | Offset |------+
|
||||
* +===============+ | |
|
||||
* | | | |
|
||||
* ... ... | |
|
||||
* | | | |
|
||||
* +===============+ <-+ |
|
||||
* B0 LoID | Len | Flags | |
|
||||
* +---+---+---+---+ |
|
||||
* | b | l | a | b | |
|
||||
* +---+---+---+---+ |
|
||||
* | l | a | \0| \0| |
|
||||
* +===============+ |
|
||||
* | | |
|
||||
* ... ... |
|
||||
* | | |
|
||||
* +===============+ |
|
||||
* B0 HiID | Len | Flags | |
|
||||
* +---+---+---+---+ |
|
||||
* | M | o | r | e | |
|
||||
* +---+---+---+---+ |
|
||||
* | b | l | a | \0| |
|
||||
* +===============+ <----+
|
||||
* B1 LoID | Len | Flags |
|
||||
* +---+---+---+---+
|
||||
* | J | u | n | k |
|
||||
* +---+---+---+---+
|
||||
* | \0| \0| \0| \0|
|
||||
* +===============+
|
||||
* | |
|
||||
* ... ...
|
||||
* | |
|
||||
* +===============+
|
||||
*
|
||||
* All Fields are aligned on their natural boundaries. The length
|
||||
* field (Len) covers both the length of the string and the header
|
||||
* fields (Len and Flags). Strings are '\0' terminated. Flags is 0
|
||||
* for normal character strings and 1 for unicode strings.
|
||||
*/
|
||||
|
||||
static char str_header[] =
|
||||
"/* This file is generated with wmc version " WMC_FULLVERSION ". Do not edit! */\n"
|
||||
"/* Source : %s */\n"
|
||||
"/* Cmdline: %s */\n"
|
||||
"/* Date : %s */\n"
|
||||
"\n"
|
||||
;
|
||||
|
||||
static char *dup_u2c(int cp, const WCHAR *uc)
|
||||
{
|
||||
int len = unistrlen(uc);
|
||||
char *cptr = xmalloc(len+1);
|
||||
const union cptable *cpdef = find_codepage(cp);
|
||||
if(!cpdef)
|
||||
internal_error(__FILE__, __LINE__, "Codepage %d not found (vanished?)", cp);
|
||||
if((len = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, cptr, len+1, NULL, NULL)) < 0)
|
||||
internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", len);
|
||||
return cptr;
|
||||
}
|
||||
|
||||
static void killnl(char *s, int ddd)
|
||||
{
|
||||
char *tmp;
|
||||
tmp = strstr(s, "\r\n");
|
||||
if(tmp)
|
||||
{
|
||||
if(ddd && tmp - s > 3)
|
||||
{
|
||||
tmp[0] = tmp[1] = tmp[2] = '.';
|
||||
tmp[3] = '\0';
|
||||
}
|
||||
else
|
||||
*tmp = '\0';
|
||||
}
|
||||
tmp = strchr(s, '\n');
|
||||
if(tmp)
|
||||
{
|
||||
if(ddd && tmp - s > 3)
|
||||
{
|
||||
tmp[0] = tmp[1] = tmp[2] = '.';
|
||||
tmp[3] = '\0';
|
||||
}
|
||||
else
|
||||
*tmp = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int killcomment(char *s)
|
||||
{
|
||||
char *tmp = s;
|
||||
int b = 0;
|
||||
while((tmp = strstr(tmp, "/*")))
|
||||
{
|
||||
tmp[1] = 'x';
|
||||
b++;
|
||||
}
|
||||
tmp = s;
|
||||
while((tmp = strstr(tmp, "*/")))
|
||||
{
|
||||
tmp[0] = 'x';
|
||||
b++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void write_h_file(const char *fname)
|
||||
{
|
||||
node_t *ndp;
|
||||
char *cptr;
|
||||
char *cast;
|
||||
FILE *fp;
|
||||
token_t *ttab;
|
||||
int ntab;
|
||||
int i;
|
||||
int once = 0;
|
||||
int idx_en = 0;
|
||||
|
||||
fp = fopen(fname, "w");
|
||||
if(!fp)
|
||||
{
|
||||
perror(fname);
|
||||
exit(1);
|
||||
}
|
||||
cptr = ctime(&now);
|
||||
killnl(cptr, 0);
|
||||
fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
|
||||
fprintf(fp, "#ifndef __WMCGENERATED_%08lx_H\n", now);
|
||||
fprintf(fp, "#define __WMCGENERATED_%08lx_H\n", now);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Write severity and facility aliases */
|
||||
get_tokentable(&ttab, &ntab);
|
||||
fprintf(fp, "/* Severity codes */\n");
|
||||
for(i = 0; i < ntab; i++)
|
||||
{
|
||||
if(ttab[i].type == tok_severity && ttab[i].alias)
|
||||
{
|
||||
cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
|
||||
fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
|
||||
free(cptr);
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "/* Facility codes */\n");
|
||||
for(i = 0; i < ntab; i++)
|
||||
{
|
||||
if(ttab[i].type == tok_facility && ttab[i].alias)
|
||||
{
|
||||
cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
|
||||
fprintf(fp, "#define %s\t0x%x\n", cptr, ttab[i].token);
|
||||
free(cptr);
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Write the message codes */
|
||||
fprintf(fp, "/* Message definitions */\n");
|
||||
for(ndp = nodehead; ndp; ndp = ndp->next)
|
||||
{
|
||||
switch(ndp->type)
|
||||
{
|
||||
case nd_comment:
|
||||
cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.comment+1);
|
||||
killnl(cptr, 0);
|
||||
killcomment(cptr);
|
||||
if(*cptr)
|
||||
fprintf(fp, "/* %s */\n", cptr);
|
||||
else
|
||||
fprintf(fp, "\n");
|
||||
free(cptr);
|
||||
break;
|
||||
case nd_msg:
|
||||
if(!once)
|
||||
{
|
||||
/*
|
||||
* Search for an english text.
|
||||
* If not found, then use the first in the list
|
||||
*/
|
||||
once++;
|
||||
for(i = 0; i < ndp->u.msg->nmsgs; i++)
|
||||
{
|
||||
if(ndp->u.msg->msgs[i]->lan == 0x409)
|
||||
{
|
||||
idx_en = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp, "/* MessageId : 0x%08x */\n", ndp->u.msg->realid);
|
||||
cptr = dup_u2c(ndp->u.msg->msgs[idx_en]->cp, ndp->u.msg->msgs[idx_en]->msg);
|
||||
killnl(cptr, 0);
|
||||
killcomment(cptr);
|
||||
fprintf(fp, "/* Approx. msg: %s */\n", cptr);
|
||||
free(cptr);
|
||||
cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->sym);
|
||||
if(ndp->u.msg->cast)
|
||||
cast = dup_u2c(WMC_DEFAULT_CODEPAGE, ndp->u.msg->cast);
|
||||
else
|
||||
cast = NULL;
|
||||
switch(ndp->u.msg->base)
|
||||
{
|
||||
case 8:
|
||||
if(cast)
|
||||
fprintf(fp, "#define %s\t((%s)0%oL)\n\n", cptr, cast, ndp->u.msg->realid);
|
||||
else
|
||||
fprintf(fp, "#define %s\t0%oL\n\n", cptr, ndp->u.msg->realid);
|
||||
break;
|
||||
case 10:
|
||||
if(cast)
|
||||
fprintf(fp, "#define %s\t((%s)%dL)\n\n", cptr, cast, ndp->u.msg->realid);
|
||||
else
|
||||
fprintf(fp, "#define %s\t%dL\n\n", cptr, ndp->u.msg->realid);
|
||||
break;
|
||||
case 16:
|
||||
if(cast)
|
||||
fprintf(fp, "#define %s\t((%s)0x%08xL)\n\n", cptr, cast, ndp->u.msg->realid);
|
||||
else
|
||||
fprintf(fp, "#define %s\t0x%08xL\n\n", cptr, ndp->u.msg->realid);
|
||||
break;
|
||||
default:
|
||||
internal_error(__FILE__, __LINE__, "Invalid base for number print");
|
||||
}
|
||||
free(cptr);
|
||||
if(cast)
|
||||
free(cast);
|
||||
break;
|
||||
default:
|
||||
internal_error(__FILE__, __LINE__, "Invalid node type %d", ndp->type);
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n#endif\n");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void write_rcbin(FILE *fp)
|
||||
{
|
||||
lan_blk_t *lbp;
|
||||
token_t *ttab;
|
||||
int ntab;
|
||||
int i;
|
||||
|
||||
get_tokentable(&ttab, &ntab);
|
||||
|
||||
for(lbp = lanblockhead; lbp; lbp = lbp->next)
|
||||
{
|
||||
char *cptr = NULL;
|
||||
fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
|
||||
for(i = 0; i < ntab; i++)
|
||||
{
|
||||
if(ttab[i].type == tok_language && ttab[i].token == lbp->lan)
|
||||
{
|
||||
if(ttab[i].alias)
|
||||
cptr = dup_u2c(WMC_DEFAULT_CODEPAGE, ttab[i].alias);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!cptr)
|
||||
internal_error(__FILE__, __LINE__, "Filename vanished for language 0x%0x", lbp->lan);
|
||||
fprintf(fp, "1 MESSAGETABLE \"%s.bin\"\n", cptr);
|
||||
free(cptr);
|
||||
}
|
||||
}
|
||||
|
||||
static char *make_string(WCHAR *uc, int len, int codepage)
|
||||
{
|
||||
char *str = xmalloc(7*len + 1);
|
||||
char *cptr = str;
|
||||
int i;
|
||||
int b;
|
||||
|
||||
if(!codepage)
|
||||
{
|
||||
*cptr++ = ' ';
|
||||
*cptr++ = 'L';
|
||||
*cptr++ = '"';
|
||||
for(i = b = 0; i < len; i++, uc++)
|
||||
{
|
||||
int n;
|
||||
if(*uc < 0x100)
|
||||
{
|
||||
if(isprint(*uc))
|
||||
{
|
||||
*cptr++ = *uc;
|
||||
b++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(*uc)
|
||||
{
|
||||
case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
|
||||
case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
|
||||
case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
|
||||
case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
|
||||
case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
|
||||
case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
|
||||
case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
|
||||
case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
|
||||
case '"': *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
|
||||
default:
|
||||
n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
|
||||
cptr += n;
|
||||
b += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n = sprintf(cptr, "\\x%04x", *uc & 0xffff);
|
||||
cptr += n;
|
||||
b += n;
|
||||
}
|
||||
if(i < len-1 && b >= 72)
|
||||
{
|
||||
*cptr++ = '"';
|
||||
*cptr++ = ',';
|
||||
*cptr++ = '\n';
|
||||
*cptr++ = ' ';
|
||||
*cptr++ = 'L';
|
||||
*cptr++ = '"';
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
len = (len + 3) & ~3;
|
||||
for(; i < len; i++)
|
||||
{
|
||||
*cptr++ = '\\';
|
||||
*cptr++ = 'x';
|
||||
*cptr++ = '0';
|
||||
*cptr++ = '0';
|
||||
*cptr++ = '0';
|
||||
*cptr++ = '0';
|
||||
}
|
||||
*cptr++ = '"';
|
||||
*cptr = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmp = xmalloc(2*len+1);
|
||||
char *cc = tmp;
|
||||
const union cptable *cpdef = find_codepage(codepage);
|
||||
|
||||
assert(cpdef != NULL);
|
||||
if((i = cp_wcstombs(cpdef, 0, uc, unistrlen(uc)+1, tmp, 2*len+1, NULL, NULL)) < 0)
|
||||
internal_error(__FILE__, __LINE__, "Buffer overflow? code %d.", i);
|
||||
*cptr++ = ' ';
|
||||
*cptr++ = '"';
|
||||
for(i = b = 0; i < len; i++, cc++)
|
||||
{
|
||||
int n;
|
||||
if(isprint(*cc))
|
||||
{
|
||||
*cptr++ = *cc;
|
||||
b++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(*cc)
|
||||
{
|
||||
case '\a': *cptr++ = '\\'; *cptr++ = 'a'; b += 2; break;
|
||||
case '\b': *cptr++ = '\\'; *cptr++ = 'b'; b += 2; break;
|
||||
case '\f': *cptr++ = '\\'; *cptr++ = 'f'; b += 2; break;
|
||||
case '\n': *cptr++ = '\\'; *cptr++ = 'n'; b += 2; break;
|
||||
case '\r': *cptr++ = '\\'; *cptr++ = 'r'; b += 2; break;
|
||||
case '\t': *cptr++ = '\\'; *cptr++ = 't'; b += 2; break;
|
||||
case '\v': *cptr++ = '\\'; *cptr++ = 'v'; b += 2; break;
|
||||
case '\\': *cptr++ = '\\'; *cptr++ = '\\'; b += 2; break;
|
||||
case '"': *cptr++ = '\\'; *cptr++ = '"'; b += 2; break;
|
||||
default:
|
||||
n = sprintf(cptr, "\\x%02x", *cc & 0xff);
|
||||
cptr += n;
|
||||
b += n;
|
||||
}
|
||||
}
|
||||
if(i < len-1 && b >= 72)
|
||||
{
|
||||
*cptr++ = '"';
|
||||
*cptr++ = ',';
|
||||
*cptr++ = '\n';
|
||||
*cptr++ = ' ';
|
||||
*cptr++ = '"';
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
len = (len + 3) & ~3;
|
||||
for(; i < len; i++)
|
||||
{
|
||||
*cptr++ = '\\';
|
||||
*cptr++ = 'x';
|
||||
*cptr++ = '0';
|
||||
*cptr++ = '0';
|
||||
}
|
||||
*cptr++ = '"';
|
||||
*cptr = '\0';
|
||||
free(tmp);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void write_rcinline(FILE *fp)
|
||||
{
|
||||
lan_blk_t *lbp;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for(lbp = lanblockhead; lbp; lbp = lbp->next)
|
||||
{
|
||||
unsigned offs = 4 * (lbp->nblk * 3 + 1);
|
||||
fprintf(fp, "\n1 MESSAGETABLE\n");
|
||||
fprintf(fp, "LANGUAGE 0x%x, 0x%x\n", lbp->lan & 0x3ff, lbp->lan >> 10);
|
||||
fprintf(fp, "{\n");
|
||||
fprintf(fp, " /* NBlocks */ 0x%08xL,\n", lbp->nblk);
|
||||
for(i = 0; i < lbp->nblk; i++)
|
||||
{
|
||||
fprintf(fp, " /* Lo,Hi,Offs */ 0x%08xL, 0x%08xL, 0x%08xL,\n",
|
||||
lbp->blks[i].idlo,
|
||||
lbp->blks[i].idhi,
|
||||
offs);
|
||||
offs += lbp->blks[i].size;
|
||||
}
|
||||
for(i = 0; i < lbp->nblk; i++)
|
||||
{
|
||||
block_t *blk = &lbp->blks[i];
|
||||
for(j = 0; j < blk->nmsg; j++)
|
||||
{
|
||||
char *cptr;
|
||||
int l = blk->msgs[j]->len;
|
||||
char *comma = j == blk->nmsg-1 && i == lbp->nblk-1 ? "" : ",";
|
||||
cptr = make_string(blk->msgs[j]->msg, l, unicodeout ? 0 : blk->msgs[j]->cp);
|
||||
fprintf(fp, "\n /* Msg 0x%08x */ 0x%04x, 0x000%c,\n",
|
||||
blk->idlo + j,
|
||||
unicodeout ? (l*2+3)&~3 : (l+3)&~3,
|
||||
unicodeout ? '1' : '0');
|
||||
fprintf(fp, "%s%s\n", cptr, comma);
|
||||
free(cptr);
|
||||
}
|
||||
}
|
||||
fprintf(fp, "}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void write_rc_file(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
char *cptr;
|
||||
|
||||
fp = fopen(fname, "w");
|
||||
if(!fp)
|
||||
{
|
||||
perror(fname);
|
||||
exit(1);
|
||||
}
|
||||
cptr = ctime(&now);
|
||||
killnl(cptr, 0);
|
||||
fprintf(fp, str_header, input_name ? input_name : "<stdin>", cmdline, cptr);
|
||||
|
||||
if(rcinline)
|
||||
write_rcinline(fp);
|
||||
else
|
||||
write_rcbin(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void write_bin_files(void)
|
||||
{
|
||||
assert(rcinline == 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Wine Message Compiler outpur generation
|
||||
*
|
||||
* Copyright 2000 Bertho A. Stultiens (BS)
|
||||
*
|
||||
*/
|
||||
#ifndef __WMC_WRITE_H
|
||||
#define __WMC_WRITE_H
|
||||
|
||||
void write_h_file(const char *fname);
|
||||
void write_rc_file(const char *fname);
|
||||
void write_bin_files(void);
|
||||
|
||||
#endif
|
|
@ -208,6 +208,6 @@ int cp_wcstombs( const union cptable *table, int flags,
|
|||
if (flags || defchar || used)
|
||||
return wcstombs_dbcs_slow( &table->dbcs, flags, src, srclen,
|
||||
dst, dstlen, defchar, used );
|
||||
return wcstombs_sbcs( &table->sbcs, src, srclen, dst, dstlen );
|
||||
return wcstombs_dbcs( &table->dbcs, src, srclen, dst, dstlen );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue