682 lines
18 KiB
Plaintext
682 lines
18 KiB
Plaintext
/*
|
|
* Wine Message Compiler parser
|
|
*
|
|
* Copyright 2000 Bertho A. Stultiens (BS)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*
|
|
* NOTES:
|
|
*
|
|
* The basic grammar of the file is yet another example of, humpf,
|
|
* design. There is a mix of context-insensitive and -sensitive
|
|
* 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 "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include "wmc.h"
|
|
#include "utils.h"
|
|
#include "lang.h"
|
|
|
|
static const char err_syntax[] = "Syntax error\n";
|
|
static const char err_number[] = "Number expected\n";
|
|
static const char err_ident[] = "Identifier expected\n";
|
|
static const char err_assign[] = "'=' expected\n";
|
|
static const char err_popen[] = "'(' expected\n";
|
|
static const char err_pclose[] = "')' expected\n";
|
|
static const char err_colon[] = "':' expected\n";
|
|
static const char err_msg[] = "Message expected\n";
|
|
|
|
/* 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 */
|
|
|
|
struct node *nodehead = NULL; /* The list of all parsed elements */
|
|
static struct node *nodetail;
|
|
struct lan_blk *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 struct cp_xlat *cpxlattab = NULL; /* Codepage translation table */
|
|
static int ncpxlattab = 0;
|
|
|
|
/* Prototypes */
|
|
static WCHAR *merge(WCHAR *s1, WCHAR *s2);
|
|
static struct lanmsg *new_lanmsg(struct lan_cp *lcp, WCHAR *msg);
|
|
static struct msg *add_lanmsg(struct msg *msg, struct lanmsg *lanmsg);
|
|
static struct msg *complete_msg(struct msg *msg, int id);
|
|
static void add_node(enum node_type type, void *p);
|
|
static void do_add_token(enum tok_enum type, struct token *tok, const char *code);
|
|
static void test_id(int id);
|
|
static int check_languages(struct node *head);
|
|
static struct lan_blk *block_messages(struct node *head);
|
|
static void add_cpxlat(int lan, int cpin, int cpout);
|
|
static struct cp_xlat *find_cpxlat(int lan);
|
|
|
|
%}
|
|
|
|
%union {
|
|
WCHAR *str;
|
|
unsigned num;
|
|
struct token *tok;
|
|
struct lanmsg *lmp;
|
|
struct msg *msg;
|
|
struct lan_cp 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\n");
|
|
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\n");
|
|
}
|
|
}
|
|
| 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)\n", $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)\n", $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($3) && !find_cpxlat($3))
|
|
mcy_warning("Language 0x%x not built-in, using codepage %d; use explicit codepage to override\n", $3, WMC_DEFAULT_CODEPAGE);
|
|
}
|
|
| token '=' tNUMBER setfile ':' error { xyyerror("Filename expected\n"); }
|
|
| 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\n"); }
|
|
;
|
|
|
|
/*----------------------------------------------------------------------
|
|
* 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\n";
|
|
if(find_cpxlat($1))
|
|
xyyerror("Codepage translation already defined for language 0x%x\n", $1);
|
|
if($3 && !is_valid_codepage($3))
|
|
xyyerror(err_nocp, $3);
|
|
if($5 && !is_valid_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\n");
|
|
$$ = $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)\n", $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\n"); have_sev = 1; }
|
|
| sevfacsym fac { if(have_fac) xyyerror("Facility already defined\n"); have_fac = 1; }
|
|
| sevfacsym sym { if(have_sym) xyyerror("Symbolname already defined\n"); have_sym = 1; }
|
|
;
|
|
|
|
sym : tSYMNAME '=' tIDENT { last_sym = $3; }
|
|
| tSYMNAME '=' error { xyyerror(err_ident); }
|
|
| tSYMNAME error { xyyerror(err_assign); }
|
|
;
|
|
|
|
sev : tSEVERITY '=' token {
|
|
struct token *tok = lookup_token($3->name);
|
|
if(!tok)
|
|
xyyerror("Undefined severityname\n");
|
|
if(tok->type != tok_severity)
|
|
xyyerror("Identifier is not of class 'severity'\n");
|
|
last_sev = tok->token;
|
|
}
|
|
| tSEVERITY '=' error { xyyerror(err_ident); }
|
|
| tSEVERITY error { xyyerror(err_assign); }
|
|
;
|
|
|
|
fac : tFACILITY '=' token {
|
|
struct token *tok = lookup_token($3->name);
|
|
if(!tok)
|
|
xyyerror("Undefined facilityname\n");
|
|
if(tok->type != tok_facility)
|
|
xyyerror("Identifier is not of class 'facility'\n");
|
|
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\n"); }
|
|
;
|
|
|
|
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 {
|
|
struct token *tok = lookup_token($4->name);
|
|
struct cp_xlat *cpx;
|
|
if(!tok)
|
|
xyyerror("Undefined language\n");
|
|
if(tok->type != tok_language)
|
|
xyyerror("Identifier is not of class 'language'\n");
|
|
if((cpx = find_cpxlat(tok->token)))
|
|
{
|
|
set_codepage($$.codepage = cpx->cpin);
|
|
}
|
|
else if(!tok->codepage)
|
|
{
|
|
const struct language *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\n"); }
|
|
| 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(struct token)); memset($$,0,sizeof(*$$)); $$->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(enum tok_enum type, struct token *tok, const char *code)
|
|
{
|
|
struct token *tp = lookup_token(tok->name);
|
|
if(tp)
|
|
{
|
|
if(tok->type != type)
|
|
mcy_warning("Type change in token\n");
|
|
if(tp != tok)
|
|
xyyerror("Overlapping token not the same\n");
|
|
/* else its already defined and changed */
|
|
if(tok->fixed)
|
|
xyyerror("Redefinition of %s\n", code);
|
|
tok->fixed = 1;
|
|
}
|
|
else
|
|
{
|
|
add_token(type, tok->name, tok->token, tok->codepage, tok->alias, 1);
|
|
free(tok);
|
|
}
|
|
}
|
|
|
|
static struct lanmsg *new_lanmsg(struct lan_cp *lcp, WCHAR *msg)
|
|
{
|
|
struct lanmsg *lmp = xmalloc(sizeof(*lmp));
|
|
lmp->lan = lcp->language;
|
|
lmp->cp = lcp->codepage;
|
|
lmp->msg = msg;
|
|
lmp->len = unistrlen(msg) + 1; /* Include termination */
|
|
lmp->file = input_name;
|
|
lmp->line = line_number;
|
|
if(lmp->len > 4096)
|
|
mcy_warning("Message exceptionally long; might be a missing termination\n");
|
|
return lmp;
|
|
}
|
|
|
|
static struct msg *add_lanmsg(struct msg *msg, struct lanmsg *lanmsg)
|
|
{
|
|
int i;
|
|
if(!msg)
|
|
{
|
|
msg = xmalloc(sizeof(*msg));
|
|
memset( msg, 0, sizeof(*msg) );
|
|
}
|
|
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\n", lanmsg->lan);
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
static int sort_lanmsg(const void *p1, const void *p2)
|
|
{
|
|
return (*(const struct lanmsg * const *)p1)->lan - (*(const struct lanmsg * const*)p2)->lan;
|
|
}
|
|
|
|
static struct msg *complete_msg(struct msg *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\n", 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(enum node_type type, void *p)
|
|
{
|
|
struct node *ndp = xmalloc(sizeof(*ndp));
|
|
memset( ndp, 0, sizeof(*ndp) );
|
|
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)
|
|
{
|
|
struct node *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\n", id, last_fac, last_sev);
|
|
}
|
|
}
|
|
|
|
static int check_languages(struct node *head)
|
|
{
|
|
static const char err_missing[] = "Missing definition for language 0x%x; MessageID %d, facility 0x%x, severity 0x%x\n";
|
|
struct node *ndp;
|
|
int nm = 0;
|
|
struct msg *msg = NULL;
|
|
|
|
for(ndp = head; ndp; ndp = ndp->next)
|
|
{
|
|
if(ndp->type != nd_msg)
|
|
continue;
|
|
if(!nm)
|
|
{
|
|
msg = ndp->u.msg;
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
struct msg *m1;
|
|
struct msg *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) ((*(const struct msg * const*)(x))->realid)
|
|
static int sort_msg(const void *p1, const void *p2)
|
|
{
|
|
return MSGRID(p1) > MSGRID(p2) ? 1 : (MSGRID(p1) == MSGRID(p2) ? 0 : -1);
|
|
}
|
|
|
|
/*
|
|
* block_messages() basically transposes the messages
|
|
* from ID/language based list to a language/ID
|
|
* based list.
|
|
*/
|
|
static struct lan_blk *block_messages(struct node *head)
|
|
{
|
|
struct lan_blk *lbp;
|
|
struct lan_blk *lblktail = NULL;
|
|
struct lan_blk *lblkhead = NULL;
|
|
struct msg **msgtab = NULL;
|
|
struct node *ndp;
|
|
int nmsg = 0;
|
|
int i;
|
|
int nl;
|
|
int factor = 2;
|
|
|
|
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(*lbp));
|
|
memset( lbp, 0, sizeof(*lbp) );
|
|
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++)
|
|
{
|
|
struct block *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 ((const struct cp_xlat *)p1)->lan - ((const struct cp_xlat *)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);
|
|
}
|
|
|
|
static struct cp_xlat *find_cpxlat(int lan)
|
|
{
|
|
struct cp_xlat t;
|
|
|
|
if(!cpxlattab) return NULL;
|
|
|
|
t.lan = lan;
|
|
return (struct cp_xlat *)bsearch(&t, cpxlattab, ncpxlattab, sizeof(*cpxlattab), sc_xlat);
|
|
}
|