| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920 | /* TODO: * * add UNDEFINED at end if not specified * convert POSITION -> FORWARD,POSITION * * * deal with lowercase in <Uhhhh> * * what about reorders that keep the same rule? * * remove "unused" collation elements? (probably doesn't save much) * * add_rule function ... returns index into rule table after possibly adding custom-indexed rule * but don't forget about multichar weights... replace with strings of indexes * */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <stdarg.h>#include <limits.h>#include <ctype.h>#include <assert.h>#include <search.h>typedef struct {	char *name;					/*  */	int num_weights;			/*  */	int ii_shift;				/*  */	int ti_shift;				/*  */	int ii_len;					/*  */	int ti_len;					/*  */	int max_weight;				/*  */	int num_col_base;			/*  */	int max_col_index;			/*  */	int undefined_idx;			/*  */	int range_low;				/*  */	int range_count;			/* high - low */	int range_base_weight;		/*  */	int num_starters;			/*  */	int range_rule_offset;		/*  */	int wcs2colidt_offset;		/*  */	int index2weight_offset;	/*  */	int index2ruleidx_offset;	/*  */	int multistart_offset;		/*  */} base_locale_t;#define BASE_LOCALE_LEN 20static base_locale_t base_locale_array[BASE_LOCALE_LEN];static size_t base_locale_len;typedef struct {	char *name;					/*  */	int base_idx;				/*  */	int undefined_idx;			/*  */		int overrides_offset;		/*  */	int multistart_offset;		/*  */} der_locale_t;#define DER_LOCALE_LEN 300static der_locale_t der_locale_array[DER_LOCALE_LEN];static size_t der_locale_len;#define OVERRIDE_LEN  50000static uint16_t override_buffer[OVERRIDE_LEN];static size_t override_len;#define MULTISTART_LEN 10000static uint16_t multistart_buffer[MULTISTART_LEN];static size_t multistart_len;#define WCS2COLIDT_LEN 200000static uint16_t wcs2colidt_buffer[WCS2COLIDT_LEN];static size_t wcs2colidt_len;#define INDEX2WEIGHT_LEN 200000static uint16_t index2weight_buffer[INDEX2WEIGHT_LEN];static size_t index2weight_len;static uint16_t index2ruleidx_buffer[INDEX2WEIGHT_LEN];static size_t index2ruleidx_len;#define WEIGHTSTR_LEN 10000static uint16_t weightstr_buffer[WEIGHTSTR_LEN];static size_t weightstr_len;#define RULETABLE_LEN (1L<<16)static uint16_t ruletable_buffer[RULETABLE_LEN];static size_t ruletable_len;#define RANGE (0x10000UL)typedef uint16_t tbl_item;static uint16_t u16_buf[10000];static int u16_buf_len;static int u16_starter;typedef struct {	uint16_t ii_len;	uint16_t ti_len;	uint16_t ut_len;	unsigned char ii_shift;	unsigned char ti_shift;	tbl_item *ii;	tbl_item *ti;	tbl_item *ut;} table_data;static size_t newopt(tbl_item *ut, size_t usize, int shift, table_data *tbl);#define MAX_COLLATION_WEIGHTS 4#define MAX_FNO 1#define MAX_FILES  (MAX_FNO + 1)static FILE *fstack[MAX_FILES];static char *fname[MAX_FILES];static int lineno[MAX_FILES];static int fno = -1;static tbl_item wcs2index[RANGE];static char linebuf[1024];static char *pos;static char *pos_e = NULL;static char end_of_token = 0;		/* slot to save */#define IN_ORDER			0x01#define IN_REORDER			0x02#define IN_REORDER_SECTIONS	0x04static int order_state;static int cur_num_weights;		/* number of weights in current use */static char cur_rule[MAX_COLLATION_WEIGHTS];static int anonsection = 0;typedef struct ll_item_struct ll_item_t;struct ll_item_struct {	ll_item_t *next;	ll_item_t *prev;	void *data;	int data_type;	int idx;};static ll_item_t *reorder_section_ptr = NULL;static int superset;static int superset_order_start_cnt; /* only support one order for now */static int superset_in_sync;static ll_item_t *comm_cur_ptr;static ll_item_t *comm_prev_ptr;enum {	R_FORWARD =		0x01,	R_POSITION =	0x02,	R_BACKWARD =	0x04		/* must be largest in value */};typedef struct {	size_t num_weights;	char rule[MAX_COLLATION_WEIGHTS];	const char *colitem[MAX_COLLATION_WEIGHTS];} weight_t;static void *root_weight = NULL;size_t unique_weights = 0;typedef struct {	const char *symbol;	weight_t *weight;} weighted_item_t;typedef struct {	const char *symbol1;	const char *symbol2;	int length;	weight_t *weight;} range_item_t;typedef struct {	const char *name;	ll_item_t *itm_list;		/* weighted_item_t list .. circular!!! */	size_t num_items;	size_t num_rules;	char rules[MAX_COLLATION_WEIGHTS];} section_t;static section_t *cur_section = NULL;typedef struct {	const char *symbol;	ll_item_t *node;} wi_index_t;typedef struct col_locale_struct col_locale_t;struct  col_locale_struct {	char *name;	void *root_colitem;			/* all base and derived, or just derived */	void *root_element;	void *root_scripts;	void *root_wi_index;	void *root_wi_index_reordered;	ll_item_t *section_list;	col_locale_t *base_locale;	/* null if this is a base */	void *root_derived_wi;	ll_item_t *derived_list;	void *root_starter_char;	void *root_starter_all;	ll_item_t *undefined_idx;};typedef struct {	const char *symbol;	int idx;} col_index_t;static void *root_col_locale = NULL;typedef struct {    const char *keyword;    void (*handler)(void);} keyword_table_t;typedef struct {    const char *string;    const char *element;	/* NULL if collating symbol */} colitem_t;static col_locale_t *cur_base = NULL;static col_locale_t *cur_derived = NULL;static col_locale_t *cur_col = NULL;static void *root_sym = NULL;static size_t num_sym = 0;static size_t mem_sym = 0;static void error_msg(const char *fmt, ...) __attribute__ ((noreturn, format (printf, 1, 2)));static void *xmalloc(size_t n);static char *xsymdup(const char *s); /* only allocate once... store in a tree */static void pushfile(char *filename);static void popfile(void);static void processfile(void);static int iscommentchar(int);static void eatwhitespace(void);static int next_line(void);static char *next_token(void);static void do_unrecognized(void);static col_locale_t *new_col_locale(char *name);static ll_item_t *new_ll_item(int data_type, void *data);static weight_t *register_weight(weight_t *w);static size_t ll_len(ll_item_t *l);static size_t ll_count(ll_item_t *l, int mask);static void add_wi_index(ll_item_t *l);static size_t tnumnodes(const void *root);static ll_item_t *find_wi_index(const char *sym, col_locale_t *cl);static void mark_reordered(const char *sym);static ll_item_t *find_wi_index_reordered(const char *sym);static ll_item_t *next_comm_ptr(void);static ll_item_t *init_comm_ptr(void);static ll_item_t *find_ll_last(ll_item_t *p);static void dump_weights(const char *name);static void finalize_base(void);static int is_ucode(const char *s);static int sym_cmp(const void *n1, const void *n2);static void do_starter_lists(col_locale_t *cl);static void dump_base_locale(int n);static void dump_der_locale(int n);static void dump_collate(FILE *fp);enum {	DT_SECTION = 0x01,	DT_WEIGHTED = 0x02,	DT_REORDER = 0x04,		  /* a section to support reorder_after */	DT_COL_LOCALE = 0x08,	DT_RANGE = 0x10,};static section_t *new_section(const char *name){	section_t *p;	char buf[128];	p = xmalloc(sizeof(section_t));	if (!name) {				/* anonymous section */		name = buf;		snprintf(buf, sizeof(buf), "anon%05d", anonsection);		++anonsection;	} else if (*name != '<') {	/* reorder */		name = buf;		snprintf(buf, sizeof(buf), "%s %05d", cur_col->name, anonsection);		++anonsection;	}#warning devel code/* 	fprintf(stderr, "section %s\n", name); */	p->name = xsymdup(name);	p->itm_list = NULL;	p->num_items = 0;	p->num_rules = 0;	memset(p->rules, 0, MAX_COLLATION_WEIGHTS);/* 	cur_num_weights = p->num_rules = 0; *//* 	memset(p->rules, 0, MAX_COLLATION_WEIGHTS); *//* 	memset(cur_rule, R_FORWARD, 4); */#warning devel code	if (*p->name == 'a') {		cur_num_weights = p->num_rules = 4;		memset(p->rules, R_FORWARD, 4);		memset(cur_rule, R_FORWARD, 4);		p->rules[3] |= R_POSITION;		cur_rule[3] |= R_POSITION;	}/* 	fprintf(stderr, "new section %s -- cur_num_weights = %d\n", p->name, cur_num_weights); */	return p;}static void do_order_start(void);static void do_order_end(void);static void do_reorder_after(void);static void do_reorder_end(void);static void do_reorder_sections_after(void);static void do_reorder_sections_end(void);static void do_copy(void);static void do_colsym(void);static void do_colele(void);static void do_script(void);static void do_range(void);static col_locale_t *new_col_locale(char *name);static int colitem_cmp(const void *n1, const void *n2);static int colelement_cmp(const void *n1, const void *n2);static void del_colitem(colitem_t *p);static colitem_t *new_colitem(char *item, char *def);static void add_colitem(char *item, char *def);static void add_script(const char *s);static unsigned int add_rule(weighted_item_t *wi);static unsigned int add_range_rule(range_item_t *ri);static const keyword_table_t keyword_table[] = {    { "collating-symbol", do_colsym },    { "collating-element", do_colele },	{ "script", do_script },    { "copy", do_copy },    { "order_start", do_order_start },    { "order_end", do_order_end },    { "order-end", do_order_end },    { "reorder-after", do_reorder_after },    { "reorder-end", do_reorder_end },    { "reorder-sections-after", do_reorder_sections_after },    { "reorder-sections-end", do_reorder_sections_end },	{ "UCLIBC_RANGE", do_range },    { NULL, do_unrecognized }};static void do_unrecognized(void){#if 1    error_msg("warning: unrecognized: %s", pos);#else/*     fprintf(stderr, "warning: unrecognized initial keyword \"%s\"\n", pos); */	fprintf(stderr, "warning: unrecognized: %s", pos);	if (end_of_token) {		fprintf(stderr, "%c%s", end_of_token, pos_e+1);	}	fprintf(stderr, "\n");#endif}/* typedef struct { *//* 	const char *symbol1; *//* 	const char *symbol2; *//* 	int length; *//* 	weight_t *weight; *//* } range_item_t; */static void do_range(void){	range_item_t *ri;	weight_t w;	int i;	char *s;	char *s1;	char *s2;	const char **ci;	ll_item_t *lli;	assert(!superset);	assert(order_state == IN_ORDER);	s1 = next_token();	if (!s1) {		error_msg("missing start of range");	}	if (!is_ucode(s1)) {		error_msg("start of range is not a ucode: %s", s1);	}	s1 = xsymdup(s1);	s2 = next_token();	if (!s2) {		error_msg("missing end of range");	}	if (!is_ucode(s2)) {		error_msg("end of range is not a ucode: %s", s2);	}	s2 = xsymdup(s2);	ri = (range_item_t *) xmalloc(sizeof(range_item_t));	ri->symbol1 = s1;	ri->symbol2 = s2;	ri->length = strtoul(s2+2, NULL, 16) - strtoul(s1+2, NULL, 16);	if (ri->length <= 0) {		error_msg("illegal range length %d", ri->length);	}	s = next_token();	w.num_weights = cur_num_weights;	for (i=0 ; i < cur_num_weights ; i++) {		w.rule[i] = cur_rule[i];	}	ci = w.colitem + (i-1);	/* now i == cur_num_weights */#define STR_DITTO "."	while (s && *s && i) {		--i;		if (*s == ';') {			ci[-i] = xsymdup(STR_DITTO);			if (*++s) {				continue;			}		}		if (*s) {			ci[-i] = xsymdup(s);		}		s = next_token();		if (s) {			if (*s == ';') {				++s;			} else if (i) {				error_msg("missing seperator");			}		}	}	if (s) {		error_msg("too many weights: %d %d |%s| %d", cur_num_weights, i, s, (int)*s);	}	while (i) {					/* missing weights are not an error */		--i;		ci[-i] = xsymdup(STR_DITTO);	}	ri->weight = register_weight(&w);/* 	if ((i = is_ucode(t)) != 0) { *//* 		assert(!t[i]); *//* 		add_colitem(t, NULL); *//* 	} */	lli = new_ll_item(DT_RANGE, ri);	if (!cur_section->itm_list) {/* 		printf("creating new item list: %s\n", wi->symbol); */		cur_section->itm_list = lli;		lli->prev = lli->next = lli;		++cur_section->num_items;	} else {		insque(lli, cur_section->itm_list->prev);/* 		printf("adding item to list: %d - %s\n", ll_len(cur_section->itm_list), wi->symbol); */		++cur_section->num_items;	}/* 	add_wi_index(lli); */}static weighted_item_t *add_weight(char *t){	weighted_item_t *wi;	weight_t w;	int i;	char *s;	const char **ci;	t = xsymdup(t);	s = next_token();	w.num_weights = cur_num_weights;	for (i=0 ; i < cur_num_weights ; i++) {		w.rule[i] = cur_rule[i];	}	ci = w.colitem + (i-1);	/* now i == cur_num_weights */	while (s && *s && i) {		--i;		if (*s == ';') {			ci[-i] = xsymdup(STR_DITTO);			if (*++s) {				continue;			}		}		if (*s) {			if (!strcmp(s,t)) {				s = STR_DITTO;			}			ci[-i] = xsymdup(s);		}		s = next_token();		if (s) {			if (*s == ';') {				++s;			} else if (i) {				error_msg("missing seperator");			}		}	}	if (s) {		error_msg("too many weights: %d %d |%s| %d", cur_num_weights, i, s, (int)*s);	}	while (i) {					/* missing weights are not an error */		--i;		ci[-i] = xsymdup(STR_DITTO);	}	wi = xmalloc(sizeof(weighted_item_t));	wi->symbol = t;	wi->weight = register_weight(&w);	if ((i = is_ucode(t)) != 0) {		assert(!t[i]);		add_colitem(t, NULL);	}	return wi;}static void add_superset_weight(char *t){	ll_item_t *lli;	weighted_item_t *wi;	if (!comm_cur_ptr		|| (strcmp(t, ((weighted_item_t *)(comm_cur_ptr->data))->symbol) != 0)		) {						/* now out of sync */		if (superset_in_sync) {	/* need a new section */			superset_in_sync = 0;			cur_section = new_section("R");			cur_num_weights = cur_section->num_rules				= ((section_t *)(cur_base->section_list->data))->num_rules;			memcpy(cur_rule,				   ((section_t *)(cur_base->section_list->data))->rules,				   MAX_COLLATION_WEIGHTS);			memcpy(cur_section->rules,				   ((section_t *)(cur_base->section_list->data))->rules,				   MAX_COLLATION_WEIGHTS);			insque(new_ll_item(DT_REORDER, cur_section), find_ll_last(cur_col->section_list));			assert(comm_prev_ptr);			lli = new_ll_item(DT_REORDER, cur_section);			lli->prev = lli->next = lli;			insque(lli, comm_prev_ptr);/* 			fprintf(stderr, "  subsection -----------------------\n"); */		}/* 		fprintf(stderr, "     %s   %s\n", t, ((weighted_item_t *)(comm_cur_ptr->data))->symbol); */		wi = add_weight(t);		lli = new_ll_item(DT_WEIGHTED, wi);		mark_reordered(wi->symbol);		/* 			printf("reorder: %s\n", t); */		if (!cur_section->itm_list) {			cur_section->itm_list = lli;			lli->prev = lli->next = lli;			++cur_section->num_items;		} else {			insque(lli, cur_section->itm_list->prev);			++cur_section->num_items;		}		add_wi_index(lli);	} else {					/* in sync */		superset_in_sync = 1;		next_comm_ptr();	}}static void do_weight(char *t){	weighted_item_t *wi;	ll_item_t *lli;	if (superset) {		add_superset_weight(t);		return;	}	switch(order_state) {		case 0:/* 			printf("no-order weight: %s\n", t); *//* 			break; */		case IN_ORDER:			/* in a section *//* 			printf("weight: %s\n", t); */			wi = add_weight(t);			lli = new_ll_item(DT_WEIGHTED, wi);			if (!cur_section->itm_list) {/* 				printf("creating new item list: %s\n", wi->symbol); */				cur_section->itm_list = lli;				lli->prev = lli->next = lli;				++cur_section->num_items;			} else {				insque(lli, cur_section->itm_list->prev);/* 				printf("adding item to list: %d - %s\n", ll_len(cur_section->itm_list), wi->symbol); */				++cur_section->num_items;			}			add_wi_index(lli);			break;		case IN_REORDER:			/* std rule - but in a block with an insert-after pt */			wi = add_weight(t);			lli = new_ll_item(DT_WEIGHTED, wi);			mark_reordered(wi->symbol);/* 			printf("reorder: %s\n", t); */			if (!cur_section->itm_list) {				cur_section->itm_list = lli;				lli->prev = lli->next = lli;				++cur_section->num_items;			} else {				insque(lli, cur_section->itm_list->prev);				++cur_section->num_items;			}			add_wi_index(lli);			break;		case IN_REORDER_SECTIONS:			t = xsymdup(t);			if (next_token() != NULL) {				error_msg("trailing text in reorder section item: %s", pos);			}			lli = cur_col->section_list;			do {				if (lli->data_type & DT_SECTION) {					if (!strcmp(((section_t *)(lli->data))->name, t)) {						lli->data_type = DT_REORDER;						lli = new_ll_item(DT_REORDER, (section_t *)(lli->data));						insque(lli, reorder_section_ptr);						reorder_section_ptr = lli;						return;					}				}				lli = lli->next;			} while (lli);			error_msg("reorder_sections_after for non-base item currently not supported: %s", t);/* 			fprintf(stderr, "reorder_secitons: %s\n", t); */			break;		default:			error_msg("invalid order_state %d", order_state);	}}static int col_locale_cmp(const void *n1, const void *n2){    return strcmp(((const col_locale_t *) n1)->name, ((const col_locale_t *) n2)->name);}static void processfile(void){	char *t;	const keyword_table_t *k;	order_state = 0;#warning devel code/* 	cur_num_weights = 0; *//* 	cur_num_weights = 4; *//* 	memset(cur_rule, R_FORWARD, 4); */	if (cur_col != cur_base) {		cur_col->base_locale = cur_base;		cur_col->undefined_idx = cur_base->undefined_idx;		if (!cur_base->derived_list) {			cur_base->derived_list = new_ll_item(DT_COL_LOCALE, cur_col);		} else {			insque(new_ll_item(DT_COL_LOCALE, cur_col), find_ll_last(cur_base->derived_list));		}	}	if (tfind(cur_col, &root_col_locale, col_locale_cmp)) {		error_msg("attempt to readd locale: %s", cur_col->name);	}	if (!tsearch(cur_col, &root_col_locale, col_locale_cmp)) {		error_msg("OUT OF MEMORY!");	}	if (superset) {		superset_order_start_cnt = 0;		superset_in_sync = 0;		init_comm_ptr();	}	while (next_line()) {/* 		printf("%5d:", lineno[fno]); *//* 		while ((t = next_token()) != NULL) { *//* 			printf(" |%s|", t); *//* 		printf("\n"); *//* 		} */		t = next_token();		assert(t);		assert(t == pos);		if ((*t == '<') || (!strcmp(t, "UNDEFINED"))) {			do_weight(t);		} else {			for (k = keyword_table ; k->keyword ; k++) {				if (!strcmp(k->keyword, t)) {					break;				}			}			k->handler();		}	}	if (cur_base == cur_col) {		fprintf(stderr, "Base: %15s", cur_col->name);	} else {#if 1		if (!cur_col->undefined_idx) {#if 0			if (superset) {				if (superset_order_start_cnt == 1) {					--superset_order_start_cnt;	/* ugh.. hack this */				}			}#endif			/* This is an awful hack to get around the problem of unspecified UNDEFINED			 * definitions in the supported locales derived from iso14651_t1. */			if (!strcmp(cur_base->name, "iso14651_t1")) {				fprintf(stderr, "Warning: adding UNDEFINED entry for %s\n", cur_col->name);				strcpy(linebuf, "order_start forward;backward;forward;forward,position\n");				pos_e = NULL;				pos = linebuf;				t = next_token();				assert(t);				assert(t == pos);				do_order_start();				strcpy(linebuf, "UNDEFINED IGNORE;IGNORE;IGNORE\n");				pos_e = NULL;				pos = linebuf;				t = next_token();				assert(t);				assert(t == pos);				do_weight(t);			} else {				error_msg("no definition of UNDEFINED for %s", cur_col->name);			}		}#endif		fprintf(stderr, " Der: %15s", cur_col->name);	}	{		ll_item_t *p = cur_col->section_list;		fprintf(stderr, "%6u weights", tnumnodes(cur_col->root_wi_index));		if (cur_base) {			fprintf(stderr, "  %6u der %6u reor %6u starter - %u new stubs",					tnumnodes(cur_base->root_derived_wi),					tnumnodes(cur_base->root_wi_index_reordered),					tnumnodes(cur_base->root_starter_char),					ll_count(cur_col->section_list, DT_REORDER));		}		fprintf(stderr, "\n");#if 0		while (p) {			assert(((section_t *)(p->data))->num_items ==				   ll_len(((section_t *)(p->data))->itm_list));			if (!p->next &&				((*((section_t *)(p->data))->name == 'a')				 && (((section_t *)(p->data))->num_items == 0))				) {				break;			}			if (!(p->data_type & DT_REORDER)) {				if ((*((section_t *)(p->data))->name != 'a')					|| (((section_t *)(p->data))->num_items > 0)					) {					fprintf(stderr,/* 							"\t%-15s %zu\n", */							"\t%-15s %6u\n",							((section_t *)(p->data))->name,							((section_t *)(p->data))->num_items);				}			}			p = p->next;		}#endif	}}static void print_colnode(const void *ptr, VISIT order, int level){    const colitem_t *p = *(const colitem_t **) ptr;    if (order == postorder || order == leaf)  {        printf("collating item = \"%s\"", p->string);		if (p->element) {			printf(" is %s", p->element);		}        printf("\n");    }}static void print_weight_node(const void *ptr, VISIT order, int level){    const weight_t *p = *(const weight_t **) ptr;	int i;    if (order == postorder || order == leaf)  {        printf("weight: (%d)  ", p->num_weights);		for (i = 0 ; i < p->num_weights ; i++) {			if (p->rule[i] & R_FORWARD) {				printf("F");			}			if (p->rule[i] & R_BACKWARD) {				printf("B");			}			if (p->rule[i] & R_POSITION) {				printf("P");			}			printf(",");		}		for (i = 0 ; i < p->num_weights ; i++) {			printf("   %s", p->colitem[i]);		}        printf("\n");    }}typedef struct {	const char *der_name;	int base_locale;} deps_t;enum {	BASE_iso14651_t1,	BASE_comm,	BASE_cs_CZ,	BASE_ar_SA,	BASE_th_TH,	BASE_ja_JP,	BASE_ko_KR,	BASE_MAX};static const char *base_name[] = {	"iso14651_t1",	"comm",	"cs_CZ",	"ar_SA",	"th_TH",	"ja_JP",	"ko_KR"};static ll_item_t *locale_list[BASE_MAX];static void init_locale_list(void){	int i;	for (i=0 ; i < BASE_MAX ; i++) {		locale_list[i] = (ll_item_t *) xmalloc(sizeof(ll_item_t));		locale_list[i]->prev = locale_list[i]->next = locale_list[i];		locale_list[i]->data = (void *) base_name[i];	}}deps_t deps[] = {	{ "af_ZA", BASE_iso14651_t1 },	{ "am_ET", BASE_iso14651_t1 },	{ "ar_AE", BASE_iso14651_t1 },	{ "ar_BH", BASE_iso14651_t1 },	{ "ar_DZ", BASE_iso14651_t1 },	{ "ar_EG", BASE_iso14651_t1 },	{ "ar_IN", BASE_iso14651_t1 },	{ "ar_IQ", BASE_iso14651_t1 },	{ "ar_JO", BASE_iso14651_t1 },	{ "ar_KW", BASE_iso14651_t1 },	{ "ar_LB", BASE_iso14651_t1 },	{ "ar_LY", BASE_iso14651_t1 },	{ "ar_MA", BASE_iso14651_t1 },	{ "ar_OM", BASE_iso14651_t1 },	{ "ar_QA", BASE_iso14651_t1 },	{ "ar_SA", BASE_ar_SA },	{ "ar_SD", BASE_iso14651_t1 },	{ "ar_SY", BASE_iso14651_t1 },	{ "ar_TN", BASE_iso14651_t1 },	{ "ar_YE", BASE_iso14651_t1 },	{ "az_AZ", BASE_iso14651_t1 },	{ "be_BY", BASE_iso14651_t1 },	{ "bg_BG", BASE_iso14651_t1 },	{ "bn_BD", BASE_iso14651_t1 },	{ "bn_IN", BASE_iso14651_t1 },	{ "br_FR", BASE_iso14651_t1 },	{ "bs_BA", BASE_iso14651_t1 },	{ "ca_ES", BASE_comm },	{ "cs_CZ", BASE_cs_CZ },	{ "cy_GB", BASE_iso14651_t1 },	{ "da_DK", BASE_comm },	{ "de_AT", BASE_iso14651_t1 },	{ "de_BE", BASE_iso14651_t1 },	{ "de_CH", BASE_iso14651_t1 },	{ "de_DE", BASE_iso14651_t1 },	{ "de_LU", BASE_iso14651_t1 },	{ "el_GR", BASE_iso14651_t1 },	{ "en_AU", BASE_iso14651_t1 },	{ "en_BW", BASE_iso14651_t1 },	{ "en_CA", BASE_comm },	{ "en_DK", BASE_iso14651_t1 },	{ "en_GB", BASE_iso14651_t1 },	{ "en_HK", BASE_iso14651_t1 },	{ "en_IE", BASE_iso14651_t1 },	{ "en_IN", BASE_iso14651_t1 },	{ "en_NZ", BASE_iso14651_t1 },	{ "en_PH", BASE_iso14651_t1 },	{ "en_SG", BASE_iso14651_t1 },	{ "en_US", BASE_iso14651_t1 },	{ "en_ZA", BASE_iso14651_t1 },	{ "en_ZW", BASE_iso14651_t1 },	{ "eo_EO", BASE_iso14651_t1 },	{ "es_AR", BASE_comm },	{ "es_BO", BASE_comm },	{ "es_CL", BASE_comm },	{ "es_CO", BASE_comm },	{ "es_CR", BASE_comm },	{ "es_DO", BASE_comm },	{ "es_EC", BASE_comm },	{ "es_ES", BASE_comm },	{ "es_GT", BASE_comm },	{ "es_HN", BASE_comm },	{ "es_MX", BASE_comm },	{ "es_NI", BASE_comm },	{ "es_PA", BASE_comm },	{ "es_PE", BASE_comm },	{ "es_PR", BASE_comm },	{ "es_PY", BASE_comm },	{ "es_SV", BASE_comm },	{ "es_US", BASE_comm },	{ "es_UY", BASE_comm },	{ "es_VE", BASE_comm },	{ "et_EE", BASE_comm },	{ "eu_ES", BASE_iso14651_t1 },	{ "fa_IR", BASE_iso14651_t1 },	{ "fi_FI", BASE_comm },	{ "fo_FO", BASE_comm },	{ "fr_BE", BASE_iso14651_t1 },	{ "fr_CA", BASE_comm },	{ "fr_CH", BASE_iso14651_t1 },	{ "fr_FR", BASE_iso14651_t1 },	{ "fr_LU", BASE_iso14651_t1 },	{ "ga_IE", BASE_iso14651_t1 },	{ "gd_GB", BASE_iso14651_t1 },	{ "gl_ES", BASE_comm },	{ "gv_GB", BASE_iso14651_t1 },	{ "he_IL", BASE_iso14651_t1 },	{ "hi_IN", BASE_iso14651_t1 },	{ "hr_HR", BASE_comm },	{ "hu_HU", BASE_iso14651_t1 },	{ "hy_AM", BASE_iso14651_t1 },	{ "id_ID", BASE_iso14651_t1 },	{ "is_IS", BASE_comm },	{ "it_CH", BASE_iso14651_t1 },	{ "it_IT", BASE_iso14651_t1 },	{ "iw_IL", BASE_iso14651_t1 },	{ "ja_JP", BASE_ja_JP },	{ "ka_GE", BASE_iso14651_t1 },	{ "kl_GL", BASE_comm },	{ "ko_KR", BASE_ko_KR },	{ "kw_GB", BASE_iso14651_t1 },	{ "lt_LT", BASE_comm },	{ "lv_LV", BASE_comm },	{ "mi_NZ", BASE_iso14651_t1 },	{ "mk_MK", BASE_iso14651_t1 },	{ "mr_IN", BASE_iso14651_t1 },	{ "ms_MY", BASE_iso14651_t1 },	{ "mt_MT", BASE_iso14651_t1 },	{ "nl_BE", BASE_iso14651_t1 },	{ "nl_NL", BASE_iso14651_t1 },	{ "nn_NO", BASE_iso14651_t1 },	{ "no_NO", BASE_comm },	{ "oc_FR", BASE_iso14651_t1 },	{ "pl_PL", BASE_comm },	{ "pt_BR", BASE_iso14651_t1 },	{ "pt_PT", BASE_iso14651_t1 },	{ "ro_RO", BASE_iso14651_t1 },	{ "ru_RU", BASE_iso14651_t1 },	{ "ru_UA", BASE_iso14651_t1 },	{ "se_NO", BASE_iso14651_t1 },	{ "sk_SK", BASE_cs_CZ },	{ "sl_SI", BASE_comm },	{ "sq_AL", BASE_iso14651_t1 },	{ "sr_YU", BASE_iso14651_t1 },	{ "sv_FI", BASE_comm },	{ "sv_SE", BASE_iso14651_t1 },	{ "ta_IN", BASE_iso14651_t1 },	{ "te_IN", BASE_iso14651_t1 },	{ "tg_TJ", BASE_iso14651_t1 },	{ "th_TH", BASE_th_TH },	{ "ti_ER", BASE_iso14651_t1 },	{ "ti_ET", BASE_iso14651_t1 },	{ "tl_PH", BASE_iso14651_t1 },	{ "tr_TR", BASE_comm },	{ "tt_RU", BASE_iso14651_t1 },	{ "uk_UA", BASE_iso14651_t1 },	{ "ur_PK", BASE_iso14651_t1 },	{ "uz_UZ", BASE_iso14651_t1 },	{ "vi_VN", BASE_iso14651_t1 },	{ "wa_BE", BASE_iso14651_t1 },	{ "yi_US", BASE_iso14651_t1 },	{ "zh_CN", BASE_iso14651_t1 },	{ "zh_HK", BASE_iso14651_t1 },	{ "zh_SG", BASE_iso14651_t1 },	{ "zh_TW", BASE_iso14651_t1 },};static int der_count[BASE_MAX];static const char *new_args[500];static int new_arg_count;static int dep_cmp(const void *s1, const void *s2){	return strcmp( (const char *) s1, ((const deps_t *) s2)->der_name);}static int old_main(int argc, char **argv);int main(int argc, char **argv){	const deps_t *p;	ll_item_t *lli;	int i;	int total;	if (argc < 2) {		return EXIT_FAILURE;	}	init_locale_list();		while (--argc) {		p = (const deps_t *) bsearch(*++argv, deps, sizeof(deps)/sizeof(deps[0]), sizeof(deps[0]), dep_cmp);		if (!p) {			if (!strcmp("C", *argv)) {				printf("ignoring C locale\n");				continue;			} else {				printf("%s not found\n", *argv);				return EXIT_FAILURE;			}		}			i = p->base_locale;		++der_count[i];		if (!strcmp(base_name[i], *argv)) {			/* same name as base, so skip after count incremented */			continue;		}				/* add it to the list.  the main body will catch duplicates */		lli = (ll_item_t *) xmalloc(sizeof(ll_item_t));		lli->prev = lli->next = NULL;		lli->data = (void *) *argv;		insque(lli, locale_list[i]);	}	total = 0;	for (i=0 ; i < BASE_MAX ; i++) {/* 		printf("der_count[%2d] = %3d\n", i, der_count[i]); */		total += der_count[i];	}/* 	printf("total = %d\n", total); */	new_args[new_arg_count++] = "dummyprogramname";	for (i=0 ; i < BASE_MAX ; i++) {		if (!der_count[i]) {			continue;		}		new_args[new_arg_count++] = (i == BASE_comm) ? "-c" : "-b";		lli = locale_list[i];		do {			new_args[new_arg_count++] = (const char *) (lli->data);			lli = lli->next;		} while (lli != locale_list[i]);		new_args[new_arg_count++] = "-f";	}/* 	for (i=0 ; i < new_arg_count ; i++) { *//* 		printf("%3d: %s\n", i, new_args[i]); *//* 	} */	return old_main(new_arg_count, (char **) new_args);}/* usage...  prog -b basefile derived {derived} -s single {single} */static int old_main(int argc, char **argv){	int next_is_base = 0;	int next_is_subset = 0;	superset = 0;	while (--argc) {		++argv;		if (**argv == '-') {			if ((*argv)[1] == 'd') {				dump_weights((*argv) + 2);			} else if ((*argv)[1] == 'f') {	/* dump all weight rules */				finalize_base();			} else if ((*argv)[1] == 'R') {	/* dump all weight rules */				twalk(root_weight, print_weight_node);			} else if (((*argv)[1] == 'c') && !(*argv)[2]) { /* new common subset */				cur_base = cur_derived = NULL;				next_is_subset = 1;				next_is_base = 1;				superset = 0;			} else if (((*argv)[1] == 'b') && !(*argv)[2]) { /* new base locale */				cur_base = cur_derived = NULL;				next_is_subset = 0;				next_is_base = 1;				superset = 0;			} else if (((*argv)[1] == 's') && !(*argv)[2]) { /* single locales follow */				cur_base = cur_derived = NULL;				next_is_subset = 0;				next_is_base = 2;				superset = 0;			} else {				error_msg("unrecognized option %s", *argv);			}			continue;		}		/* new file */		new_col_locale(*argv);	/* automaticly sets cur_col */		if (next_is_base) {			cur_base = cur_col;		} else {			cur_derived = cur_col;		}		pushfile(*argv);/* 		fprintf(stderr, "processing file %s\n", *argv); */		processfile();			/* this does a popfile *//* 		twalk(cur_col->root_colitem, print_colnode); */				if (next_is_base == 1) {			next_is_base = 0;		}		if (next_is_subset) {			next_is_subset = 0;			superset = 1;		}	}	fprintf(stderr, "success!\n");	fprintf(stderr,/* 			"num_sym=%zu mem_sym=%zu  unique_weights=%zu\n", */			"num_sym=%u mem_sym=%u  unique_weights=%u\n",			num_sym, mem_sym, unique_weights);/* 	twalk(root_weight, print_weight_node); */	fprintf(stderr, "num base locales = %d    num derived locales = %d\n",			base_locale_len, der_locale_len);	fprintf(stderr,			"override_len = %d      multistart_len = %d    weightstr_len = %d\n"			"wcs2colidt_len = %d    index2weight_len = %d  index2ruleidx_len = %d\n"			"ruletable_len = %d\n"			"total size is %d bytes or %d kB\n",			override_len, multistart_len, weightstr_len,			wcs2colidt_len, index2weight_len, index2ruleidx_len,			ruletable_len,#warning mult by 2 for rule indecies			(override_len + multistart_len + weightstr_len			 + wcs2colidt_len + index2weight_len + index2ruleidx_len + ruletable_len) * 2,			(override_len + multistart_len + weightstr_len			 + wcs2colidt_len + index2weight_len + index2ruleidx_len + ruletable_len + 511) / 512);#if 0	{		int i;		for (i=0 ; i < base_locale_len ; i++) {			dump_base_locale(i);		}		for (i=0 ; i < der_locale_len ; i++) {			dump_der_locale(i);		}	}#endif	{		FILE *fp = fopen("locale_collate.h", "w");		if (!fp) {			error_msg("couldn't open output file!");		}		dump_collate(fp);		if (ferror(fp) || fclose(fp)) {			error_msg("write error or close error for output file!\n");		}	}    return EXIT_SUCCESS;}static void error_msg(const char *fmt, ...) {	va_list arg;	fprintf(stderr, "Error: ");	if (fno >= 0) {	    fprintf(stderr, "file %s (%d): ", fname[fno], lineno[fno]);	}	va_start(arg, fmt);	vfprintf(stderr, fmt, arg);	va_end(arg);	fprintf(stderr, "\n");	exit(EXIT_FAILURE);}static void pushfile(char *filename){	static fbuf[PATH_MAX];	snprintf(fbuf, PATH_MAX, "collation/%s", filename);	if (fno >= MAX_FNO) {		error_msg("file stack size exceeded");	}					  	if (!(fstack[++fno] = fopen(fbuf, "r"))) {		--fno;					/* oops */		error_msg("cannot open file %s", fbuf);	}	fname[fno] = xsymdup(filename);	lineno[fno] = 0;}static void popfile(void){	if (fno < 0) {		error_msg("pop on empty file stack");	}/* 	free(fname[fno]); */	fclose(fstack[fno]);	--fno;}static void eatwhitespace(void){	while (isspace(*pos)) {		++pos;	}}static int iscommentchar(int c){	return ((c == '#') || (c == '%'));}static int next_line(void){	size_t n;	char *s = linebuf;	assert(fno >= 0);	pos_e = NULL;	do {		if (fgets(s, sizeof(linebuf), fstack[fno]) != NULL) {			++lineno[fno];			n = strlen(linebuf);			if ((n == sizeof(linebuf) - 1) && (linebuf[n-1] != '\n')) {				/* Either line is too long or last line is very long with				 * no trailing newline.  But we'll always treat it as an				 * errro. */				error_msg("line too long?");			}			--n;			/* Be careful... last line doesn't need a newline. */			if (linebuf[n] == '\n') {				linebuf[n--] = 0;	/* trim trailing newline */			}			pos = linebuf;			eatwhitespace();			if (*pos && !iscommentchar(*pos)) { /* not empty or comment line */				return 1;		/* got a line */			}		} else {				/* eof */			popfile();		}	} while (fno >= 0);	return 0;}static char *next_token(void){	char *p;#if 0	if (pos_e == NULL) {		return NULL		pos = pos_e;		*pos = end_of_token;		end_of_token = 0;	}#else	if (pos_e != NULL) {		pos = pos_e;		*pos = end_of_token;		end_of_token = 0;	}#endif	eatwhitespace();	p = pos;	if (!*p || iscommentchar(*p)) {	/* end of line or start of comment */		pos = pos_e = NULL;		*p = 0;					/* treat comment as end of line *//* 		fprintf(stdout, "returning NUL token |%s|\n", pos); */		return NULL;#if 1	} else if (*p == '<') {	 /* collating symbol, element, or value */		while (*++p) {			if ((*p == '/') && p[1]) {				++p;				continue;			}			if (*p == '>') {				pos_e = ++p;				end_of_token = *p;				*p = 0;/* 				fprintf(stdout, "returning col token |%s|\n", pos); */				return pos;			}		}	} else if (*p == '"') {		/* collating element value? */		while (*++p) {			if (*p == '"') {	/* found the end of the quoted string */				pos_e = ++p;				end_of_token = *p;				*p = 0;/* 				fprintf(stdout, "returning quote token |%s|\n", pos); */				return pos;			}		}#endif	} else {					/* some kind of keyword */		while (*++p) {			if (isspace(*p) || (*p == ';')) {				break;			}		}		pos_e = p;		end_of_token = *p;		*p = 0;/* 		fprintf(stdout, "returning key token |%s|\n", pos); */		return pos;	}	error_msg("illegal token |%s|", pos);}static void *xmalloc(size_t n){	void *p;	if (!(p = malloc(n))) {		error_msg("OUT OF MEMORY");	}	return p;}static void do_copy(void){	char *s;	char *e;	if ((s = next_token()) != NULL) {		e = strchr(s + 1, '"');		if ((*s == '"') && e && (*e == '"') && !e[1]) {			if (next_token() != NULL) {				error_msg("illegal trailing text: %s", pos);			}			*e = 0;			++s;			if (cur_base && !strcmp(cur_base->name,s)) {/* 				fprintf(stderr, "skipping copy of base file %s\n", s); */#warning need to update last in order and position or check				return;			}/* 			fprintf(stderr, "full copy of %s\n", s); */			pushfile(s);			return;		}	}	error_msg("illegal or missing arg for copy: %s", s);}static void do_colsym(void){	char *s;	char *e;	if ((s = next_token()) != NULL) {		e = strrchr(s,'>');		if ((*s == '<') && e && (*e == '>') && !e[1]) {			if (next_token() != NULL) {				error_msg("illegal trailing text: %s", pos);			}			e[1] = 0; /* cleanup in case next_token stored something */			add_colitem(s,NULL);			return;		}	}	error_msg("illegal or missing arg for collating-symbol: %s", s);}static void do_colele(void){	char *s;	char *e;	char *s1;	char *e1;	int n;	if ((s = next_token()) != NULL) {		e = strrchr(s,'>');		if ((*s == '<') && e && (*e == '>') && !e[1]) {			if (((s1 = next_token()) == NULL)				|| (strcmp(s1,"from") != 0)				|| ((s1 = next_token()) == NULL)				|| (*s1 != '\"')				) {				error_msg("illegal format for collating-element spec");			}			e1 = strchr(s1 + 1, '"');			if ((*s1 != '"') || !e1 || (*e1 != '"') || (e1[1] != 0)) {				error_msg("illegal definition for collating-element: %s", s1);			}			if (next_token() != NULL) {				error_msg("illegal trailing text: %s", pos);			}			e[1] = 0; /* cleanup in case next_token stored something */			e1[1] = 0;			add_colitem(s,s1);			++s1;			if (!(n = is_ucode(s1))) {				error_msg("starting char must be a <U####> code: %s", s1);			}			assert(s1[n] == '<');			s1[n] = 0;			s = xsymdup(s1);			if (!(tsearch(s, &cur_base->root_starter_char, sym_cmp))) {				error_msg("OUT OF MEMORY");			}			return;		}	}	error_msg("illegal or missing arg for collating-element: %s", s);}static ll_item_t *find_section_list_item(const char *name, col_locale_t *loc){	ll_item_t *p;	if (!loc) {		return NULL;	}	p = loc->section_list;	while (p) {#warning devel code/* 		if (!((p->data_type == DT_SECTION) || (p->data_type == DT_REORDER))) { *//* 			fprintf(stderr, "fsli = %d\n", p->data_type); *//* 		} */		assert((p->data_type == DT_SECTION) || (p->data_type == DT_REORDER));		if (!strcmp(name, ((section_t *)(p->data))->name)) {			break;		}		p = p->next;	}	return p;}static ll_item_t *find_ll_last(ll_item_t *p){	assert(p);	while (p->next) {		p = p->next;	}	return p;}static void do_script(void){	char *s;	char *e;	if ((s = next_token()) != NULL) {		e = strrchr(s,'>');		if ((*s == '<') && e && (*e == '>') && !e[1]) {			if (next_token() != NULL) {				error_msg("illegal trailing text: %s", pos);			}			e[1] = 0; /* cleanup in case next_token stored something */			add_script(s);			return;		}	}	error_msg("illegal or missing arg for script: %s", s);}static col_locale_t *new_col_locale(char *name){	ll_item_t *lli;	ll_item_t *lli2;	cur_col = (col_locale_t *) xmalloc(sizeof(col_locale_t));	cur_col->name = name;	cur_col->root_colitem = NULL;	cur_col->root_element = NULL;	cur_col->root_scripts = NULL;	cur_col->base_locale = NULL;	if (!superset) {		/* start with an anonymous section */		cur_section = new_section(NULL);		cur_col->section_list = new_ll_item(DT_SECTION, cur_section);	} else {		/* start with a reorder section */		cur_section = new_section("R");		cur_num_weights = cur_section->num_rules			= ((section_t *)(cur_base->section_list->data))->num_rules;		memcpy(cur_rule,			   ((section_t *)(cur_base->section_list->data))->rules,			   MAX_COLLATION_WEIGHTS);		memcpy(cur_section->rules,			   ((section_t *)(cur_base->section_list->data))->rules,			   MAX_COLLATION_WEIGHTS);		cur_col->section_list = new_ll_item(DT_REORDER, cur_section);		assert(cur_base->section_list->next == NULL); /* currently only one section allowed */		lli = ((section_t *)(cur_base->section_list->data))->itm_list;		assert(lli);		lli2 = new_ll_item(DT_REORDER, cur_section);		lli2->prev = lli2->next = lli2;		insque(lli2, lli->prev);		((section_t *)(cur_base->section_list->data))->itm_list = lli2;	}/* 	cur_col->section_list = NULL; *//* 	add_script(((section_t *)(cur_col->section_list->data))->name); */	cur_col->root_wi_index = NULL;	cur_col->root_wi_index_reordered = NULL;	cur_col->root_derived_wi = NULL;	cur_col->derived_list = NULL;	cur_col->root_starter_char = NULL;	cur_col->root_starter_all = NULL;	cur_col->undefined_idx = NULL;	return cur_col;}static int colitem_cmp(const void *n1, const void *n2){    return strcmp(((colitem_t *)n1)->string, ((colitem_t *)n2)->string);}static int colelement_cmp(const void *n1, const void *n2){    int r;    r = strcmp(((colitem_t *)n1)->string, ((colitem_t *)n2)->string);    if (!r) {		if (((colitem_t *)n1)->element && ((colitem_t *)n2)->element) {			r = strcmp(((colitem_t *)n1)->element, ((colitem_t *)n2)->element);		} else if (((colitem_t *)n1)->element == ((colitem_t *)n2)->element) {			r = 0;				/* both null */		} else {			r = (((colitem_t *)n1)->element == NULL) ? -1 : 1;		}     }    return r;}static void del_colitem(colitem_t *p){/*     free((void *) p->element); *//*     free((void *) p->string); */    free(p);}static colitem_t *new_colitem(char *item, char *def){	colitem_t *p;	p = xmalloc(sizeof(colitem_t));	p->string = xsymdup(item);	p->element = (!def) ? def : xsymdup(def);	return p;}static void add_colitem(char *item, char *def){	colitem_t *p;#if 0	printf("adding collation item %s", item);	if (def) {		printf(" with definition %s", def);	}	printf("\n");#endif	p = new_colitem(item, def);#warning devel code	if (superset) {		if (tfind(p, &cur_base->root_colitem, colitem_cmp)) {/* 			fprintf(stderr, "skipping superset duplicate collating item \"%s\"\n", p->string); */			del_colitem(p);			return;/* 		} else { *//* 			fprintf(stderr, "superset: new collating item \"%s\" = %s\n", p->string, p->element); */		}	}	if (cur_col == cur_derived) {		if (!tfind(p, &cur_base->root_colitem, colitem_cmp)) {			/* not in current but could be in base */			if (!tsearch(p, &cur_base->root_colitem, colitem_cmp)) {				error_msg("OUT OF MEMORY!");			}		} else if (!tfind(p,  &cur_base->root_colitem, colelement_cmp)) {			error_msg("collating element/symbol mismatch: item=%s def=%s", item, def);		}	}	if (!tfind(p, &cur_col->root_colitem, colitem_cmp)) {		/* not in current but could be in base */		if (!tsearch(p, &cur_col->root_colitem, colitem_cmp)) {			error_msg("OUT OF MEMORY!");		}	} else if (!tfind(p,  &cur_col->root_colitem, colelement_cmp)) {		error_msg("collating element/symbol mismatch");	} else {					/* already there */		fprintf(stderr, "duplicate collating item \"%s\"\n", p->string);		del_colitem(p);	}}/* add a script (section) to the current locale */static void add_script(const char *s){	ll_item_t *l;	/* make sure it isn't in base if working with derived */	if (cur_base != cur_col) {		if (find_section_list_item(s, cur_base)) {			error_msg("attempt to add script %s for derived when already in base", s);		}	}	if (find_section_list_item(s, cur_col)) {		error_msg("attempt to readd script %s", s);	}		l = find_ll_last(cur_col->section_list);	insque(new_ll_item(DT_SECTION, new_section(s)), l);}static const char str_forward[] =  "forward";static const char str_backward[] = "backward";static const char str_position[] = "position";static void do_order_start(void){	const char *s;	char *e;	ll_item_t *l;	section_t *sect;	int rule;	if (order_state & ~IN_ORDER) {		error_msg("order_start following reorder{_sections}_after");	}	order_state |= IN_ORDER;	if (superset) {		if (++superset_order_start_cnt > 1) {			error_msg("currently only a common order_start is supported in superset");		}		return;	}	if (!(s = next_token())) {		s = str_forward;		/* if no args */	}	if (*s == '<') {		/* section (script) */		e = strrchr(s,'>');		if ((*s == '<') && e && (*e == '>') && !e[1]) {			e[1] = 0; /* cleanup in case next_token stored something */			if (!(l = find_section_list_item(s, cur_col))) {				error_msg("ref of undefined sections: %s", s);			}			sect = (section_t *)(l->data);			if (sect->num_rules) {				error_msg("sections already defined: %s", s);			}		} else {			error_msg("illegal section ref: %s", s);		}		if (!(s = next_token())) {			s = str_forward;		/* if no args */		} else if (*s != ';') {			error_msg("missing seperator!");		}	} else {					/* need an anonymous section */		if ((*cur_section->name != '<') && (cur_section->num_items == 0)) { /* already in an empty anonymous section */			sect = cur_section;		} else {			sect = new_section(NULL);			l = find_ll_last(cur_col->section_list);			insque(new_ll_item(DT_SECTION, new_section(s)), l);		}		sect->num_rules = 0;	/* setting this below so nix default */	}	cur_section = sect;#warning need to add section to weight list?	/* now do rules */	do {		rule = 0;		if (*s == ';') {			++s;		}		while (*s) {			if (!strncmp(str_forward, s, 7)) {				rule |= R_FORWARD;				s += 7;			} else if (!strncmp(str_backward, s, 8)) {				rule |= R_BACKWARD;				s += 8;			} else if (!strncmp(str_position, s, 8)) {				rule |= R_POSITION;				s += 8;			}			if (*s == ',') {				++s;				continue;			}			if (!*s || (*s == ';')) {				if (sect->num_rules >= MAX_COLLATION_WEIGHTS) {					error_msg("more than %d weight rules!", MAX_COLLATION_WEIGHTS);				}				if (!rule) {					error_msg("missing weight rule!");				}				if ((rule & (R_FORWARD|R_BACKWARD|R_POSITION)) > R_BACKWARD) {					error_msg("backward paired with  forward and/or position!");				}				sect->rules[sect->num_rules++] = rule;				rule = 0;				continue;			}			error_msg("illegal weight rule: %s", s);		}	} while ((s = next_token()) != NULL);	cur_section = sect;/* 	fprintf(stderr, "setting cur_num_weights to %d for %s\n", sect->num_rules, sect->name); */	cur_num_weights = sect->num_rules;	memcpy(cur_rule, sect->rules, MAX_COLLATION_WEIGHTS);}static void do_order_end(void){	if (!(order_state & IN_ORDER)) {		error_msg("order_end with no matching order_start");	}	order_state &= ~IN_ORDER;	cur_section = new_section(NULL);}static void do_reorder_after(void){	char *t;	ll_item_t *lli;	const weight_t *w;	int save_cur_num_weights;	char save_cur_rule[MAX_COLLATION_WEIGHTS];	if (order_state & ~IN_REORDER) {		error_msg("reorder_after following order_start or reorder_sections_after");	}	order_state |= IN_REORDER;	if (superset) {		error_msg("currently reorder_after is not supported in supersets");	}#warning have to use rule for current section!!!	if (!(t = next_token())) {		error_msg("missing arg for reorder_after");	}	t = xsymdup(t);	if (next_token() != NULL) {		error_msg("trailing text reorder_after: %s", pos);	}	if (cur_col == cur_base) {		error_msg("sorry.. reorder_after in base locale is not currently supported");	}	if (!(lli = find_wi_index(t, cur_base))) {		error_msg("reorder_after for non-base item currently not supported: %s", t);	}	w = ((weighted_item_t *)(lli->data))->weight;	save_cur_num_weights = cur_num_weights;	memcpy(save_cur_rule, cur_rule, MAX_COLLATION_WEIGHTS);	cur_section = new_section("R");	insque(new_ll_item(DT_REORDER, cur_section), lli);#if 0	{		ll_item_t *l1;		ll_item_t *l2;		ll_item_t *l3;		l1 = new_ll_item(DT_REORDER, cur_section);		l2 = find_ll_last(cur_col->section_list);		insque(l1, l2);		l3 = find_ll_last(cur_col->section_list);		fprintf(stderr, "reorder_after %p %p %p %s\n", l1, l2, l3, cur_section->name);	}#else	insque(new_ll_item(DT_REORDER, cur_section), find_ll_last(cur_col->section_list));#endif	cur_num_weights = cur_section->num_rules = save_cur_num_weights;	memcpy(cur_rule, save_cur_rule, MAX_COLLATION_WEIGHTS);	memcpy(cur_section->rules, save_cur_rule, MAX_COLLATION_WEIGHTS);#warning devel code/* 	fprintf(stderr, "reorder -- %s %d\n", ((weighted_item_t *)(lli->data))->symbol, w->num_weights); */#warning hack to get around hu_HU reorder-after problem/* 	if (!w->num_weights) { *//* 	} else { *//* 		cur_num_weights = w->num_weights; *//* 		memcpy(cur_rule, w->rule, MAX_COLLATION_WEIGHTS); *//* 	}	 *//* 	fprintf(stderr, "reorder_after succeeded for %s\n", t); */}static void do_reorder_end(void){	if (!(order_state & IN_REORDER)) {		error_msg("reorder_end with no matching reorder_after");	}	order_state &= ~IN_REORDER;}static void do_reorder_sections_after(void){	const char *t;	ll_item_t *lli;	if (order_state & ~IN_REORDER_SECTIONS) {		error_msg("reorder_sections_after following order_start or reorder_after");	}	order_state |= IN_REORDER_SECTIONS;	if (superset) {		error_msg("currently reorder_sections_after is not supported in supersets");	}	if (!(t = next_token())) {		error_msg("missing arg for reorder_sections_after");	}	t = xsymdup(t);	if (next_token() != NULL) {		error_msg("trailing text reorder_sections_after: %s", pos);	}	if (cur_col == cur_base) {		error_msg("sorry.. reorder_sections_after in base locale is not currently supported");	}	lli = cur_base->section_list;	do {/* 		fprintf(stderr, "hmm -- |%s|%d|\n", ((section_t *)(lli->data))->name, lli->data_type); */		if (lli->data_type & DT_SECTION) {/* 			fprintf(stderr, "checking |%s|%s|\n", ((section_t *)(lli->data))->name, t); */			if (!strcmp(((section_t *)(lli->data))->name, t)) {				reorder_section_ptr = lli;				return;			}		}		lli = lli->next;	} while (lli);	error_msg("reorder_sections_after for non-base item currently not supported: %s", t);}static void do_reorder_sections_end(void){	if (!(order_state & IN_REORDER_SECTIONS)) {		error_msg("reorder_sections_end with no matching reorder_sections_after");	}	order_state &= ~IN_REORDER_SECTIONS;	reorder_section_ptr = NULL;}static ll_item_t *new_ll_item(int data_type, void *data){	ll_item_t *p;	p = xmalloc(sizeof(ll_item_t));	p->next = p->prev = NULL;	p->data_type = data_type;	p->data = data;	p->idx = INT_MIN;	return p;}static int sym_cmp(const void *n1, const void *n2){/* 	fprintf(stderr, "sym_cmp: |%s| |%s|\n", (const char *)n1, (const char *)n2); */    return strcmp((const char *) n1, (const char *) n2);}static char *xsymdup(const char *s){	void *p;	if (!(p = tfind(s, &root_sym, sym_cmp))) { /* not a currently known symbol */		if (!(s = strdup(s)) || !(p = tsearch(s, &root_sym, sym_cmp))) {			error_msg("OUT OF MEMORY!");		}		++num_sym;		mem_sym += strlen(s) + 1;/* 		fprintf(stderr, "xsymdup: alloc |%s| %p |%s| %p\n", *(char **)p, p, s, s); *//* 	} else { *//* 		fprintf(stderr, "xsymdup: found |%s| %p\n", *(char **)p, p); */	}	return *(char **) p;}static int weight_cmp(const void *n1, const void *n2){	const weight_t *w1 = (const weight_t *) n1;	const weight_t *w2 = (const weight_t *) n2;	int i, r;	if (w1->num_weights != w2->num_weights) {		return w1->num_weights - w2->num_weights;	}	for (i=0 ; i < w1->num_weights ; i++) {		if (w1->rule[i] != w2->rule[i]) {			return w1->rule[i] - w2->rule[i];		}		if ((r = strcmp(w1->colitem[i], w2->colitem[i])) != 0) {			return r;		}	}	return 0;}static weight_t *register_weight(weight_t *w){	void *p;	if (!(p = tfind(w, &root_weight, weight_cmp))) { /* new weight */		p = xmalloc(sizeof(weight_t));		memcpy(p, w, sizeof(weight_t));		if (!(p = tsearch(p, &root_weight, weight_cmp))) {			error_msg("OUT OF MEMORY!");		}		++unique_weights;/* 	} else { *//* 		fprintf(stderr, "rw: found\n"); */	}	return *(weight_t **)p;}static size_t ll_len(ll_item_t *l){	size_t n = 0;	ll_item_t *p = l;	while (p) {		++n;		p = p->next;		if (p == l) {			/* work for circular too */			break;		}	}	return n;}static size_t ll_count(ll_item_t *l, int mask){	size_t n = 0;	ll_item_t *p = l;	while (p) {		if (p->data_type & mask) {			++n;		}		p = p->next;		if (p == l) {			/* work for circular too */			break;		}	}	return n;}static int wi_index_cmp(const void *n1, const void *n2){	const char *s1 = ((weighted_item_t *)(((ll_item_t *) n1)->data))->symbol;	const char *s2 = ((weighted_item_t *)(((ll_item_t *) n2)->data))->symbol;    return strcmp(s1, s2);}static void add_wi_index(ll_item_t *l){	assert(l->data_type == DT_WEIGHTED);	if (!strcmp(((weighted_item_t *)(l->data))->symbol, "UNDEFINED")) {		cur_col->undefined_idx = l;	}	if (!tfind(l, &cur_col->root_wi_index, wi_index_cmp)) { /* new wi_index */		if (!tsearch(l, &cur_col->root_wi_index, wi_index_cmp)) {			error_msg("OUT OF MEMORY!");		}	}	if (cur_base != cur_col) {		if (!tfind(l, &cur_base->root_wi_index, wi_index_cmp)) {/* not a base val *//* 			printf("derived: %s\n", ((weighted_item_t *)(l->data))->symbol); */			if (!tfind(l, &cur_base->root_derived_wi, wi_index_cmp)) { /* new derived */				if (!tsearch(l, &cur_base->root_derived_wi, wi_index_cmp)) {					error_msg("OUT OF MEMORY!");				}			}		}	}}static int final_index;static int is_ucode(const char *s){	if ((s[0] == '<')		&& (s[1] == 'U')		&& isxdigit(s[2])		&& isxdigit(s[3])		&& isxdigit(s[4])		&& isxdigit(s[5])		&& (s[6] == '>')		) {		return 7;	} else {		return 0;	}}static void add_final_col_index(const char *s){	ENTRY e;	e.key = (char *) s;	e.data = (void *)(final_index);	if (!hsearch(e, FIND)) {	/* not in the table */		if (!hsearch(e, ENTER)) {			error_msg("OUT OF MEMORY! (hsearch)");		}#if 0		{			int n;			void *v;			colitem_t ci;			colitem_t *p;			const char *t;			if (!strcmp(s, "UNDEFINED")) {				printf("%6d: %s\n", final_index, s);			} else {				assert(*s == '<');				if ((n = is_ucode(s)) != 0) {					assert(!s[n]);					printf("%6d: %s\n", final_index, s);				} else {					ci.string = (char *) s;					ci.element = NULL; /* don't care */					v = tfind(&ci, &cur_base->root_colitem, colitem_cmp);					if (!v) {						fprintf(stderr, "%s  NOT DEFINED!!!\n", s);					} else {						p = *((colitem_t **) v);						if (p->element != NULL) {							t = p->element;							assert(*t == '"');							++t;							n = is_ucode(t);							assert(n);							printf("%6d: %.*s | ", final_index, n, t);							do {								t += n;								assert(*t);								if (*t == '"') {									assert(!t[1]);									break;								}								n = is_ucode(t);								assert(n);								printf("%.*s", n, t);							} while (1);							printf("   collating-element %s\n", s);						} else {							printf("%6d: %s  (collating-symbol)\n", final_index, s);						}					}				}			}		}#endif		++final_index;	}}static int final_index_val0(const char *s){	ENTRY *p;	ENTRY e;	e.key = (char *) s;	if (!(p = hsearch(e, FIND))) {	/* not in the table */		return 0;	}	return (int)(p->data);}static int final_index_val(const char *s){	ENTRY *p;	ENTRY e;	e.key = (char *) s;	if (!(p = hsearch(e, FIND))) {	/* not in the table */		error_msg("can't find final index: %s", s);	}	return (int)(p->data);}static size_t num_tree_nodes;static void count_nodes(const void *ptr, VISIT order, int level){    if ((order == postorder) || (order == leaf))  {		++num_tree_nodes;    }}static size_t tnumnodes(const void *root){	num_tree_nodes = 0;	twalk(root, count_nodes);	return num_tree_nodes;}static ll_item_t *find_wi_index(const char *sym, col_locale_t *cl){	weighted_item_t w;	ll_item_t l;	void *p;	w.symbol = sym;	l.data = &w;	l.data_type = DT_WEIGHTED;	p = tfind(&l, &cl->root_wi_index, wi_index_cmp);	if (p) {		p = *(ll_item_t **)p;	}	return (ll_item_t *) p;}static void mark_reordered(const char *sym){	ll_item_t *lli;	lli = find_wi_index(sym, cur_base);	if (lli) {		if (!tsearch(lli, &cur_base->root_wi_index_reordered, wi_index_cmp)) {			error_msg("OUT OF MEMORY!");		}	}}static ll_item_t *find_wi_index_reordered(const char *sym){	weighted_item_t w;	ll_item_t l;	void *p;	w.symbol = sym;	l.data = &w;	l.data_type = DT_WEIGHTED;	p = tfind(&l, &cur_base->root_wi_index_reordered, wi_index_cmp);	if (p) {		p = *(ll_item_t **)p;	}	return (ll_item_t *) p;}static ll_item_t *init_comm_ptr(void){	assert(cur_base);	assert(cur_base->section_list);	/* at the moment, only support one section in comm */	assert(cur_base->section_list->next == NULL);	comm_cur_ptr = ((section_t *)(cur_base->section_list->data))->itm_list;	while (comm_cur_ptr && (comm_cur_ptr->data_type & DT_REORDER)) {		comm_cur_ptr = comm_cur_ptr->next;	}#warning devel code/* 	{ *//* 		ll_item_t *p = comm_cur_ptr; *//* 		fprintf(stderr, "init_comm_ptr\n"); *//* 		while (p != comm_cur_ptr) { *//* 			if (p->data_type & DT_WEIGHTED) { *//* 				fprintf(stderr, "%s", ((weighted_item_t *)p)->symbol); *//* 			} *//* 			p = p->next; *//* 		} *//* 	} */	assert(comm_cur_ptr);/* 	fprintf(stderr, "init_comm_ptr -- %s %p %p %p %d\n", *//* 			((weighted_item_t *)(comm_cur_ptr->data))->symbol, *//* 			comm_cur_ptr, comm_cur_ptr->prev, comm_cur_ptr->next, *//* 			ll_len(comm_cur_ptr)); */	comm_prev_ptr = NULL;	return comm_cur_ptr;}static ll_item_t *next_comm_ptr(void){	/* at the moment, only support one section in comm */	assert(cur_base->section_list->next == NULL);	comm_prev_ptr = comm_cur_ptr;    while (comm_cur_ptr && ((comm_cur_ptr = comm_cur_ptr->next) != NULL)) {		if (!(comm_cur_ptr->data_type & DT_REORDER)) {			break;		}	}	return comm_cur_ptr;}static int dump_count;#if 0static void dump_section(section_t *s, int mask, col_locale_t *der){	ll_item_t *lli;	ll_item_t *lli0;	weighted_item_t *w;	weight_t *p;	int i;	lli0 = lli = s->itm_list;	if (!lli0) {		return;	}	do {		if (!(lli->data_type & mask)) {			lli = lli->next;			continue;		}		if (lli->data_type & DT_WEIGHTED) {			++dump_count;			w = (weighted_item_t *)(lli->data);			p = w->weight;			printf("%6d: %s (%d) ", dump_count, w->symbol, p->num_weights);			for (i = 0 ; i < p->num_weights ; i++) {				if (p->rule[i] & R_FORWARD) {					printf("F");				}				if (p->rule[i] & R_BACKWARD) {					printf("B");				}				if (p->rule[i] & R_POSITION) {					printf("P");				}				printf(",");			}			for (i = 0 ; i < p->num_weights ; i++) {				printf("   %s", p->colitem[i]);			}			printf("\n");		} else if (lli->data_type & (DT_SECTION|DT_REORDER)) {			if (lli->data_type == DT_REORDER) {				assert(der);				if (strncmp(((section_t *)(lli->data))->name, der->name, strlen(der->name))) {					lli = lli->next;					continue;				}			}			if (lli->data_type & DT_SECTION) {				printf("SECTION -----------------\n");			} else {				printf("REORDER -----------------\n");			}			dump_section((section_t *)(lli->data), mask, der);			printf("DONE --------------------\n");		}		lli = lli->next;	} while (lli != lli0);}#elsestatic int in_reorder_section = 0;static void dump_section(section_t *s, int mask, col_locale_t *der){	ll_item_t *lli;	ll_item_t *lli0;	weighted_item_t *w;	weight_t *p;	int i;	lli0 = lli = s->itm_list;	if (!lli0) {		return;	}	do {		if (!(lli->data_type & mask)) {			lli = lli->next;			continue;		}		if (lli->data_type & DT_WEIGHTED) {			++dump_count;			w = (weighted_item_t *)(lli->data);			p = w->weight;#if 1			if (in_reorder_section) {				printf(" %p", w);			}#else			printf("%6d: %s (%d) ", dump_count, w->symbol, p->num_weights);			for (i = 0 ; i < p->num_weights ; i++) {				if (p->rule[i] & R_FORWARD) {					printf("F");				}				if (p->rule[i] & R_BACKWARD) {					printf("B");				}				if (p->rule[i] & R_POSITION) {					printf("P");				}				printf(",");			}			for (i = 0 ; i < p->num_weights ; i++) {				printf("   %s", p->colitem[i]);			}			printf("\n");#endif		} else if (lli->data_type & (DT_SECTION|DT_REORDER)) {			if (lli->data_type == DT_REORDER) {				assert(der);				if (strncmp(((section_t *)(lli->data))->name, der->name, strlen(der->name))) {					lli = lli->next;					continue;				}			}			if (lli->data_type & DT_SECTION) {/* 				printf("SECTION -----------------\n"); */				assert(0);			} else {/* 				printf("REORDER -----------------\n"); */				in_reorder_section = 1;			}			dump_section((section_t *)(lli->data), mask, der);/* 			printf("DONE --------------------\n"); */			printf("\n");			in_reorder_section = 0;		}		lli = lli->next;	} while (lli != lli0);}#endifstatic void dump_weights(const char *name){	ll_item_t *lli;	col_locale_t *base;	col_locale_t *der;	col_locale_t cl;	void *p;	assert(name);	if (!*name) {				/* use last */		base = cur_base;		der = cur_derived;	} else {		cl.name = (char *) name;		if (!(p = tfind(&cl, &root_col_locale, col_locale_cmp))) {			error_msg("unknown locale: %s", name);		}		base = *((col_locale_t **) p);		der = NULL;		if (base->base_locale) { /* oops... really derived */			der = base;			base = der->base_locale;		}	}	dump_count = 0;	if (base) {/* 		printf("BASE - %s\n", base->name); */		for (lli = base->section_list ; lli ; lli = lli->next) {/* 			printf("SECTION %s\n", ((section_t *)(lli->data))->name); */			dump_section((section_t *)(lli->data), ~0, der);		}	}	assert(der != base);	if (der) {/* 		printf("DERIVED - %s\n", der->name); */		for (lli = der->section_list ; lli ; lli = lli->next) {			if (lli->data_type == DT_SECTION) {				dump_section((section_t *)(lli->data), DT_WEIGHTED, der);			}		}	}/* 	printf("DONE\n"); */}static void print_starter_node(const void *ptr, VISIT order, int level){    if (order == postorder || order == leaf)  {		fprintf(stderr, "   %s\n", *(const char **) ptr);    }}static void finalize_base(void){	ll_item_t *s;	ll_item_t *h;	ll_item_t *lli;	ll_item_t *h2;	ll_item_t *l2;	ll_item_t *cli;	ll_item_t *rli = NULL;	weighted_item_t *w;	weight_t *p;	int i, n, mr, r, mi;	col_locale_t *cl;	void *mm;	int num_invariant = 0;	int num_varying = 0;	int max_weight;	int index2weight_len_inc = 1;	assert(cur_base);	assert(base_locale_len+1 < BASE_LOCALE_LEN);	base_locale_array[base_locale_len].name = cur_base->name;	base_locale_array[base_locale_len].num_weights = 1;	base_locale_array[base_locale_len].index2weight_offset = index2weight_len;	base_locale_array[base_locale_len].index2ruleidx_offset = index2ruleidx_len;	if (!strcmp(cur_base->name,"ja_JP") || !strcmp(cur_base->name,"ko_KR")) {#warning fix the index2weight check!!		index2weight_len_inc = 0;	}/* 	printf("%s -- index2weight_len = %d\n", cur_base->name, index2weight_len); */	if (!hcreate(30000)) {		error_msg("OUT OF MEMORY!");	}	/* first pass ... set the fixed indexes */	final_index = i = 1;	mr = 0;	for (s = cur_base->section_list ; s ; s = s->next) {#if 1		if (s->data_type & DT_REORDER) { /* a reordered section */			fprintf(stderr, "pass1: reordered section %s - xxx\n", ((section_t *)(s->data))->name);			lli = ((section_t *)(s->data))->itm_list;			r = 0;			if (lli) {/* 				r = ll_len( ((section_t *)(lli->data))->itm_list ); */				r = ll_len(lli) + 1;			}			if (r > mr) {				mr = r;			}			fprintf(stderr, "pass1: reordered section %s - %d\n", ((section_t *)(s->data))->name, r);			continue;		}#endif		h = lli = ((section_t *)(s->data))->itm_list;		if (!lli) {			continue;		}		do {			if (lli->data_type & DT_RANGE) {				i += mr;				mr = 0;#warning check ko_kR and 9/* 				++i; */				lli->idx = i;				assert(!rli);				rli = lli;				fprintf(stderr, "range pre = %d  after = ", i);				i += ((range_item_t *)(lli->data))->length + 1;#warning check ko_kR and 9/* 				++i; */				fprintf(stderr, "%d\n", i);				if (!index2weight_len_inc) { /* ko_KR hack */					final_index += ((range_item_t *)(lli->data))->length + 1;				}/* 				add_final_col_index("RANGE"); */			} else if (lli->data_type & DT_WEIGHTED) {				i += mr;				mr = 0;				w = (weighted_item_t *)(lli->data);				if (find_wi_index_reordered(w->symbol)) { /* reordered symbol so skip on first pass */					++num_varying;					++i;					continue;				}				++num_invariant;				index2weight_buffer[index2weight_len] = lli->idx = i++;				index2weight_len += index2weight_len_inc;				add_final_col_index(w->symbol);							} else {				assert(lli->data_type & DT_REORDER);				r = ll_len( ((section_t *)(lli->data))->itm_list );#warning check ko_kR and 9				if (r > mr) {					mr = r;				}/* 				r = 0; */			}		} while ((lli = lli->next) != h);	}	/* second pass ... set the reordered indexes */	mi = i + mr;	mr = i = 0;	for (s = cur_base->section_list ; s ; s = s->next) {		h = lli = ((section_t *)(s->data))->itm_list;		if (!lli) {			continue;		}		do {			if (lli->data_type & DT_RANGE) {				i += mr;				mr = 0;				i = lli->idx + ((range_item_t *)(lli->data))->length + 1;#warning check			} else if ((lli->data_type & DT_WEIGHTED) && !(s->data_type & DT_REORDER)) {				i += mr;				mr = 0;				w = (weighted_item_t *)(lli->data);				if (find_wi_index_reordered(w->symbol) /* reordered symbol skipped on first pass */#if 0					|| (s->data_type & DT_REORDER) /* or in a reordered section */#endif					) {					assert(!(s->data_type & DT_REORDER));					index2weight_buffer[index2weight_len] = lli->idx = ++i;					index2weight_len += index2weight_len_inc;					add_final_col_index(w->symbol);/* 					fprintf(stdout, "%11s: r %6d %6d %s\n", *//* 							cur_base->name, lli->idx, final_index_val(w->symbol), w->symbol); */					continue;				}				i = lli->idx;/* 				fprintf(stdout, "%11s: w %6d %6d %s\n", *//* 						cur_base->name, lli->idx, final_index_val(w->symbol), w->symbol); */			} else {/* 				fprintf(stderr, "section: %s  %d  %d\n", ((section_t *)(s->data))->name, *//* 						s->data_type, lli->data_type); *//* 					assert(!(s->data_type & DT_REORDER)); *//* 				assert(lli->data_type & DT_REORDER); */#if 1				if (s->data_type & DT_REORDER) {					h2 = l2 = lli;					if (!h2) {						continue;					}				} else {					assert(s->data_type & DT_SECTION);					h2 = l2 = ((section_t *)(lli->data))->itm_list;					if (!h2) {						continue;					}				}#else				h2 = l2 = ((section_t *)(lli->data))->itm_list;				if (!h2) {					continue;				}#endif				r = 0;				do {					assert(l2->data_type & DT_WEIGHTED);					++r;					l2->idx = i + r;/* 					fprintf(stdout, "%s: R %6d        %s\n", *//* 							((section_t *)(lli->data))->name, l2->idx, ((weighted_item_t *)(l2->data))->symbol); */				} while ((l2 = l2->next) != h2);				if (r > mr) {					mr = r;				}			}		} while ((lli = lli->next) != h);	}	/* finally, walk through all derived locales and set non-reordered section items */	mr = mi;	for (cli = cur_base->derived_list ; cli ; cli = cli->next) {		cl = (col_locale_t *)(cli->data);/* 		fprintf(stderr, "pass3: %d  %s\n", cli->data_type, cl->name); *//* 		fprintf(stdout, "pass3: %d  %s\n", cli->data_type, cl->name); */		assert(cli->data_type == DT_COL_LOCALE);		i = mi;		for (s = cl->section_list ; s ; s = s->next) {/* 			if (s->data_type & DT_REORDER) { *//* 				continue; *//* 			} */			h = lli = ((section_t *)(s->data))->itm_list;			if (!lli) {				continue;			}			do {				assert(!(lli->data_type & DT_RANGE));				if (lli->data_type & DT_WEIGHTED) {/* 					fprintf(stderr, "     %d %d %s\n", lli->data_type, lli->idx, ((weighted_item_t *)(lli->data))->symbol); */					add_final_col_index(((weighted_item_t *)(lli->data))->symbol);					if (s->data_type & DT_REORDER) {						continue;					}					assert(lli->idx == INT_MIN);					lli->idx = ++i;/* 					fprintf(stdout, "%11s: S %6d %6d %s\n", *//* 							cl->name, lli->idx, *//* 							final_index_val(((weighted_item_t *)(lli->data))->symbol), *//* 							((weighted_item_t *)(lli->data))->symbol); */				} else {					assert(0);					assert(lli->data_type & DT_SECTION);					h2 = l2 = ((section_t *)(lli->data))->itm_list;					if (!h2) {						continue;					}					do {						assert(l2->data_type & DT_WEIGHTED);						assert(l2->idx == INT_MIN);						l2->idx = ++i;						add_final_col_index(((weighted_item_t *)(l2->data))->symbol);					} while ((l2 = l2->next) != h2);				}			} while ((lli = lli->next) != h);		}		if (i > mr) {			mr = i;		}	}	max_weight = mr;	assert(num_varying == tnumnodes(cur_base->root_wi_index_reordered));	/* we can now initialize the wcs2index array */	{		ENTRY *p;		ENTRY e;		char buf[8];		static const char xd[] = "0123456789ABCDEF";		int starter_index = final_index;		int wcs2index_count = 0;		strcpy(buf, "<U....>");		memset(wcs2index, 0, sizeof(wcs2index));		e.key = (char *) buf;		for (i=1 ; i <= 0xffff ; i++) {			buf[5] = xd[ i & 0xf ];			buf[4] = xd[ (i >> 4) & 0xf ];			buf[3] = xd[ (i >> 8) & 0xf ];			buf[2] = xd[ (i >> 12) & 0xf ];			if ((p = hsearch(e, FIND)) != NULL) {				++wcs2index_count;				if ((tfind(buf, &cur_base->root_starter_char, sym_cmp)) != NULL) {					wcs2index[i] = ++starter_index;/* 					fprintf(stderr, "wcs2index[ %#06x ] = %d  (starter)\n", i, wcs2index[i]); */				} else {					wcs2index[i] = (int)(p->data);/* 					fprintf(stderr, "wcs2index[ %#06x ] = %d\n", i, wcs2index[i]); */				}			} else {				if ((tfind(buf, &cur_base->root_starter_char, sym_cmp)) != NULL) {					error_msg("marked starter but not in hash: %s", buf);				}			}		}	/* ---------------------------------------------------------------------- */		{			int i, n;			table_data table;			size_t t, smallest;			n = 0;			smallest = SIZE_MAX;			table.ii = NULL;			for (i=0 ; i < 14 ; i++) {				if ((RANGE >> i) < 4) {					break;				}				t = newopt(wcs2index, RANGE, i, &table);				if (smallest >= t) {					n = i;					smallest = t;					/*  			} else { */					/*  				break; */				}			}/* 			printf("smallest = %u  for range %#x (%u)\n", smallest, RANGE, RANGE); */			assert(smallest != SIZE_MAX);			if (smallest + wcs2colidt_len >= WCS2COLIDT_LEN) {				error_msg("WCS2COLIDT_LEN too small");			}			base_locale_array[base_locale_len].wcs2colidt_offset = wcs2colidt_len;			table.ii = wcs2colidt_buffer + wcs2colidt_len;			t = smallest;			smallest = SIZE_MAX;			smallest = newopt(wcs2index, RANGE, n, &table);			assert(t == smallest);			wcs2colidt_len += smallest;/* 			fprintf(stderr, "smallest = %d   wcs2colidt_len = %d\n", smallest, wcs2colidt_len); */#if 0			{				unsigned int sc, n, i0, i1;				unsigned int u = 0xe40;				table_data *tbl = &table;#define WCctype_TI_MASK ((1 << tbl->ti_shift)-1)#define WCctype_TI_SHIFT (tbl->ti_shift)#define WCctype_TI_LEN (tbl->ti_len)#define WCctype_II_MASK ((1 << tbl->ii_shift)-1)#define WCctype_II_SHIFT (tbl->ii_shift)#define WCctype_II_LEN (tbl->ii_len)				sc = u & WCctype_TI_MASK;				u >>= WCctype_TI_SHIFT;				n = u & WCctype_II_MASK;				u >>= WCctype_II_SHIFT;				i0 = tbl->ii[u];				fprintf(stderr, "i0 = %d\n", i0);				i0 <<= WCctype_II_SHIFT;				i1 = tbl->ii[WCctype_II_LEN + i0 + n];				/* 	i1 = tbl->ti[i0 + n]; */				fprintf(stderr, "i1 = %d\n", i1);				i1 <<= WCctype_TI_SHIFT;				/* 	return *(uint16_t *)(&(tbl->ii[WCctype_II_LEN + WCctype_TI_LEN + i1 + sc])); */				fprintf(stderr, "i2 = %d\n", WCctype_II_LEN + WCctype_TI_LEN + i1 + sc);				fprintf(stderr, "val = %d\n",  tbl->ii[WCctype_II_LEN + WCctype_TI_LEN + i1 + sc]);				/* 	return tbl->ut[i1 + sc]; */			}#endif			base_locale_array[base_locale_len].ii_shift = table.ii_shift;			base_locale_array[base_locale_len].ti_shift = table.ti_shift;			base_locale_array[base_locale_len].ii_len = table.ii_len;			base_locale_array[base_locale_len].ti_len = table.ti_len;		}	/* ---------------------------------------------------------------------- */		base_locale_array[base_locale_len].num_col_base = num_invariant + num_varying;		base_locale_array[base_locale_len].max_col_index = final_index;		base_locale_array[base_locale_len].max_weight = max_weight;		fprintf(stderr, "%s: %6u invariant  %6u varying  %6u derived  %6u total  %6u max weight  %6u wcs2\n",				cur_base->name, num_invariant, num_varying,				tnumnodes(cur_base->root_derived_wi), final_index, max_weight,				wcs2index_count);	}#if 1	/* ok, now we need to dump out the base and derived tables... */	/* don't forget to break up collating elements!!! *//* 	fprintf(stdout, "**************************************************\n"); */	/* first pass ... set the invariants */	for (s = cur_base->section_list ; s ; s = s->next) {#if 1		if (s->data_type & DT_REORDER) {			fprintf(stderr, "1: skipping reordered section %s\n", ((section_t *)(s->data))->name);			continue;		}#endif		h = lli = ((section_t *)(s->data))->itm_list;		if (!lli) {			continue;		}		do {			if (lli->data_type & DT_WEIGHTED) {				w = (weighted_item_t *)(lli->data);				if (find_wi_index_reordered(w->symbol)) { /* reordered symbol so skip on first pass */					continue;				}				if (index2weight_len_inc) {					index2ruleidx_buffer[index2ruleidx_len++] = 						add_rule((weighted_item_t *)(lli->data));				}/* 				fprintf(stdout, "%11s: w %6d %6d %s\n", *//* 						cur_base->name, lli->idx, final_index_val(w->symbol), w->symbol); */			}		} while ((lli = lli->next) != h);	}	/* second pass ... set varying */	for (s = cur_base->section_list ; s ; s = s->next) {#if 1		if (s->data_type & DT_REORDER) {			fprintf(stderr, "2: skipping reordered section %s\n", ((section_t *)(s->data))->name);			continue;		}#endif		h = lli = ((section_t *)(s->data))->itm_list;		if (!lli) {			continue;		}		do {			if (lli->data_type & DT_WEIGHTED) {				w = (weighted_item_t *)(lli->data);				if (find_wi_index_reordered(w->symbol)) { /* reordered symbol so skip on first pass */					if (index2weight_len_inc) {						index2ruleidx_buffer[index2ruleidx_len++] = 							add_rule((weighted_item_t *)(lli->data));					}/* 					fprintf(stdout, "%11s: r %6d %6d %s\n", *//* 							cur_base->name, lli->idx, final_index_val(w->symbol), w->symbol); */					continue;				}			}		} while ((lli = lli->next) != h);	}	do_starter_lists(cur_base);/* 	fprintf(stderr,"updated final_index = %d\n", final_index); */	if (rli) {		base_locale_array[base_locale_len].range_low			= strtoul(((range_item_t *)(rli->data))->symbol1 + 2, NULL, 16);		base_locale_array[base_locale_len].range_count			= ((range_item_t *)(rli->data))->length;		base_locale_array[base_locale_len].range_base_weight = rli->idx;		base_locale_array[base_locale_len].range_rule_offset = add_range_rule((range_item_t *)(rli->data));/* 		fprintf(stdout, "%11s:   %6d %6d %s %s (%d)\n", *//* 				"RANGE", rli->idx, -1, *//* 				((range_item_t *)(rli->data))->symbol1, *//* 				((range_item_t *)(rli->data))->symbol2, *//* 				((range_item_t *)(rli->data))->length); */	}/* 	fprintf(stdout,"\nDerived\n\n"); */	/* first, if base name is of the form ll_CC, add a derived locale for it */	if ((strlen(cur_base->name) == 5)		&& islower(cur_base->name[0])		&& islower(cur_base->name[1])		&& (cur_base->name[2] == '_')		&& isupper(cur_base->name[3])		&& isupper(cur_base->name[4])		) {		fprintf(stderr, "adding special derived for %s\n", cur_base->name);/* 	fprintf(stderr,"updated final_index = %d\n", final_index); */		assert(der_locale_len+1 < DER_LOCALE_LEN);		der_locale_array[der_locale_len].name = cur_base->name;		der_locale_array[der_locale_len].base_idx = base_locale_len;				u16_buf[0] = 1;		u16_buf[1] = 0;		u16_buf_len = 2;		mm = NULL;		if ((u16_buf_len > override_len) ||			!(mm = memmem(override_buffer, override_len*sizeof(override_buffer[0]),						  u16_buf, u16_buf_len*sizeof(u16_buf[0])))			) {			assert(override_len + u16_buf_len < OVERRIDE_LEN);			memcpy(override_buffer + override_len, u16_buf, u16_buf_len*sizeof(u16_buf[0]));			der_locale_array[der_locale_len].overrides_offset = override_len;			override_len += u16_buf_len;/* 			printf("%s: override_len = %d   u16_buf_len = %d\n", cl->name, override_len, u16_buf_len); */		} else if (!(u16_buf_len > override_len)) {			assert(mm);			der_locale_array[der_locale_len].overrides_offset = ((uint16_t *)(mm)) - override_buffer;/* 			printf("%s: memmem found a match with u16_buf_len = %d\n", cl->name, u16_buf_len); */		}		der_locale_array[der_locale_len].multistart_offset			= base_locale_array[base_locale_len].multistart_offset;		der_locale_array[der_locale_len].undefined_idx = final_index_val0("UNDEFINED");		if (!der_locale_array[der_locale_len].undefined_idx) {			error_msg("no UNDEFINED definition for %s", cur_base->name);		}		++der_locale_len;	} else {		fprintf(stderr, "NOT adding special derived for %s\n", cur_base->name);	}	/* now all the derived... */	for (cli = cur_base->derived_list ; cli ; cli = cli->next) {		cl = (col_locale_t *)(cli->data);		assert(cli->data_type == DT_COL_LOCALE);		assert(der_locale_len+1 < DER_LOCALE_LEN);		der_locale_array[der_locale_len].name = cl->name;		der_locale_array[der_locale_len].base_idx = base_locale_len;		u16_buf_len = 0;		for (i = 0 ; i < 2 ; i++) {			if (i) {/* 				fprintf(stdout, "   section --- (singles)\n"); */				u16_buf[u16_buf_len++] = 1;	/* single */			}			/* we do this in two passes... first all sequences, then all single reorders */			for (s = cl->section_list ; s ; s = s->next) {				h = lli = ((section_t *)(s->data))->itm_list;				if (!lli) {					continue;				}				assert(u16_buf_len +4 < sizeof(u16_buf)/sizeof(u16_buf[0]));				if ((!i && (ll_len(h) > 1) ) || (ll_len(h) == i)) {					if (!i) {/* 						fprintf(stdout, "   section ----------------- %d %d\n", i, ll_len(h)); */						u16_buf[u16_buf_len++] = ll_len(h);	/* multi */						assert(lli->data_type & DT_WEIGHTED);#if 0						u16_buf[u16_buf_len++] = final_index_val(((weighted_item_t *)(lli->data))->symbol);	/* start index */#endif						u16_buf[u16_buf_len++] = lli->idx; /* start weight */					}					do {						if (lli->data_type & DT_WEIGHTED) {/* 							fprintf(stdout, "%11s: S %6d %6d %s\n", *//* 									cl->name, lli->idx, *//* 									final_index_val(((weighted_item_t *)(lli->data))->symbol), *//* 									((weighted_item_t *)(lli->data))->symbol); */#if 0							if (i) {								assert(u16_buf_len +4 < sizeof(u16_buf)/sizeof(u16_buf[0]));								u16_buf[u16_buf_len++] = final_index_val(((weighted_item_t *)(lli->data))->symbol);								assert(u16_buf[u16_buf_len-1]);								u16_buf[u16_buf_len++] = lli->idx; /* weight */							}#else							assert(u16_buf_len +4 < sizeof(u16_buf)/sizeof(u16_buf[0]));							u16_buf[u16_buf_len++] = final_index_val(((weighted_item_t *)(lli->data))->symbol);							assert(u16_buf[u16_buf_len-1]);							if (i) {								u16_buf[u16_buf_len++] = lli->idx; /* weight */							}#endif							u16_buf[u16_buf_len++] = add_rule((weighted_item_t *)(lli->data));						}					} while ((lli = lli->next) != h);				}			}		}		u16_buf[u16_buf_len++] = 0;		mm = NULL;		if ((u16_buf_len > override_len) ||			!(mm = memmem(override_buffer, override_len*sizeof(override_buffer[0]),						  u16_buf, u16_buf_len*sizeof(u16_buf[0])))			) {			assert(override_len + u16_buf_len < OVERRIDE_LEN);			memcpy(override_buffer + override_len, u16_buf, u16_buf_len*sizeof(u16_buf[0]));			der_locale_array[der_locale_len].overrides_offset = override_len;			override_len += u16_buf_len;/* 			printf("%s: override_len = %d   u16_buf_len = %d\n", cl->name, override_len, u16_buf_len); */		} else if (!(u16_buf_len > override_len)) {			assert(mm);			der_locale_array[der_locale_len].overrides_offset = ((uint16_t *)(mm)) - override_buffer;/* 			printf("%s: memmem found a match with u16_buf_len = %d\n", cl->name, u16_buf_len); */		}		do_starter_lists(cl);		der_locale_array[der_locale_len].undefined_idx = final_index_val0("UNDEFINED");#if 0		assert(der_locale_array[der_locale_len].undefined_idx);		if (!der_locale_array[der_locale_len].undefined_idx) {			der_locale_array[der_locale_len].undefined_idx = base_locale_array[base_locale_len].undefined_idx;		}#endif		if (!der_locale_array[der_locale_len].undefined_idx) {			error_msg("no UNDEFINED definition for %s", cl->name);		}		++der_locale_len;	}#endif#warning handle UNDEFINED idx specially?  what if in only some of derived?/* 	base_locale_array[base_locale_len].undefined_idx = final_index_val0("UNDEFINED"); */	base_locale_array[base_locale_len].undefined_idx = 0;	hdestroy();	++base_locale_len;/* 	if (tnumnodes(cur_base->root_starter_char)) { *//* 		fprintf(stderr, "starter nodes\n"); *//* 		twalk(cur_base->root_starter_char, print_starter_node); *//* 	} */}static int starter_all_cmp(const void *n1, const void *n2){	const char *s1 = ((weighted_item_t *) n1)->symbol;	const char *s2 = ((weighted_item_t *) n2)->symbol;	colitem_t x;	colitem_t *p;	int n;	/* sort by 1st char ... then inverse for string */	x.element = NULL;	if (!is_ucode(s1)) {		x.string = s1;		p = tfind(&x, &cur_base->root_colitem, colitem_cmp);		s1 = (*((colitem_t **) p))->element + 1;	}	if (!is_ucode(s2)) {		x.string = s2;		p = tfind(&x, &cur_base->root_colitem, colitem_cmp);		s2 = (*((colitem_t **) p))->element + 1;	}	/* <U####>< */	/* 01234567 */	assert(is_ucode(s1));	assert(is_ucode(s2));	n = strncmp(s1+2, s2+2, 4);	if (n) {		return n;	}	s1 += 7;	s2 += 7;	return strcmp(s2, s1);}static void print_starter_all_node(const void *ptr, VISIT order, int level){    const weighted_item_t *w = *(const weighted_item_t **) ptr;	colitem_t *ci;	void *p;	int n;	colitem_t x;    if (order == postorder || order == leaf)  {#if 0		if ((n = is_ucode(w->symbol)) != 0) {			printf(" %s\n", w->symbol);		} else {			x.string = w->symbol;			x.element = NULL;			p = tfind(&x, &cur_base->root_colitem, colitem_cmp);			assert(p);			ci = *((colitem_t **) p);			printf("%s = %s\n", ci->element, w->symbol);		}#else		printf("%s|", w->symbol);/* 		if ((n = is_ucode(w->symbol)) != 0) { *//* 			printf("\n"); *//* 		} */#endif	}}static void process_starter_node(const void *ptr, VISIT order, int level){    const weighted_item_t *w = *(const weighted_item_t **) ptr;	colitem_t *ci;	void *p;	int n;	colitem_t x;	const char *s;	char buf[32];	/* store index of collation item followed by (unprefixed) nul-terminated string */    if (order == postorder || order == leaf)  {		if ((n = is_ucode(w->symbol)) != 0) {			u16_buf[u16_buf_len++] = final_index_val(w->symbol);			assert(u16_buf[u16_buf_len-1]);			u16_buf[u16_buf_len++] = 0;			if (++u16_starter < base_locale_array[base_locale_len].num_starters) {				u16_buf[u16_starter] = u16_buf_len;			}/* 			fprintf(stderr, "ucode - %d %d\n", u16_buf[u16_starter-1], u16_buf_len); */		} else {			x.string = w->symbol;			x.element = NULL;			p = tfind(&x, &cur_base->root_colitem, colitem_cmp);			assert(p);			ci = *((colitem_t **) p);			s = ci->element;			u16_buf[u16_buf_len++] = final_index_val(w->symbol);			assert(u16_buf[u16_buf_len-1]);			assert(*s == '"');			n = is_ucode(++s);/* 			fprintf(stderr, "s is |%s| with len %d (%d)\n", s, strlen(s), n); */			assert(n);			s += n;			while (*s != '"') {				n = is_ucode(s);				assert(n);				strncpy(buf, s, n+1);				buf[n] = 0;/* 				fprintf(stderr, "buf is |%s| with len %d (%d)\n", buf, strlen(buf), n); */				u16_buf[u16_buf_len++] = final_index_val(buf);				assert(u16_buf[u16_buf_len-1]);				s += n;			}			u16_buf[u16_buf_len++] = 0;		}	}}static void **p_cl_root_starter_all;static void complete_starter_node(const void *ptr, VISIT order, int level){	weighted_item_t w;	weighted_item_t *p;    if (order == postorder || order == leaf)  {		w.symbol = *(const char **) ptr;		w.weight = NULL;		if (!tfind(&w, p_cl_root_starter_all, starter_all_cmp)) {			p = xmalloc(sizeof(weighted_item_t));			p->symbol = w.symbol;			p->weight = NULL;/* 			fprintf(stderr, "complete_starter_node: %s\n", *(const char **) ptr); */			if (!tsearch(p, p_cl_root_starter_all, starter_all_cmp)) {				error_msg("OUT OF MEMORY");			}		}    }}static void do_starter_lists(col_locale_t *cl){	ll_item_t *s;	ll_item_t *h;	ll_item_t *lli;	col_locale_t *c;	colitem_t *ci;	weighted_item_t *w;	void *p;	char buf[32];	int n;	colitem_t x;	void *mm;	c = cl;	if (c != cur_base) {		c = cur_base;	}/* 	printf("STARTERS %s --------------------\n", cl->name); */ LOOP:	for (s = c->section_list ; s ; s = s->next) {		h = lli = ((section_t *)(s->data))->itm_list;		if (!lli) {			continue;		}		do {			if (lli->data_type & DT_WEIGHTED) {				w = (weighted_item_t *)(lli->data);				ci = NULL;				if ((n = is_ucode(w->symbol)) != 0) {					strcpy(buf, w->symbol);				} else {/* 					fprintf(stdout, "looking for |%s|\n", w->symbol); */					x.string = w->symbol;					x.element = NULL;					p = tfind(&x, &cur_base->root_colitem, colitem_cmp);					if (!p) {/* 						fprintf(stderr, "Whoa... processing starters for %s and couldn't find %s\n", *//* 								cl->name, w->symbol); */						continue;					}					ci = *((colitem_t **) p);					if (!ci->element) {	/* just a collating symbol */						continue;					}					assert(ci->element[0] == '"');					n = is_ucode(ci->element + 1);					assert(n);					strncpy(buf, ci->element + 1, n);				}				if ((tfind(buf, &cur_base->root_starter_char, sym_cmp)) != NULL) {/* 					fprintf(stdout, "adding from %s: %s", c->name, w->symbol); *//* 					if (ci) { *//* 						fprintf(stdout, " = %s", ci->element); *//* 					} *//* 					fprintf(stdout, "\n"); */					if (!tsearch(w, &cl->root_starter_all, starter_all_cmp)) {						error_msg("OUT OF MEMORY");					}				}			}		} while ((lli = lli->next) != h);	}	if (c != cl) {		c = cl;		goto LOOP;	}	p_cl_root_starter_all = &cl->root_starter_all;	twalk(cur_base->root_starter_char, complete_starter_node);	if (cl == cur_base) {		base_locale_array[base_locale_len].num_starters	= tnumnodes(cur_base->root_starter_char);	}#if 0	printf("\nNow walking tree...\n\n");	twalk(cl->root_starter_all, print_starter_all_node);	printf("\n\n");#endif	u16_starter = 0;	u16_buf[0] = u16_buf_len = base_locale_array[base_locale_len].num_starters;	twalk(cl->root_starter_all, process_starter_node);/* 	fprintf(stderr, "s=%d n=%d\n", u16_starter,  base_locale_array[base_locale_len].num_starters); */	assert(u16_starter == base_locale_array[base_locale_len].num_starters);#if 0	{ int i;	for (i=0 ; i < u16_buf_len ; i++) {		fprintf(stderr, "starter %2d: %d - %#06x\n", i, u16_buf[i], u16_buf[i]);	}}#endif	mm = NULL;	if (u16_buf_len) {/* 		assert(base_locale_array[base_locale_len].num_starters); */		if ((u16_buf_len > multistart_len) ||			!(mm = memmem(multistart_buffer, multistart_len*sizeof(multistart_buffer[0]),						  u16_buf, u16_buf_len*sizeof(u16_buf[0])))			) {			assert(multistart_len + u16_buf_len < MULTISTART_LEN);			memcpy(multistart_buffer + multistart_len, u16_buf, u16_buf_len*sizeof(u16_buf[0]));			if (cl == cur_base) {				base_locale_array[base_locale_len].multistart_offset = multistart_len;			} else {				der_locale_array[der_locale_len].multistart_offset = multistart_len;			}			multistart_len += u16_buf_len;/* 			fprintf(stderr, "%s: multistart_len = %d   u16_buf_len = %d\n", cl->name, multistart_len, u16_buf_len); */		} else if (!(u16_buf_len > multistart_len)) {			assert(mm);			if (cl == cur_base) {				base_locale_array[base_locale_len].multistart_offset = ((uint16_t *)(mm)) - multistart_buffer;			} else {				der_locale_array[der_locale_len].multistart_offset = ((uint16_t *)(mm)) - multistart_buffer;			}/* 			fprintf(stderr, "%s: memmem found a match with u16_buf_len = %d\n", cl->name, u16_buf_len); */		}	} else {		assert(!base_locale_array[base_locale_len].num_starters);	}/* 	printf("u16_buf_len = %d\n", u16_buf_len); *//* 	printf("STARTERS %s DONE ---------------\n", cl->name); */}/* For sorting the blocks of unsigned chars. */static size_t nu_val;int nu_memcmp(const void *a, const void *b){	return memcmp(*(unsigned char**)a, *(unsigned char**)b, nu_val * sizeof(tbl_item));}size_t newopt(tbl_item *ut, size_t usize, int shift, table_data *tbl){	static int recurse = 0;	tbl_item *ti[RANGE];	/* table index */	size_t numblocks;	size_t blocksize;	size_t uniq;	size_t i, j;	size_t smallest, t;	tbl_item *ii_save;	int uniqblock[1 << (8*sizeof(tbl_item) - 1)];	tbl_item uit[RANGE];	int shift2;	if (shift > 15) {		return SIZE_MAX;	}	ii_save = NULL;	blocksize = 1 << shift;	numblocks = usize >> shift;	/* init table index */	for (i=j=0 ; i < numblocks ; i++) {		ti[i] = ut + j;		j += blocksize;	}	/* sort */	nu_val = blocksize;	qsort(ti, numblocks, sizeof(unsigned char *), nu_memcmp);		uniq = 1;	uit[(ti[0]-ut)/blocksize] = 0;	for (i=1 ; i < numblocks ; i++) {		if (memcmp(ti[i-1], ti[i], blocksize*sizeof(tbl_item)) < 0) {			if (++uniq > (1 << (8*sizeof(tbl_item) - 1))) {				break;			}			uniqblock[uniq - 1] = i;		}#if 1		else if (memcmp(ti[i-1], ti[i], blocksize*sizeof(tbl_item)) > 0) {			printf("bad sort %i!\n", i);			abort();		}#endif		uit[(ti[i]-ut)/blocksize] = uniq - 1;	}	smallest = SIZE_MAX;	shift2 = -1;	if (uniq <= (1 << (8*sizeof(tbl_item) - 1))) {		smallest = numblocks + uniq * blocksize;		if (!recurse) {			++recurse;			for (j=1 ; j < 14 ; j++) {				if ((numblocks >> j) < 2) break;				if (tbl) {					ii_save = tbl->ii;					tbl->ii = NULL;				}				if ((t = newopt(uit, numblocks, j, tbl)) < SIZE_MAX) {					t += uniq * blocksize;				}				if (tbl) {					tbl->ii = ii_save;				}				if (smallest >= t) {					shift2 = j;					smallest = t;/* 					if (!tbl->ii) { *//* 						printf("ishift %u  tshift %u  size %u\n", *//* 							   shift2, shift, t); *//* 					} *//*  				} else { *//*  					break; */				}			}			--recurse;		}	} else {		return SIZE_MAX;	}	if (tbl->ii) {		if (recurse) {			tbl->ii_shift = shift;			tbl->ii_len = numblocks;			memcpy(tbl->ii, uit, numblocks*sizeof(tbl_item));			tbl->ti = tbl->ii + tbl->ii_len;			tbl->ti_len = uniq * blocksize;			for (i=0 ; i < uniq ; i++) {				memcpy(tbl->ti + i * blocksize, ti[uniqblock[i]], blocksize*sizeof(tbl_item));			}		} else {			++recurse;/* 			printf("setting ishift %u  tshift %u\n", shift2, shift); */			newopt(uit, numblocks, shift2, tbl);			--recurse;			tbl->ti_shift = shift;			tbl->ut_len = uniq * blocksize;			tbl->ut = tbl->ti + tbl->ti_len;			for (i=0 ; i < uniq ; i++) {				memcpy(tbl->ut + i * blocksize, ti[uniqblock[i]], blocksize*sizeof(tbl_item));			}		}	}	return smallest;}static const int rule2val[8] = {	-1,	(1 << 14),					/* forward */	(2 << 14),					/* position */	(3 << 14),					/* forward,position */	0,							/* backward */	-1,	-1,	-1,};static int final_index_val_x(const char *s, const char *sym){	int r;	if (!(r = final_index_val0(s))) {		if (!strcmp(s, "IGNORE")) {			r = 0;		} else if (!strcmp(s, "..") || !strcmp(sym, "RANGE")) {			if (*sym == '.') {				final_index_val(sym); /* make sure it's known */			}			r = 0x3fff;		} else if (!strcmp(s, ".")) {			r = 0x3ffe;		} else {			error_msg("can't find final index: %s", s);		}	}	return r;}/* store rule2val in 2 high bits and collation index in lower. * for sort strings, store (offset from base) + max colindex as index. */static unsigned int add_rule(weighted_item_t *wi){	weight_t *w = wi->weight;	int i, j, r, n;	uint16_t rbuf[MAX_COLLATION_WEIGHTS];	uint16_t ws_buf[32];	void *mm;	char buf[32];	const char *s;	const char *e;	for (i=0 ; i < MAX_COLLATION_WEIGHTS ; i++) {		rbuf[i] = rule2val[R_FORWARD]; /* set a default to forward-ignore */	}	if (base_locale_array[base_locale_len].num_weights < w->num_weights) {		base_locale_array[base_locale_len].num_weights = w->num_weights;	}	for (i=0 ; i < w->num_weights ; i++) {		assert(rule2val[(int)(w->rule[i])] >= 0);		assert(w->colitem[i] && *w->colitem[i]);		if (*w->colitem[i] == '"') { /* string... */			s = w->colitem[i] + 1;			assert(*s == '<');			n = 0;			do {				e = s;				do {					if (*e == '/') {						e += 2;						continue;					}				} while (*e++ != '>');				assert(((size_t)(e-s) < sizeof(buf)));				memcpy(buf, s, (size_t)(e-s));				buf[(size_t)(e-s)] = 0;				r = final_index_val_x(buf, wi->symbol);				assert(n + 1 < sizeof(ws_buf)/sizeof(ws_buf[0]));				ws_buf[n++] = r | rule2val[(int)(w->rule[i])];				s = e;			} while (*s != '"');			ws_buf[n++] = 0;	/* terminator */			mm = memmem(weightstr_buffer, weightstr_len*sizeof(weightstr_buffer[0]),						ws_buf, n*sizeof(ws_buf[0]));			if (!mm) {				assert(weightstr_len + n < WEIGHTSTR_LEN);				memcpy(weightstr_buffer + weightstr_len, ws_buf, n*sizeof(ws_buf[0]));				mm = weightstr_buffer + weightstr_len;				weightstr_len += n;			}			r = (((uint16_t *)(mm)) - weightstr_buffer)				+ base_locale_array[base_locale_len].max_col_index + 2;			assert(r < (1 << 14));			rbuf[i] = r | rule2val[(int)(w->rule[i])];		} else {				/* item */			r = final_index_val_x(w->colitem[i], wi->symbol); 			rbuf[i] = r | rule2val[(int)(w->rule[i])];		}	}	for (i=0 ; i < ruletable_len ; i += MAX_COLLATION_WEIGHTS) {		if (!memcmp(ruletable_buffer + i, rbuf, MAX_COLLATION_WEIGHTS*sizeof(ruletable_buffer[0]))) {			return i/MAX_COLLATION_WEIGHTS;		}	}	memcpy(ruletable_buffer + ruletable_len, rbuf, MAX_COLLATION_WEIGHTS*sizeof(ruletable_buffer[0]));	ruletable_len += MAX_COLLATION_WEIGHTS;	return  (ruletable_len / MAX_COLLATION_WEIGHTS)-1;}static unsigned int add_range_rule(range_item_t *ri){	weight_t *w = ri->weight;	int i, j, r, n;	uint16_t rbuf[MAX_COLLATION_WEIGHTS];	uint16_t ws_buf[32];	void *mm;	char buf[32];	const char *s;	const char *e;	for (i=0 ; i < MAX_COLLATION_WEIGHTS ; i++) {		rbuf[i] = rule2val[R_FORWARD]; /* set a default to forward-ignore */	}	if (base_locale_array[base_locale_len].num_weights < w->num_weights) {		base_locale_array[base_locale_len].num_weights = w->num_weights;	}	for (i=0 ; i < w->num_weights ; i++) {		assert(rule2val[(int)(w->rule[i])] >= 0);		assert(w->colitem[i] && *w->colitem[i]);		if (*w->colitem[i] == '"') { /* string... */			s = w->colitem[i] + 1;			assert(*s == '<');			n = 0;			do {				e = s;				do {					if (*e == '/') {						e += 2;						continue;					}				} while (*e++ != '>');				assert(((size_t)(e-s) < sizeof(buf)));				memcpy(buf, s, (size_t)(e-s));				buf[(size_t)(e-s)] = 0;				r = final_index_val_x(buf, "RANGE");				assert(n + 1 < sizeof(ws_buf)/sizeof(ws_buf[0]));				ws_buf[n++] = r | rule2val[(int)(w->rule[i])];				s = e;			} while (*s != '"');			ws_buf[n++] = 0;	/* terminator */			mm = memmem(weightstr_buffer, weightstr_len*sizeof(weightstr_buffer[0]),						ws_buf, n*sizeof(ws_buf[0]));			if (!mm) {				assert(weightstr_len + n < WEIGHTSTR_LEN);				memcpy(weightstr_buffer + weightstr_len, ws_buf, n*sizeof(ws_buf[0]));				mm = weightstr_buffer + weightstr_len;				weightstr_len += n;			}			r = (((uint16_t *)(mm)) - weightstr_buffer)				+ base_locale_array[base_locale_len].max_col_index + 2;			assert(r < (1 << 14));			rbuf[i] = r | rule2val[(int)(w->rule[i])];		} else {				/* item */			r = final_index_val_x(w->colitem[i], "RANGE");			rbuf[i] = r | rule2val[(int)(w->rule[i])];		}	}	for (i=0 ; i < ruletable_len ; i += MAX_COLLATION_WEIGHTS) {		if (!memcmp(ruletable_buffer + i, rbuf, MAX_COLLATION_WEIGHTS*sizeof(ruletable_buffer[0]))) {			return i/MAX_COLLATION_WEIGHTS;		}	}	memcpy(ruletable_buffer + ruletable_len, rbuf, MAX_COLLATION_WEIGHTS*sizeof(ruletable_buffer[0]));	ruletable_len += MAX_COLLATION_WEIGHTS;	return  (ruletable_len / MAX_COLLATION_WEIGHTS)-1;}#define DUMPn(X) fprintf(stderr, "%10d-%-.20s", base_locale_array[n]. X, #X);static void dump_base_locale(int n){	assert(n < base_locale_len);	fprintf(stderr, "Base Locale: %s\n", base_locale_array[n].name);	DUMPn(num_weights);	DUMPn(ii_shift);	DUMPn(ti_shift);	DUMPn(ii_len);	DUMPn(ti_len);	DUMPn(max_weight);	fprintf(stderr, "\n");	DUMPn(num_col_base);	DUMPn(max_col_index);	DUMPn(undefined_idx);	DUMPn(range_low);	DUMPn(range_count);	fprintf(stderr, "\n");	DUMPn(range_base_weight);	DUMPn(num_starters);	fprintf(stderr, "\n");	DUMPn(range_rule_offset);	DUMPn(wcs2colidt_offset);	DUMPn(index2weight_offset);	fprintf(stderr, "\n");	DUMPn(index2ruleidx_offset);	DUMPn(multistart_offset);	fprintf(stderr, "\n");}#undef DUMPn#define DUMPn(X) fprintf(stderr, "%10d-%s", der_locale_array[n]. X, #X);static void dump_der_locale(int n){	assert(n < der_locale_len);	fprintf(stderr, "Derived Locale: %s (%.12s)",			der_locale_array[n].name,			base_locale_array[der_locale_array[n].base_idx].name);	DUMPn(base_idx);	DUMPn(undefined_idx);		DUMPn(overrides_offset);	DUMPn(multistart_offset);	fprintf(stderr, "\n");}static unsigned long collate_pos;static void dump_u16_array(FILE *fp, uint16_t *u, int len, const char *name){	int i;	fprintf(fp, "\t/* %8lu %s */\n", collate_pos, name);	for (i=0 ; i < len ; i++) {		if (!(i & 7)) {			fprintf(fp, "\n\t");		}		fprintf(fp,"  %#06x,", (unsigned int)(u[i]));	}	fprintf(fp,"\n");	collate_pos += len;}#define OUT_U16C(X,N) fprintf(fp,"\t%10d, /* %8lu %s */\n", X, collate_pos++, N); static void dump_collate(FILE *fp){	int n;	fprintf(fp, "const uint16_t __locale_collate_tbl[] = {\n");	OUT_U16C(base_locale_len, "numbef of base locales");	OUT_U16C(der_locale_len, "number of derived locales");	OUT_U16C(MAX_COLLATION_WEIGHTS, "max collation weights");	OUT_U16C(index2weight_len, "number of index2{weight|ruleidx} elements");	OUT_U16C(weightstr_len, "number of weightstr elements");	OUT_U16C(multistart_len, "number of multistart elements");	OUT_U16C(override_len, "number of override elements");	OUT_U16C(ruletable_len, "number of ruletable elements");#undef DUMPn#define DUMPn(X) fprintf(fp, "\t%10d, /* %8lu %s */\n", base_locale_array[n]. X, collate_pos++, #X);	for (n=0 ; n < base_locale_len ; n++) {		unsigned wcs2colidt_offset_low = base_locale_array[n].wcs2colidt_offset & 0xffffU;		unsigned wcs2colidt_offset_hi = base_locale_array[n].wcs2colidt_offset >> 16;		fprintf(fp, "\t/* Base Locale %2d: %s */\n", n, base_locale_array[n].name);		DUMPn(num_weights);		DUMPn(num_starters);		DUMPn(ii_shift);		DUMPn(ti_shift);		DUMPn(ii_len);		DUMPn(ti_len);		DUMPn(max_weight);		DUMPn(num_col_base);		DUMPn(max_col_index);		DUMPn(undefined_idx);		DUMPn(range_low);		DUMPn(range_count);		DUMPn(range_base_weight);		DUMPn(range_rule_offset);		DUMPn(index2weight_offset);		DUMPn(index2ruleidx_offset);		DUMPn(multistart_offset);#undef DUMPn#define DUMPn(X) fprintf(fp, "\t%10d, /* %8lu %s */\n", X, collate_pos++, #X);		DUMPn(wcs2colidt_offset_low);		DUMPn(wcs2colidt_offset_hi);	}#undef DUMPn			fprintf(fp, "#define COL_IDX_C     %5d\n", 0);#define DUMPn(X) fprintf(fp, "\t%10d, /* %8lu %s */\n", der_locale_array[n]. X, collate_pos++, #X);	for (n=0 ; n < der_locale_len ; n++) {		fprintf(fp, "#define COL_IDX_%s %5d\n", der_locale_array[n].name, n+1);		fprintf(fp, "\t/* Derived Locale %4d: %s (%.12s) */\n",				n, der_locale_array[n].name,				base_locale_array[der_locale_array[n].base_idx].name);		DUMPn(base_idx);		DUMPn(undefined_idx);		DUMPn(overrides_offset);		DUMPn(multistart_offset);	}#undef DUMPn	fprintf(fp, "\n");	dump_u16_array(fp, index2weight_buffer, index2weight_len, "index2weight");	dump_u16_array(fp, index2ruleidx_buffer, index2ruleidx_len, "index2ruleidx");	dump_u16_array(fp, multistart_buffer, multistart_len, "multistart");	dump_u16_array(fp, override_buffer, override_len, "override");	dump_u16_array(fp, ruletable_buffer, ruletable_len, "ruletable");	dump_u16_array(fp, weightstr_buffer, weightstr_len, "weightstr");	dump_u16_array(fp, wcs2colidt_buffer, wcs2colidt_len, "wcs2colidt");	fprintf(fp,"}; /* %8lu */\n", collate_pos);	fprintf(fp,"#define __lc_collate_data_LEN  %d\n\n", collate_pos);}
 |