mcy.y 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. * Wine Message Compiler parser
  3. *
  4. * Copyright 2000 Bertho A. Stultiens (BS)
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. *
  20. * NOTES:
  21. *
  22. * The basic grammar of the file is yet another example of, humpf,
  23. * design. There is a mix of context-insensitive and -sensitive
  24. * stuff, which makes it rather complicated.
  25. * The header definitions are all context-insensitive because they have
  26. * delimited arguments, whereas the message headers are (semi-) context-
  27. * sensitive and the messages themselves are, well, RFC82[12] delimited.
  28. * This mixture seems to originate from the time that ms and ibm were
  29. * good friends and developing os/2 according to the "compatibility"
  30. * switch and reading some comments here and there.
  31. *
  32. * I'll ignore most of the complications and concentrate on the concept
  33. * which allows me to use yacc. Basically, everything is context-
  34. * insensitive now, with the exception of the message-text itself and
  35. * the preceding language declaration.
  36. *
  37. */
  38. %{
  39. #include "config.h"
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <assert.h>
  43. #include "wmc.h"
  44. #include "utils.h"
  45. #include "lang.h"
  46. static const char err_syntax[] = "Syntax error\n";
  47. static const char err_number[] = "Number expected\n";
  48. static const char err_ident[] = "Identifier expected\n";
  49. static const char err_assign[] = "'=' expected\n";
  50. static const char err_popen[] = "'(' expected\n";
  51. static const char err_pclose[] = "')' expected\n";
  52. static const char err_colon[] = "':' expected\n";
  53. static const char err_msg[] = "Message expected\n";
  54. /* Scanner switches */
  55. int want_nl = 0; /* Request next newlinw */
  56. int want_line = 0; /* Request next complete line */
  57. int want_file = 0; /* Request next ident as filename */
  58. struct node *nodehead = NULL; /* The list of all parsed elements */
  59. static struct node *nodetail;
  60. struct lan_blk *lanblockhead; /* List of parsed elements transposed */
  61. static int base = 16; /* Current printout base to use (8, 10 or 16) */
  62. static WCHAR *cast = NULL; /* Current typecast to use */
  63. static int last_id = 0; /* The last message ID parsed */
  64. static int last_sev = 0; /* Last severity code parsed */
  65. static int last_fac = 0; /* Last facility code parsed */
  66. static WCHAR *last_sym = NULL;/* Last alias symbol parsed */
  67. static int have_sev; /* Set if severity parsed for current message */
  68. static int have_fac; /* Set if facility parsed for current message */
  69. static int have_sym; /* Set is symbol parsed for current message */
  70. static struct cp_xlat *cpxlattab = NULL; /* Codepage translation table */
  71. static int ncpxlattab = 0;
  72. /* Prototypes */
  73. static WCHAR *merge(WCHAR *s1, WCHAR *s2);
  74. static struct lanmsg *new_lanmsg(struct lan_cp *lcp, WCHAR *msg);
  75. static struct msg *add_lanmsg(struct msg *msg, struct lanmsg *lanmsg);
  76. static struct msg *complete_msg(struct msg *msg, int id);
  77. static void add_node(enum node_type type, void *p);
  78. static void do_add_token(enum tok_enum type, struct token *tok, const char *code);
  79. static void test_id(int id);
  80. static int check_languages(struct node *head);
  81. static struct lan_blk *block_messages(struct node *head);
  82. static void add_cpxlat(int lan, int cpin, int cpout);
  83. static struct cp_xlat *find_cpxlat(int lan);
  84. %}
  85. %union {
  86. WCHAR *str;
  87. unsigned num;
  88. struct token *tok;
  89. struct lanmsg *lmp;
  90. struct msg *msg;
  91. struct lan_cp lcp;
  92. }
  93. %token tSEVNAMES tFACNAMES tLANNAMES tBASE tCODEPAGE
  94. %token tTYPEDEF tNL tSYMNAME tMSGEND
  95. %token tSEVERITY tFACILITY tLANGUAGE tMSGID
  96. %token <str> tIDENT tLINE tFILE tCOMMENT
  97. %token <num> tNUMBER
  98. %token <tok> tTOKEN
  99. %type <str> alias lines
  100. %type <num> optcp id msgid clan
  101. %type <tok> token
  102. %type <lmp> body
  103. %type <msg> bodies msg
  104. %type <lcp> lang
  105. %%
  106. file : items {
  107. if(!check_languages(nodehead))
  108. xyyerror("No messages defined\n");
  109. lanblockhead = block_messages(nodehead);
  110. }
  111. ;
  112. items : decl
  113. | items decl
  114. ;
  115. decl : global
  116. | msg { add_node(nd_msg, $1); }
  117. | tCOMMENT { add_node(nd_comment, $1); }
  118. | error { xyyerror(err_syntax); /* `Catch all' error */ }
  119. ;
  120. global : tSEVNAMES '=' '(' smaps ')'
  121. | tSEVNAMES '=' '(' smaps error { xyyerror(err_pclose); }
  122. | tSEVNAMES '=' error { xyyerror(err_popen); }
  123. | tSEVNAMES error { xyyerror(err_assign); }
  124. | tFACNAMES '=' '(' fmaps ')'
  125. | tFACNAMES '=' '(' fmaps error { xyyerror(err_pclose); }
  126. | tFACNAMES '=' error { xyyerror(err_popen); }
  127. | tFACNAMES error { xyyerror(err_assign); }
  128. | tLANNAMES '=' '(' lmaps ')'
  129. | tLANNAMES '=' '(' lmaps error { xyyerror(err_pclose); }
  130. | tLANNAMES '=' error { xyyerror(err_popen); }
  131. | tLANNAMES error { xyyerror(err_assign); }
  132. | tCODEPAGE '=' '(' cmaps ')'
  133. | tCODEPAGE '=' '(' cmaps error { xyyerror(err_pclose); }
  134. | tCODEPAGE '=' error { xyyerror(err_popen); }
  135. | tCODEPAGE error { xyyerror(err_assign); }
  136. | tTYPEDEF '=' tIDENT { cast = $3; }
  137. | tTYPEDEF '=' error { xyyerror(err_number); }
  138. | tTYPEDEF error { xyyerror(err_assign); }
  139. | tBASE '=' tNUMBER {
  140. switch(base)
  141. {
  142. case 8:
  143. case 10:
  144. case 16:
  145. base = $3;
  146. break;
  147. default:
  148. xyyerror("Numberbase must be 8, 10 or 16\n");
  149. }
  150. }
  151. | tBASE '=' error { xyyerror(err_number); }
  152. | tBASE error { xyyerror(err_assign); }
  153. ;
  154. /*----------------------------------------------------------------------
  155. * SeverityNames mapping
  156. */
  157. smaps : smap
  158. | smaps smap
  159. | error { xyyerror(err_ident); }
  160. ;
  161. smap : token '=' tNUMBER alias {
  162. $1->token = $3;
  163. $1->alias = $4;
  164. if($3 & (~0x3))
  165. xyyerror("Severity value out of range (0x%08x > 0x3)\n", $3);
  166. do_add_token(tok_severity, $1, "severity");
  167. }
  168. | token '=' error { xyyerror(err_number); }
  169. | token error { xyyerror(err_assign); }
  170. ;
  171. /*----------------------------------------------------------------------
  172. * FacilityNames mapping
  173. */
  174. fmaps : fmap
  175. | fmaps fmap
  176. | error { xyyerror(err_ident); }
  177. ;
  178. fmap : token '=' tNUMBER alias {
  179. $1->token = $3;
  180. $1->alias = $4;
  181. if($3 & (~0xfff))
  182. xyyerror("Facility value out of range (0x%08x > 0xfff)\n", $3);
  183. do_add_token(tok_facility, $1, "facility");
  184. }
  185. | token '=' error { xyyerror(err_number); }
  186. | token error { xyyerror(err_assign); }
  187. ;
  188. alias : /* Empty */ { $$ = NULL; }
  189. | ':' tIDENT { $$ = $2; }
  190. | ':' error { xyyerror(err_ident); }
  191. ;
  192. /*----------------------------------------------------------------------
  193. * LanguageNames mapping
  194. */
  195. lmaps : lmap
  196. | lmaps lmap
  197. | error { xyyerror(err_ident); }
  198. ;
  199. lmap : token '=' tNUMBER setfile ':' tFILE optcp {
  200. $1->token = $3;
  201. $1->alias = $6;
  202. $1->codepage = $7;
  203. do_add_token(tok_language, $1, "language");
  204. if(!find_language($3) && !find_cpxlat($3))
  205. mcy_warning("Language 0x%x not built-in, using codepage %d; use explicit codepage to override\n", $3, WMC_DEFAULT_CODEPAGE);
  206. }
  207. | token '=' tNUMBER setfile ':' error { xyyerror("Filename expected\n"); }
  208. | token '=' tNUMBER error { xyyerror(err_colon); }
  209. | token '=' error { xyyerror(err_number); }
  210. | token error { xyyerror(err_assign); }
  211. ;
  212. optcp : /* Empty */ { $$ = 0; }
  213. | ':' tNUMBER { $$ = $2; }
  214. | ':' error { xyyerror("Codepage-number expected\n"); }
  215. ;
  216. /*----------------------------------------------------------------------
  217. * Codepages mapping
  218. */
  219. cmaps : cmap
  220. | cmaps cmap
  221. | error { xyyerror(err_ident); }
  222. ;
  223. cmap : clan '=' tNUMBER ':' tNUMBER {
  224. static const char err_nocp[] = "Codepage %d not builtin; cannot convert\n";
  225. if(find_cpxlat($1))
  226. xyyerror("Codepage translation already defined for language 0x%x\n", $1);
  227. if($3 && !is_valid_codepage($3))
  228. xyyerror(err_nocp, $3);
  229. if($5 && !is_valid_codepage($5))
  230. xyyerror(err_nocp, $5);
  231. add_cpxlat($1, $3, $5);
  232. }
  233. | clan '=' tNUMBER ':' error { xyyerror(err_number); }
  234. | clan '=' tNUMBER error { xyyerror(err_colon); }
  235. | clan '=' error { xyyerror(err_number); }
  236. | clan error { xyyerror(err_assign); }
  237. ;
  238. clan : tNUMBER { $$ = $1; }
  239. | tTOKEN {
  240. if($1->type != tok_language)
  241. xyyerror("Language name or code expected\n");
  242. $$ = $1->token;
  243. }
  244. ;
  245. /*----------------------------------------------------------------------
  246. * Message-definition parsing
  247. */
  248. msg : msgid sevfacsym { test_id($1); } bodies { $$ = complete_msg($4, $1); }
  249. ;
  250. msgid : tMSGID '=' id {
  251. if($3 & (~0xffff))
  252. xyyerror("Message ID value out of range (0x%08x > 0xffff)\n", $3);
  253. $$ = $3;
  254. }
  255. | tMSGID error { xyyerror(err_assign); }
  256. ;
  257. id : /* Empty */ { $$ = ++last_id; }
  258. | tNUMBER { $$ = last_id = $1; }
  259. | '+' tNUMBER { $$ = last_id += $2; }
  260. | '+' error { xyyerror(err_number); }
  261. ;
  262. sevfacsym: /* Empty */ { have_sev = have_fac = have_sym = 0; }
  263. | sevfacsym sev { if(have_sev) xyyerror("Severity already defined\n"); have_sev = 1; }
  264. | sevfacsym fac { if(have_fac) xyyerror("Facility already defined\n"); have_fac = 1; }
  265. | sevfacsym sym { if(have_sym) xyyerror("Symbolname already defined\n"); have_sym = 1; }
  266. ;
  267. sym : tSYMNAME '=' tIDENT { last_sym = $3; }
  268. | tSYMNAME '=' error { xyyerror(err_ident); }
  269. | tSYMNAME error { xyyerror(err_assign); }
  270. ;
  271. sev : tSEVERITY '=' token {
  272. struct token *tok = lookup_token($3->name);
  273. if(!tok)
  274. xyyerror("Undefined severityname\n");
  275. if(tok->type != tok_severity)
  276. xyyerror("Identifier is not of class 'severity'\n");
  277. last_sev = tok->token;
  278. }
  279. | tSEVERITY '=' error { xyyerror(err_ident); }
  280. | tSEVERITY error { xyyerror(err_assign); }
  281. ;
  282. fac : tFACILITY '=' token {
  283. struct token *tok = lookup_token($3->name);
  284. if(!tok)
  285. xyyerror("Undefined facilityname\n");
  286. if(tok->type != tok_facility)
  287. xyyerror("Identifier is not of class 'facility'\n");
  288. last_fac = tok->token;
  289. }
  290. | tFACILITY '=' error { xyyerror(err_ident); }
  291. | tFACILITY error { xyyerror(err_assign); }
  292. ;
  293. /*----------------------------------------------------------------------
  294. * Message-text parsing
  295. */
  296. bodies : body { $$ = add_lanmsg(NULL, $1); }
  297. | bodies body { $$ = add_lanmsg($1, $2); }
  298. | error { xyyerror("'Language=...' (start of message text-definition) expected\n"); }
  299. ;
  300. body : lang setline lines tMSGEND { $$ = new_lanmsg(&$1, $3); }
  301. ;
  302. /*
  303. * The newline is to be able to set the codepage
  304. * to the language based codepage for the next
  305. * message to be parsed.
  306. */
  307. lang : tLANGUAGE setnl '=' token tNL {
  308. struct token *tok = lookup_token($4->name);
  309. struct cp_xlat *cpx;
  310. if(!tok)
  311. xyyerror("Undefined language\n");
  312. if(tok->type != tok_language)
  313. xyyerror("Identifier is not of class 'language'\n");
  314. if((cpx = find_cpxlat(tok->token)))
  315. {
  316. set_codepage($$.codepage = cpx->cpin);
  317. }
  318. else if(!tok->codepage)
  319. {
  320. const struct language *lan = find_language(tok->token);
  321. if(!lan)
  322. {
  323. /* Just set default; warning was given while parsing languagenames */
  324. set_codepage($$.codepage = WMC_DEFAULT_CODEPAGE);
  325. }
  326. else
  327. {
  328. /* The default seems to be to use the DOS codepage... */
  329. set_codepage($$.codepage = lan->doscp);
  330. }
  331. }
  332. else
  333. set_codepage($$.codepage = tok->codepage);
  334. $$.language = tok->token;
  335. }
  336. | tLANGUAGE setnl '=' token error { xyyerror("Missing newline\n"); }
  337. | tLANGUAGE setnl '=' error { xyyerror(err_ident); }
  338. | tLANGUAGE error { xyyerror(err_assign); }
  339. ;
  340. lines : tLINE { $$ = $1; }
  341. | lines tLINE { $$ = merge($1, $2); }
  342. | error { xyyerror(err_msg); }
  343. | lines error { xyyerror(err_msg); }
  344. ;
  345. /*----------------------------------------------------------------------
  346. * Helper rules
  347. */
  348. token : tIDENT { $$ = xmalloc(sizeof(struct token)); memset($$,0,sizeof(*$$)); $$->name = $1; }
  349. | tTOKEN { $$ = $1; }
  350. ;
  351. setnl : /* Empty */ { want_nl = 1; }
  352. ;
  353. setline : /* Empty */ { want_line = 1; }
  354. ;
  355. setfile : /* Empty */ { want_file = 1; }
  356. ;
  357. %%
  358. static WCHAR *merge(WCHAR *s1, WCHAR *s2)
  359. {
  360. int l1 = unistrlen(s1);
  361. int l2 = unistrlen(s2);
  362. s1 = xrealloc(s1, (l1 + l2 + 1) * sizeof(*s1));
  363. unistrcpy(s1+l1, s2);
  364. free(s2);
  365. return s1;
  366. }
  367. static void do_add_token(enum tok_enum type, struct token *tok, const char *code)
  368. {
  369. struct token *tp = lookup_token(tok->name);
  370. if(tp)
  371. {
  372. if(tok->type != type)
  373. mcy_warning("Type change in token\n");
  374. if(tp != tok)
  375. xyyerror("Overlapping token not the same\n");
  376. /* else its already defined and changed */
  377. if(tok->fixed)
  378. xyyerror("Redefinition of %s\n", code);
  379. tok->fixed = 1;
  380. }
  381. else
  382. {
  383. add_token(type, tok->name, tok->token, tok->codepage, tok->alias, 1);
  384. free(tok);
  385. }
  386. }
  387. static struct lanmsg *new_lanmsg(struct lan_cp *lcp, WCHAR *msg)
  388. {
  389. struct lanmsg *lmp = xmalloc(sizeof(*lmp));
  390. lmp->lan = lcp->language;
  391. lmp->cp = lcp->codepage;
  392. lmp->msg = msg;
  393. lmp->len = unistrlen(msg) + 1; /* Include termination */
  394. lmp->file = input_name;
  395. lmp->line = line_number;
  396. if(lmp->len > 4096)
  397. mcy_warning("Message exceptionally long; might be a missing termination\n");
  398. return lmp;
  399. }
  400. static struct msg *add_lanmsg(struct msg *msg, struct lanmsg *lanmsg)
  401. {
  402. int i;
  403. if(!msg)
  404. {
  405. msg = xmalloc(sizeof(*msg));
  406. memset( msg, 0, sizeof(*msg) );
  407. }
  408. msg->msgs = xrealloc(msg->msgs, (msg->nmsgs+1) * sizeof(*(msg->msgs)));
  409. msg->msgs[msg->nmsgs] = lanmsg;
  410. msg->nmsgs++;
  411. for(i = 0; i < msg->nmsgs-1; i++)
  412. {
  413. if(msg->msgs[i]->lan == lanmsg->lan)
  414. xyyerror("Message for language 0x%x already defined\n", lanmsg->lan);
  415. }
  416. return msg;
  417. }
  418. static int sort_lanmsg(const void *p1, const void *p2)
  419. {
  420. return (*(const struct lanmsg * const *)p1)->lan - (*(const struct lanmsg * const*)p2)->lan;
  421. }
  422. static struct msg *complete_msg(struct msg *mp, int id)
  423. {
  424. assert(mp != NULL);
  425. mp->id = id;
  426. if(have_sym)
  427. mp->sym = last_sym;
  428. else
  429. xyyerror("No symbolic name defined for message id %d\n", id);
  430. mp->sev = last_sev;
  431. mp->fac = last_fac;
  432. qsort(mp->msgs, mp->nmsgs, sizeof(*(mp->msgs)), sort_lanmsg);
  433. mp->realid = id | (last_sev << 30) | (last_fac << 16);
  434. if(custombit)
  435. mp->realid |= 1 << 29;
  436. mp->base = base;
  437. mp->cast = cast;
  438. return mp;
  439. }
  440. static void add_node(enum node_type type, void *p)
  441. {
  442. struct node *ndp = xmalloc(sizeof(*ndp));
  443. memset( ndp, 0, sizeof(*ndp) );
  444. ndp->type = type;
  445. ndp->u.all = p;
  446. if(nodetail)
  447. {
  448. ndp->prev = nodetail;
  449. nodetail->next = ndp;
  450. nodetail = ndp;
  451. }
  452. else
  453. {
  454. nodehead = nodetail = ndp;
  455. }
  456. }
  457. static void test_id(int id)
  458. {
  459. struct node *ndp;
  460. for(ndp = nodehead; ndp; ndp = ndp->next)
  461. {
  462. if(ndp->type != nd_msg)
  463. continue;
  464. if(ndp->u.msg->id == id && ndp->u.msg->sev == last_sev && ndp->u.msg->fac == last_fac)
  465. xyyerror("MessageId %d with facility 0x%x and severity 0x%x already defined\n", id, last_fac, last_sev);
  466. }
  467. }
  468. static int check_languages(struct node *head)
  469. {
  470. static const char err_missing[] = "Missing definition for language 0x%x; MessageID %d, facility 0x%x, severity 0x%x\n";
  471. struct node *ndp;
  472. int nm = 0;
  473. struct msg *msg = NULL;
  474. for(ndp = head; ndp; ndp = ndp->next)
  475. {
  476. if(ndp->type != nd_msg)
  477. continue;
  478. if(!nm)
  479. {
  480. msg = ndp->u.msg;
  481. }
  482. else
  483. {
  484. int i;
  485. struct msg *m1;
  486. struct msg *m2;
  487. if(ndp->u.msg->nmsgs > msg->nmsgs)
  488. {
  489. m1 = ndp->u.msg;
  490. m2 = msg;
  491. }
  492. else
  493. {
  494. m1 = msg;
  495. m2 = ndp->u.msg;
  496. }
  497. for(i = 0; i < m1->nmsgs; i++)
  498. {
  499. if(i > m2->nmsgs)
  500. error(err_missing, m1->msgs[i]->lan, m2->id, m2->fac, m2->sev);
  501. else if(m1->msgs[i]->lan < m2->msgs[i]->lan)
  502. error(err_missing, m1->msgs[i]->lan, m2->id, m2->fac, m2->sev);
  503. else if(m1->msgs[i]->lan > m2->msgs[i]->lan)
  504. error(err_missing, m2->msgs[i]->lan, m1->id, m1->fac, m1->sev);
  505. }
  506. }
  507. nm++;
  508. }
  509. return nm;
  510. }
  511. #define MSGRID(x) ((*(const struct msg * const*)(x))->realid)
  512. static int sort_msg(const void *p1, const void *p2)
  513. {
  514. return MSGRID(p1) > MSGRID(p2) ? 1 : (MSGRID(p1) == MSGRID(p2) ? 0 : -1);
  515. }
  516. /*
  517. * block_messages() basically transposes the messages
  518. * from ID/language based list to a language/ID
  519. * based list.
  520. */
  521. static struct lan_blk *block_messages(struct node *head)
  522. {
  523. struct lan_blk *lbp;
  524. struct lan_blk *lblktail = NULL;
  525. struct lan_blk *lblkhead = NULL;
  526. struct msg **msgtab = NULL;
  527. struct node *ndp;
  528. int nmsg = 0;
  529. int i;
  530. int nl;
  531. int factor = 2;
  532. for(ndp = head; ndp; ndp = ndp->next)
  533. {
  534. if(ndp->type != nd_msg)
  535. continue;
  536. msgtab = xrealloc(msgtab, (nmsg+1) * sizeof(*msgtab));
  537. msgtab[nmsg++] = ndp->u.msg;
  538. }
  539. assert(nmsg != 0);
  540. qsort(msgtab, nmsg, sizeof(*msgtab), sort_msg);
  541. for(nl = 0; nl < msgtab[0]->nmsgs; nl++) /* This should be equal for all after check_languages() */
  542. {
  543. lbp = xmalloc(sizeof(*lbp));
  544. memset( lbp, 0, sizeof(*lbp) );
  545. if(!lblktail)
  546. {
  547. lblkhead = lblktail = lbp;
  548. }
  549. else
  550. {
  551. lblktail->next = lbp;
  552. lbp->prev = lblktail;
  553. lblktail = lbp;
  554. }
  555. lbp->nblk = 1;
  556. lbp->blks = xmalloc(sizeof(*lbp->blks));
  557. lbp->blks[0].idlo = msgtab[0]->realid;
  558. lbp->blks[0].idhi = msgtab[0]->realid;
  559. /* The plus 4 is the entry header; (+3)&~3 is DWORD alignment */
  560. lbp->blks[0].size = ((factor * msgtab[0]->msgs[nl]->len + 3) & ~3) + 4;
  561. lbp->blks[0].msgs = xmalloc(sizeof(*lbp->blks[0].msgs));
  562. lbp->blks[0].nmsg = 1;
  563. lbp->blks[0].msgs[0] = msgtab[0]->msgs[nl];
  564. lbp->lan = msgtab[0]->msgs[nl]->lan;
  565. for(i = 1; i < nmsg; i++)
  566. {
  567. struct block *blk = &(lbp->blks[lbp->nblk-1]);
  568. if(msgtab[i]->realid == blk->idhi+1)
  569. {
  570. blk->size += ((factor * msgtab[i]->msgs[nl]->len + 3) & ~3) + 4;
  571. blk->idhi++;
  572. blk->msgs = xrealloc(blk->msgs, (blk->nmsg+1) * sizeof(*blk->msgs));
  573. blk->msgs[blk->nmsg++] = msgtab[i]->msgs[nl];
  574. }
  575. else
  576. {
  577. lbp->nblk++;
  578. lbp->blks = xrealloc(lbp->blks, lbp->nblk * sizeof(*lbp->blks));
  579. blk = &(lbp->blks[lbp->nblk-1]);
  580. blk->idlo = msgtab[i]->realid;
  581. blk->idhi = msgtab[i]->realid;
  582. blk->size = ((factor * msgtab[i]->msgs[nl]->len + 3) & ~3) + 4;
  583. blk->msgs = xmalloc(sizeof(*blk->msgs));
  584. blk->nmsg = 1;
  585. blk->msgs[0] = msgtab[i]->msgs[nl];
  586. }
  587. }
  588. }
  589. free(msgtab);
  590. return lblkhead;
  591. }
  592. static int sc_xlat(const void *p1, const void *p2)
  593. {
  594. return ((const struct cp_xlat *)p1)->lan - ((const struct cp_xlat *)p2)->lan;
  595. }
  596. static void add_cpxlat(int lan, int cpin, int cpout)
  597. {
  598. cpxlattab = xrealloc(cpxlattab, (ncpxlattab+1) * sizeof(*cpxlattab));
  599. cpxlattab[ncpxlattab].lan = lan;
  600. cpxlattab[ncpxlattab].cpin = cpin;
  601. cpxlattab[ncpxlattab].cpout = cpout;
  602. ncpxlattab++;
  603. qsort(cpxlattab, ncpxlattab, sizeof(*cpxlattab), sc_xlat);
  604. }
  605. static struct cp_xlat *find_cpxlat(int lan)
  606. {
  607. struct cp_xlat t;
  608. if(!cpxlattab) return NULL;
  609. t.lan = lan;
  610. return (struct cp_xlat *)bsearch(&t, cpxlattab, ncpxlattab, sizeof(*cpxlattab), sc_xlat);
  611. }