xref: /plan9/sys/src/cmd/dict/utils.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <bio.h>
4*219b2ee8SDavid du Colombier #include <stdarg.h>
5*219b2ee8SDavid du Colombier #include "dict.h"
6*219b2ee8SDavid du Colombier 
7*219b2ee8SDavid du Colombier Dict dicts[] = {
8*219b2ee8SDavid du Colombier 	{"oed",		"Oxford English Dictionary, 2nd Ed.",
9*219b2ee8SDavid du Colombier 	 "/lib/dict/oed2",	"/lib/dict/oed2index",
10*219b2ee8SDavid du Colombier 	 oednextoff,	oedprintentry,		oedprintkey},
11*219b2ee8SDavid du Colombier 	{"ahd",		"American Heritage Dictionary, 2nd College Ed.",
12*219b2ee8SDavid du Colombier 	 "/lib/ahd/DICT.DB",	"/lib/ahd/index",
13*219b2ee8SDavid du Colombier 	 ahdnextoff,	ahdprintentry,		ahdprintkey},
14*219b2ee8SDavid du Colombier 	{"thesaurus",	"Collins Thesaurus",
15*219b2ee8SDavid du Colombier 	 "/lib/dict/thesaurus",	"/lib/dict/thesindex",
16*219b2ee8SDavid du Colombier 	 thesnextoff,	thesprintentry,	thesprintkey},
17*219b2ee8SDavid du Colombier 
18*219b2ee8SDavid du Colombier 	{"ce",		"Gendai Chinese->English",
19*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic24.dat",
20*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/ceindex",
21*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
22*219b2ee8SDavid du Colombier 	{"ceh",		"Gendai Chinese->English (Hanzi index)",
23*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic24.dat",
24*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/cehindex",
25*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
26*219b2ee8SDavid du Colombier 	{"ec",		"Gendai English->Chinese",
27*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic24.dat",
28*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/ecindex",
29*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
30*219b2ee8SDavid du Colombier 
31*219b2ee8SDavid du Colombier 	{"dae",		"Gyldendal Danish->English",
32*219b2ee8SDavid du Colombier 	 "/lib/dict/world/gylddata/sandic30.dat",
33*219b2ee8SDavid du Colombier 	 "/lib/dict/world/gylddata/daeindex",
34*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
35*219b2ee8SDavid du Colombier 	{"eda",		"Gyldendal English->Danish",
36*219b2ee8SDavid du Colombier 	 "/lib/dict/world/gylddata/sandic29.dat",
37*219b2ee8SDavid du Colombier 	 "/lib/dict/world/gylddata/edaindex",
38*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
39*219b2ee8SDavid du Colombier 
40*219b2ee8SDavid du Colombier 	{"due",		"Wolters-Noordhoff Dutch->English",
41*219b2ee8SDavid du Colombier 	 "/lib/dict/world/woltdata/sandic07.dat",
42*219b2ee8SDavid du Colombier 	 "/lib/dict/world/woltdata/deindex",
43*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
44*219b2ee8SDavid du Colombier 	{"edu",		"Wolters-Noordhoff English->Dutch",
45*219b2ee8SDavid du Colombier 	 "/lib/dict/world/woltdata/sandic06.dat",
46*219b2ee8SDavid du Colombier 	 "/lib/dict/world/woltdata/edindex",
47*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
48*219b2ee8SDavid du Colombier 
49*219b2ee8SDavid du Colombier 	{"fie",		"WSOY Finnish->English",
50*219b2ee8SDavid du Colombier 	 "/lib/dict/world/werndata/sandic32.dat",
51*219b2ee8SDavid du Colombier 	 "/lib/dict/world/werndata/fieindex",
52*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
53*219b2ee8SDavid du Colombier 	{"efi",		"WSOY English->Finnish",
54*219b2ee8SDavid du Colombier 	 "/lib/dict/world/werndata/sandic31.dat",
55*219b2ee8SDavid du Colombier 	 "/lib/dict/world/werndata/efiindex",
56*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
57*219b2ee8SDavid du Colombier 
58*219b2ee8SDavid du Colombier 	{"fe",		"Collins French->English",
59*219b2ee8SDavid du Colombier 	 "/lib/dict/fe",	"/lib/dict/feindex",
60*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
61*219b2ee8SDavid du Colombier 	{"ef",		"Collins English->French",
62*219b2ee8SDavid du Colombier 	 "/lib/dict/ef",	"/lib/dict/efindex",
63*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
64*219b2ee8SDavid du Colombier 
65*219b2ee8SDavid du Colombier 	{"ge",		"Collins German->English",
66*219b2ee8SDavid du Colombier 	 "/lib/dict/ge",	"/lib/dict/geindex",
67*219b2ee8SDavid du Colombier 	 pcollgnextoff,	pcollgprintentry,	pcollgprintkey},
68*219b2ee8SDavid du Colombier 	{"eg",		"Collins English->German",
69*219b2ee8SDavid du Colombier 	 "/lib/dict/eg",	"/lib/dict/egindex",
70*219b2ee8SDavid du Colombier 	 pcollgnextoff,	pcollgprintentry,	pcollgprintkey},
71*219b2ee8SDavid du Colombier 
72*219b2ee8SDavid du Colombier 	{"ie",		"Collins Italian->English",
73*219b2ee8SDavid du Colombier 	 "/lib/dict/ie",	"/lib/dict/ieindex",
74*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
75*219b2ee8SDavid du Colombier 	{"ei",		"Collins English->Italian",
76*219b2ee8SDavid du Colombier 	 "/lib/dict/ei",	"/lib/dict/eiindex",
77*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
78*219b2ee8SDavid du Colombier 
79*219b2ee8SDavid du Colombier 	{"je",		"Sanshusha Japanese->English",
80*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic18.dat",
81*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/jeindex",
82*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
83*219b2ee8SDavid du Colombier 	{"jek",		"Sanshusha Japanese->English (Kanji index)",
84*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic18.dat",
85*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/jekindex",
86*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
87*219b2ee8SDavid du Colombier 	{"ej",		"Sanshusha English->Japanese",
88*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic18.dat",
89*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/ejindex",
90*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
91*219b2ee8SDavid du Colombier 
92*219b2ee8SDavid du Colombier 	{"tjeg",	"Sanshusha technical Japanese->English,German",
93*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic16.dat",
94*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/tjegindex",
95*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
96*219b2ee8SDavid du Colombier 	{"tjegk",	"Sanshusha technical Japanese->English,German (Kanji index)",
97*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic16.dat",
98*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/tjegkindex",
99*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
100*219b2ee8SDavid du Colombier 	{"tegj",	"Sanshusha technical English->German,Japanese",
101*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic16.dat",
102*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/tegjindex",
103*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
104*219b2ee8SDavid du Colombier 	{"tgje",	"Sanshusha technical German->Japanese,English",
105*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/sandic16.dat",
106*219b2ee8SDavid du Colombier 	 "/lib/dict/world/sansdata/tgjeindex",
107*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
108*219b2ee8SDavid du Colombier 
109*219b2ee8SDavid du Colombier 	{"ne",		"Kunnskapforlaget Norwegian->English",
110*219b2ee8SDavid du Colombier 	 "/lib/dict/world/kunndata/sandic28.dat",
111*219b2ee8SDavid du Colombier 	 "/lib/dict/world/kunndata/neindex",
112*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
113*219b2ee8SDavid du Colombier 	{"en",		"Kunnskapforlaget English->Norwegian",
114*219b2ee8SDavid du Colombier 	 "/lib/dict/world/kunndata/sandic27.dat",
115*219b2ee8SDavid du Colombier 	 "/lib/dict/world/kunndata/enindex",
116*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
117*219b2ee8SDavid du Colombier 
118*219b2ee8SDavid du Colombier 	{"re",		"Leon Ungier Russian->English",
119*219b2ee8SDavid du Colombier 	 "/lib/dict/re",	"/lib/dict/reindex",
120*219b2ee8SDavid du Colombier 	 simplenextoff,	simpleprintentry,	simpleprintkey},
121*219b2ee8SDavid du Colombier 	{"er",		"Leon Ungier English->Russian",
122*219b2ee8SDavid du Colombier 	 "/lib/dict/re",	"/lib/dict/erindex",
123*219b2ee8SDavid du Colombier 	 simplenextoff,	simpleprintentry,	simpleprintkey},
124*219b2ee8SDavid du Colombier 
125*219b2ee8SDavid du Colombier 	{"se",		"Collins Spanish->English",
126*219b2ee8SDavid du Colombier 	 "/lib/dict/se",	"/lib/dict/seindex",
127*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
128*219b2ee8SDavid du Colombier 	{"es",		"Collins English->Spanish",
129*219b2ee8SDavid du Colombier 	 "/lib/dict/es",	"/lib/dict/esindex",
130*219b2ee8SDavid du Colombier 	 pcollnextoff,	pcollprintentry,	pcollprintkey},
131*219b2ee8SDavid du Colombier 
132*219b2ee8SDavid du Colombier 	{"swe",		"Esselte Studium Swedish->English",
133*219b2ee8SDavid du Colombier 	 "/lib/dict/world/essedata/sandic34.dat",
134*219b2ee8SDavid du Colombier 	 "/lib/dict/world/essedata/sweindex",
135*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
136*219b2ee8SDavid du Colombier 	{"esw",		"Esselte Studium English->Swedish",
137*219b2ee8SDavid du Colombier 	 "/lib/dict/world/essedata/sandic33.dat",
138*219b2ee8SDavid du Colombier 	 "/lib/dict/world/essedata/eswindex",
139*219b2ee8SDavid du Colombier 	 worldnextoff,	worldprintentry,	worldprintkey},
140*219b2ee8SDavid du Colombier 
141*219b2ee8SDavid du Colombier 	{"movie",	"Movies -- by title",
142*219b2ee8SDavid du Colombier 	 "/lib/movie/data",	"/lib/dict/movtindex",
143*219b2ee8SDavid du Colombier 	 movienextoff,	movieprintentry,	movieprintkey},
144*219b2ee8SDavid du Colombier 	{"moviea",	"Movies -- by actor",
145*219b2ee8SDavid du Colombier 	 "/lib/movie/data",	"/lib/dict/movaindex",
146*219b2ee8SDavid du Colombier 	 movienextoff,	movieprintentry,	movieprintkey},
147*219b2ee8SDavid du Colombier 	{"movied",	"Movies -- by director",
148*219b2ee8SDavid du Colombier 	 "/lib/movie/data",	"/lib/dict/movdindex",
149*219b2ee8SDavid du Colombier 	 movienextoff,	movieprintentry,	movieprintkey},
150*219b2ee8SDavid du Colombier 
151*219b2ee8SDavid du Colombier 	{"slang",	"English Slang",
152*219b2ee8SDavid du Colombier 	 "/lib/dict/slang",	"/lib/dict/slangindex",
153*219b2ee8SDavid du Colombier 	 slangnextoff,	slangprintentry,	slangprintkey},
154*219b2ee8SDavid du Colombier 
155*219b2ee8SDavid du Colombier 	{"robert",	"Robert Électronique",
156*219b2ee8SDavid du Colombier 	 "/lib/dict/robert/_pointers",	"/lib/dict/robert/_index",
157*219b2ee8SDavid du Colombier 	 robertnextoff,	robertindexentry,	robertprintkey},
158*219b2ee8SDavid du Colombier 	{"robertv",	"Robert Électronique - formes des verbes",
159*219b2ee8SDavid du Colombier 	 "/lib/dict/robert/flex.rob",	"/lib/dict/robert/_flexindex",
160*219b2ee8SDavid du Colombier 	 robertnextflex,	robertflexentry,	robertprintkey},
161*219b2ee8SDavid du Colombier 
162*219b2ee8SDavid du Colombier 	{0, 0, 0, 0, 0}
163*219b2ee8SDavid du Colombier };
164*219b2ee8SDavid du Colombier 
165*219b2ee8SDavid du Colombier typedef struct Lig Lig;
166*219b2ee8SDavid du Colombier struct Lig {
167*219b2ee8SDavid du Colombier 	Rune	start;		/* accent rune */
168*219b2ee8SDavid du Colombier 	Rune	*pairs;		/* <char,accented version> pairs */
169*219b2ee8SDavid du Colombier };
170*219b2ee8SDavid du Colombier 
171*219b2ee8SDavid du Colombier static Lig ligtab[Nligs] = {
172*219b2ee8SDavid du Colombier [LACU-LIGS]	{L'´',	L"AÁaáCĆcćEÉeégģIÍiíıíLĹlĺNŃnńOÓoóRŔrŕSŚsśUÚuúYÝyýZŹzź"},
173*219b2ee8SDavid du Colombier [LGRV-LIGS]	{L'ˋ',	L"AÀaàEÈeèIÌiìıìOÒoòUÙuù"},
174*219b2ee8SDavid du Colombier [LUML-LIGS]	{L'¨',	L"AÄaäEËeëIÏiïOÖoöUÜuüYŸyÿ"},
175*219b2ee8SDavid du Colombier [LCED-LIGS]	{L'¸',	L"CÇcçGĢKĶkķLĻlļNŅnņRŖrŗSŞsşTŢtţ"},
176*219b2ee8SDavid du Colombier [LTIL-LIGS]	{L'˜',	L"AÃaãIĨiĩıĩNÑnñOÕoõUŨuũ"},
177*219b2ee8SDavid du Colombier [LBRV-LIGS]	{L'˘',	L"AĂaăEĔeĕGĞgğIĬiĭıĭOŎoŏUŬuŭ"},
178*219b2ee8SDavid du Colombier [LRNG-LIGS]	{L'˚',	L"AÅaåUŮuů"},
179*219b2ee8SDavid du Colombier [LDOT-LIGS]	{L'˙',	L"CĊcċEĖeėGĠgġIİLĿlŀZŻzż"},
180*219b2ee8SDavid du Colombier [LDTB-LIGS]	{L'.',	L""},
181*219b2ee8SDavid du Colombier [LFRN-LIGS]	{L'⌢',	L"AÂaâCĈcĉEÊeêGĜgĝHĤhĥIÎiîıîJĴjĵOÔoôSŜsŝUÛuûWŴwŵYŶyŷ"},
182*219b2ee8SDavid du Colombier [LFRB-LIGS]	{L'̯',	L""},
183*219b2ee8SDavid du Colombier [LOGO-LIGS]	{L'˛',	L"AĄaąEĘeęIĮiįıįUŲuų"},
184*219b2ee8SDavid du Colombier [LMAC-LIGS]	{L'¯',	L"AĀaāEĒeēIĪiīıīOŌoōUŪuū"},
185*219b2ee8SDavid du Colombier [LHCK-LIGS]	{L'ˇ',	L"CČcčDĎdďEĚeěLĽlľNŇnňRŘrřSŠsšTŤtťZŽzž"},
186*219b2ee8SDavid du Colombier [LASP-LIGS]	{L'ʽ',	L""},
187*219b2ee8SDavid du Colombier [LLEN-LIGS]	{L'ʼ',	L""},
188*219b2ee8SDavid du Colombier [LBRB-LIGS]	{L'̮',	L""}
189*219b2ee8SDavid du Colombier };
190*219b2ee8SDavid du Colombier 
191*219b2ee8SDavid du Colombier Rune *multitab[Nmulti] = {
192*219b2ee8SDavid du Colombier [MAAS-MULTI]	L"ʽα",
193*219b2ee8SDavid du Colombier [MALN-MULTI]	L"ʼα",
194*219b2ee8SDavid du Colombier [MAND-MULTI]	L"and",
195*219b2ee8SDavid du Colombier [MAOQ-MULTI]	L"a/q",
196*219b2ee8SDavid du Colombier [MBRA-MULTI]	L"<|",
197*219b2ee8SDavid du Colombier [MDD-MULTI]	L"..",
198*219b2ee8SDavid du Colombier [MDDD-MULTI]	L"...",
199*219b2ee8SDavid du Colombier [MEAS-MULTI]	L"ʽε",
200*219b2ee8SDavid du Colombier [MELN-MULTI]	L"ʼε",
201*219b2ee8SDavid du Colombier [MEMM-MULTI]	L"——",
202*219b2ee8SDavid du Colombier [MHAS-MULTI]	L"ʽη",
203*219b2ee8SDavid du Colombier [MHLN-MULTI]	L"ʼη",
204*219b2ee8SDavid du Colombier [MIAS-MULTI]	L"ʽι",
205*219b2ee8SDavid du Colombier [MILN-MULTI]	L"ʼι",
206*219b2ee8SDavid du Colombier [MLCT-MULTI]	L"ct",
207*219b2ee8SDavid du Colombier [MLFF-MULTI]	L"ff",
208*219b2ee8SDavid du Colombier [MLFFI-MULTI]	L"ffi",
209*219b2ee8SDavid du Colombier [MLFFL-MULTI]	L"ffl",
210*219b2ee8SDavid du Colombier [MLFL-MULTI]	L"fl",
211*219b2ee8SDavid du Colombier [MLFI-MULTI]	L"fi",
212*219b2ee8SDavid du Colombier [MLLS-MULTI]	L"ɫɫ",
213*219b2ee8SDavid du Colombier [MLST-MULTI]	L"st",
214*219b2ee8SDavid du Colombier [MOAS-MULTI]	L"ʽο",
215*219b2ee8SDavid du Colombier [MOLN-MULTI]	L"ʼο",
216*219b2ee8SDavid du Colombier [MOR-MULTI]	L"or",
217*219b2ee8SDavid du Colombier [MRAS-MULTI]	L"ʽρ",
218*219b2ee8SDavid du Colombier [MRLN-MULTI]	L"ʼρ",
219*219b2ee8SDavid du Colombier [MTT-MULTI]	L"~~",
220*219b2ee8SDavid du Colombier [MUAS-MULTI]	L"ʽυ",
221*219b2ee8SDavid du Colombier [MULN-MULTI]	L"ʼυ",
222*219b2ee8SDavid du Colombier [MWAS-MULTI]	L"ʽω",
223*219b2ee8SDavid du Colombier [MWLN-MULTI]	L"ʼω",
224*219b2ee8SDavid du Colombier [MOE-MULTI]	L"oe",
225*219b2ee8SDavid du Colombier [MES-MULTI]	L"  ",
226*219b2ee8SDavid du Colombier };
227*219b2ee8SDavid du Colombier 
228*219b2ee8SDavid du Colombier #define	risupper(r)	(L'A' <= (r) && (r) <= L'Z')
229*219b2ee8SDavid du Colombier #define	rislatin1(r)	(0xC0 <= (r) && (r) <= 0xFF)
230*219b2ee8SDavid du Colombier #define	rtolower(r)	((r)-'A'+'a')
231*219b2ee8SDavid du Colombier 
232*219b2ee8SDavid du Colombier static Rune latin_fold_tab[] =
233*219b2ee8SDavid du Colombier {
234*219b2ee8SDavid du Colombier /*	Table to fold latin 1 characters to ASCII equivalents
235*219b2ee8SDavid du Colombier 			based at Rune value 0xc0
236*219b2ee8SDavid du Colombier 
237*219b2ee8SDavid du Colombier 	 À    Á    Â    Ã    Ä    Å    Æ    Ç
238*219b2ee8SDavid du Colombier 	 È    É    Ê    Ë    Ì    Í    Î    Ï
239*219b2ee8SDavid du Colombier 	 Ð    Ñ    Ò    Ó    Ô    Õ    Ö    ×
240*219b2ee8SDavid du Colombier 	 Ø    Ù    Ú    Û    Ü    Ý    Þ    ß
241*219b2ee8SDavid du Colombier 	 à    á    â    ã    ä    å    æ    ç
242*219b2ee8SDavid du Colombier 	 è    é    ê    ë    ì    í    î    ï
243*219b2ee8SDavid du Colombier 	 ð    ñ    ò    ó    ô    õ    ö    ÷
244*219b2ee8SDavid du Colombier 	 ø    ù    ú    û    ü    ý    þ    ÿ
245*219b2ee8SDavid du Colombier */
246*219b2ee8SDavid du Colombier 	'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
247*219b2ee8SDavid du Colombier 	'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
248*219b2ee8SDavid du Colombier 	'd', 'n', 'o', 'o', 'o', 'o', 'o',  0 ,
249*219b2ee8SDavid du Colombier 	'o', 'u', 'u', 'u', 'u', 'y',  0 ,  0 ,
250*219b2ee8SDavid du Colombier 	'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c',
251*219b2ee8SDavid du Colombier 	'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i',
252*219b2ee8SDavid du Colombier 	'd', 'n', 'o', 'o', 'o', 'o', 'o',  0 ,
253*219b2ee8SDavid du Colombier 	'o', 'u', 'u', 'u', 'u', 'y',  0 , 'y',
254*219b2ee8SDavid du Colombier };
255*219b2ee8SDavid du Colombier 
256*219b2ee8SDavid du Colombier static Rune 	*ttabstack[20];
257*219b2ee8SDavid du Colombier static int	ntt;
258*219b2ee8SDavid du Colombier 
259*219b2ee8SDavid du Colombier /*
260*219b2ee8SDavid du Colombier  * tab is an array of n Assoc's, sorted by key.
261*219b2ee8SDavid du Colombier  * Look for key in tab, and return corresponding val
262*219b2ee8SDavid du Colombier  * or -1 if not there
263*219b2ee8SDavid du Colombier  */
264*219b2ee8SDavid du Colombier long
265*219b2ee8SDavid du Colombier lookassoc(Assoc *tab, int n, char *key)
266*219b2ee8SDavid du Colombier {
267*219b2ee8SDavid du Colombier 	Assoc *q;
268*219b2ee8SDavid du Colombier 	long i, low, high;
269*219b2ee8SDavid du Colombier 	int r;
270*219b2ee8SDavid du Colombier 
271*219b2ee8SDavid du Colombier 	for(low = -1, high = n; high > low+1; ){
272*219b2ee8SDavid du Colombier 		i = (high+low)/2;
273*219b2ee8SDavid du Colombier 		q = &tab[i];
274*219b2ee8SDavid du Colombier 		if((r=strcmp(key, q->key))<0)
275*219b2ee8SDavid du Colombier 			high = i;
276*219b2ee8SDavid du Colombier 		else if(r == 0)
277*219b2ee8SDavid du Colombier 			return q->val;
278*219b2ee8SDavid du Colombier 		else
279*219b2ee8SDavid du Colombier 			low=i;
280*219b2ee8SDavid du Colombier 	}
281*219b2ee8SDavid du Colombier 	return -1;
282*219b2ee8SDavid du Colombier }
283*219b2ee8SDavid du Colombier 
284*219b2ee8SDavid du Colombier long
285*219b2ee8SDavid du Colombier looknassoc(Nassoc *tab, int n, long key)
286*219b2ee8SDavid du Colombier {
287*219b2ee8SDavid du Colombier 	Nassoc *q;
288*219b2ee8SDavid du Colombier 	long i, low, high;
289*219b2ee8SDavid du Colombier 
290*219b2ee8SDavid du Colombier 	for(low = -1, high = n; high > low+1; ){
291*219b2ee8SDavid du Colombier 		i = (high+low)/2;
292*219b2ee8SDavid du Colombier 		q = &tab[i];
293*219b2ee8SDavid du Colombier 		if(key < q->key)
294*219b2ee8SDavid du Colombier 			high = i;
295*219b2ee8SDavid du Colombier 		else if(key == q->key)
296*219b2ee8SDavid du Colombier 			return q->val;
297*219b2ee8SDavid du Colombier 		else
298*219b2ee8SDavid du Colombier 			low=i;
299*219b2ee8SDavid du Colombier 	}
300*219b2ee8SDavid du Colombier 	return -1;
301*219b2ee8SDavid du Colombier }
302*219b2ee8SDavid du Colombier 
303*219b2ee8SDavid du Colombier void
304*219b2ee8SDavid du Colombier err(char *fmt, ...)
305*219b2ee8SDavid du Colombier {
306*219b2ee8SDavid du Colombier 	char buf[1000];
307*219b2ee8SDavid du Colombier 	va_list v;
308*219b2ee8SDavid du Colombier 
309*219b2ee8SDavid du Colombier 	va_start(v, fmt);
310*219b2ee8SDavid du Colombier 	doprint(buf, &buf[1000], fmt, v);
311*219b2ee8SDavid du Colombier 	va_end(v);
312*219b2ee8SDavid du Colombier 	fprint(2, "%s: %s\n", argv0, buf);
313*219b2ee8SDavid du Colombier }
314*219b2ee8SDavid du Colombier 
315*219b2ee8SDavid du Colombier /*
316*219b2ee8SDavid du Colombier  * Write the rune r to bout, keeping track of line length
317*219b2ee8SDavid du Colombier  * and breaking the lines (at blanks) when they get too long
318*219b2ee8SDavid du Colombier  */
319*219b2ee8SDavid du Colombier void
320*219b2ee8SDavid du Colombier outrune(long r)
321*219b2ee8SDavid du Colombier {
322*219b2ee8SDavid du Colombier 	if(outinhibit)
323*219b2ee8SDavid du Colombier 		return;
324*219b2ee8SDavid du Colombier 	if(++linelen > breaklen && r == L' ') {
325*219b2ee8SDavid du Colombier 		Bputc(bout, '\n');
326*219b2ee8SDavid du Colombier 		linelen = 0;
327*219b2ee8SDavid du Colombier 	} else
328*219b2ee8SDavid du Colombier 		Bputrune(bout, r);
329*219b2ee8SDavid du Colombier }
330*219b2ee8SDavid du Colombier 
331*219b2ee8SDavid du Colombier void
332*219b2ee8SDavid du Colombier outrunes(Rune *rp)
333*219b2ee8SDavid du Colombier {
334*219b2ee8SDavid du Colombier 	Rune r;
335*219b2ee8SDavid du Colombier 
336*219b2ee8SDavid du Colombier 	while((r = *rp++) != 0)
337*219b2ee8SDavid du Colombier 		outrune(r);
338*219b2ee8SDavid du Colombier }
339*219b2ee8SDavid du Colombier 
340*219b2ee8SDavid du Colombier /* like outrune, but when arg is know to be a char */
341*219b2ee8SDavid du Colombier void
342*219b2ee8SDavid du Colombier outchar(int c)
343*219b2ee8SDavid du Colombier {
344*219b2ee8SDavid du Colombier 	if(outinhibit)
345*219b2ee8SDavid du Colombier 		return;
346*219b2ee8SDavid du Colombier 	if(++linelen > breaklen && c == ' ') {
347*219b2ee8SDavid du Colombier 		c ='\n';
348*219b2ee8SDavid du Colombier 		linelen = 0;
349*219b2ee8SDavid du Colombier 	}
350*219b2ee8SDavid du Colombier 	BPUTC(bout, c);
351*219b2ee8SDavid du Colombier }
352*219b2ee8SDavid du Colombier 
353*219b2ee8SDavid du Colombier void
354*219b2ee8SDavid du Colombier outchars(char *s)
355*219b2ee8SDavid du Colombier {
356*219b2ee8SDavid du Colombier 	char c;
357*219b2ee8SDavid du Colombier 
358*219b2ee8SDavid du Colombier 	while((c = *s++) != 0)
359*219b2ee8SDavid du Colombier 		outchar(c);
360*219b2ee8SDavid du Colombier }
361*219b2ee8SDavid du Colombier 
362*219b2ee8SDavid du Colombier void
363*219b2ee8SDavid du Colombier outprint(char *fmt, ...)
364*219b2ee8SDavid du Colombier {
365*219b2ee8SDavid du Colombier 	char buf[1000];
366*219b2ee8SDavid du Colombier 	va_list v;
367*219b2ee8SDavid du Colombier 
368*219b2ee8SDavid du Colombier 	va_start(v, fmt);
369*219b2ee8SDavid du Colombier 	doprint(buf, &buf[1000], fmt, v);
370*219b2ee8SDavid du Colombier 	va_end(v);
371*219b2ee8SDavid du Colombier 	outchars(buf);
372*219b2ee8SDavid du Colombier }
373*219b2ee8SDavid du Colombier 
374*219b2ee8SDavid du Colombier void
375*219b2ee8SDavid du Colombier outpiece(char *b, char *e)
376*219b2ee8SDavid du Colombier {
377*219b2ee8SDavid du Colombier 	int c, lastc;
378*219b2ee8SDavid du Colombier 
379*219b2ee8SDavid du Colombier 	lastc = 0;
380*219b2ee8SDavid du Colombier 	while(b < e) {
381*219b2ee8SDavid du Colombier 		c = *b++;
382*219b2ee8SDavid du Colombier 		if(c == '\n')
383*219b2ee8SDavid du Colombier 			c = ' ';
384*219b2ee8SDavid du Colombier 		if(!(c == ' ' && lastc == ' '))
385*219b2ee8SDavid du Colombier 			outchar(c);
386*219b2ee8SDavid du Colombier 		lastc = c;
387*219b2ee8SDavid du Colombier 	}
388*219b2ee8SDavid du Colombier }
389*219b2ee8SDavid du Colombier 
390*219b2ee8SDavid du Colombier /*
391*219b2ee8SDavid du Colombier  * Go to new line if not already there; indent if ind != 0.
392*219b2ee8SDavid du Colombier  * If ind > 1, leave a blank line too.
393*219b2ee8SDavid du Colombier  * Slight hack: assume if current line is only one or two
394*219b2ee8SDavid du Colombier  * characters long, then they were spaces.
395*219b2ee8SDavid du Colombier  */
396*219b2ee8SDavid du Colombier void
397*219b2ee8SDavid du Colombier outnl(int ind)
398*219b2ee8SDavid du Colombier {
399*219b2ee8SDavid du Colombier 	if(outinhibit)
400*219b2ee8SDavid du Colombier 		return;
401*219b2ee8SDavid du Colombier 	if(ind) {
402*219b2ee8SDavid du Colombier 		if(ind > 1) {
403*219b2ee8SDavid du Colombier 			if(linelen > 2)
404*219b2ee8SDavid du Colombier 				Bputc(bout, '\n');
405*219b2ee8SDavid du Colombier 			Bprint(bout, "\n  ");
406*219b2ee8SDavid du Colombier 		} else if(linelen == 0)
407*219b2ee8SDavid du Colombier 			Bprint(bout, "  ");
408*219b2ee8SDavid du Colombier 		else if(linelen == 1)
409*219b2ee8SDavid du Colombier 			Bputc(bout, ' ');
410*219b2ee8SDavid du Colombier 		else if(linelen != 2)
411*219b2ee8SDavid du Colombier 			Bprint(bout, "\n  ");
412*219b2ee8SDavid du Colombier 		linelen = 2;
413*219b2ee8SDavid du Colombier 	} else {
414*219b2ee8SDavid du Colombier 		if(linelen) {
415*219b2ee8SDavid du Colombier 			Bputc(bout, '\n');
416*219b2ee8SDavid du Colombier 			linelen = 0;
417*219b2ee8SDavid du Colombier 		}
418*219b2ee8SDavid du Colombier 	}
419*219b2ee8SDavid du Colombier }
420*219b2ee8SDavid du Colombier 
421*219b2ee8SDavid du Colombier /*
422*219b2ee8SDavid du Colombier  * Fold the runes in null-terminated rp.
423*219b2ee8SDavid du Colombier  * Use the sort(1) definition of folding (uppercase to lowercase,
424*219b2ee8SDavid du Colombier  * latin1-accented characters to corresponding unaccented chars)
425*219b2ee8SDavid du Colombier  */
426*219b2ee8SDavid du Colombier void
427*219b2ee8SDavid du Colombier fold(Rune *rp)
428*219b2ee8SDavid du Colombier {
429*219b2ee8SDavid du Colombier 	Rune r;
430*219b2ee8SDavid du Colombier 
431*219b2ee8SDavid du Colombier 	while((r = *rp) != 0) {
432*219b2ee8SDavid du Colombier 		if (rislatin1(r) && latin_fold_tab[r-0xc0])
433*219b2ee8SDavid du Colombier 				r = latin_fold_tab[r-0xc0];
434*219b2ee8SDavid du Colombier 		if(risupper(r))
435*219b2ee8SDavid du Colombier 			r = rtolower(r);
436*219b2ee8SDavid du Colombier 		*rp++ = r;
437*219b2ee8SDavid du Colombier 	}
438*219b2ee8SDavid du Colombier }
439*219b2ee8SDavid du Colombier 
440*219b2ee8SDavid du Colombier /*
441*219b2ee8SDavid du Colombier  * Like fold, but put folded result into new
442*219b2ee8SDavid du Colombier  * (assumed to have enough space).
443*219b2ee8SDavid du Colombier  * old is a regular expression, but we know that
444*219b2ee8SDavid du Colombier  * metacharacters aren't affected
445*219b2ee8SDavid du Colombier  */
446*219b2ee8SDavid du Colombier void
447*219b2ee8SDavid du Colombier foldre(char *new, char *old)
448*219b2ee8SDavid du Colombier {
449*219b2ee8SDavid du Colombier 	Rune r;
450*219b2ee8SDavid du Colombier 
451*219b2ee8SDavid du Colombier 	while(*old) {
452*219b2ee8SDavid du Colombier 		old += chartorune(&r, old);
453*219b2ee8SDavid du Colombier 		if (rislatin1(r) && latin_fold_tab[r-0xc0])
454*219b2ee8SDavid du Colombier 				r = latin_fold_tab[r-0xc0];
455*219b2ee8SDavid du Colombier 		if(risupper(r))
456*219b2ee8SDavid du Colombier 			r = rtolower(r);
457*219b2ee8SDavid du Colombier 		new += runetochar(new, &r);
458*219b2ee8SDavid du Colombier 	}
459*219b2ee8SDavid du Colombier 	*new = 0;
460*219b2ee8SDavid du Colombier }
461*219b2ee8SDavid du Colombier 
462*219b2ee8SDavid du Colombier /*
463*219b2ee8SDavid du Colombier  *	acomp(s, t) returns:
464*219b2ee8SDavid du Colombier  *		-2 if s strictly precedes t
465*219b2ee8SDavid du Colombier  *		-1 if s is a prefix of t
466*219b2ee8SDavid du Colombier  *		0 if s is the same as t
467*219b2ee8SDavid du Colombier  *		1 if t is a prefix of s
468*219b2ee8SDavid du Colombier  *		2 if t strictly precedes s
469*219b2ee8SDavid du Colombier  */
470*219b2ee8SDavid du Colombier 
471*219b2ee8SDavid du Colombier int
472*219b2ee8SDavid du Colombier acomp(Rune *s, Rune *t)
473*219b2ee8SDavid du Colombier {
474*219b2ee8SDavid du Colombier 	int cs, ct;
475*219b2ee8SDavid du Colombier 
476*219b2ee8SDavid du Colombier 	for(;;) {
477*219b2ee8SDavid du Colombier 		cs = *s;
478*219b2ee8SDavid du Colombier 		ct = *t;
479*219b2ee8SDavid du Colombier 		if(cs != ct)
480*219b2ee8SDavid du Colombier 			break;
481*219b2ee8SDavid du Colombier 		if(cs == 0)
482*219b2ee8SDavid du Colombier 			return 0;
483*219b2ee8SDavid du Colombier 		s++;
484*219b2ee8SDavid du Colombier 		t++;
485*219b2ee8SDavid du Colombier 	}
486*219b2ee8SDavid du Colombier 	if(cs == 0)
487*219b2ee8SDavid du Colombier 		return -1;
488*219b2ee8SDavid du Colombier 	if(ct == 0)
489*219b2ee8SDavid du Colombier 		return 1;
490*219b2ee8SDavid du Colombier 	if(cs < ct)
491*219b2ee8SDavid du Colombier 		return -2;
492*219b2ee8SDavid du Colombier 	return 2;
493*219b2ee8SDavid du Colombier }
494*219b2ee8SDavid du Colombier 
495*219b2ee8SDavid du Colombier /*
496*219b2ee8SDavid du Colombier  * Copy null terminated Runes from 'from' to 'to'.
497*219b2ee8SDavid du Colombier  */
498*219b2ee8SDavid du Colombier void
499*219b2ee8SDavid du Colombier runescpy(Rune *to, Rune *from)
500*219b2ee8SDavid du Colombier {
501*219b2ee8SDavid du Colombier 	while((*to++ = *from++) != 0)
502*219b2ee8SDavid du Colombier 		continue;
503*219b2ee8SDavid du Colombier }
504*219b2ee8SDavid du Colombier 
505*219b2ee8SDavid du Colombier /*
506*219b2ee8SDavid du Colombier  * Conversion of unsigned number to long, no overflow detection
507*219b2ee8SDavid du Colombier  */
508*219b2ee8SDavid du Colombier long
509*219b2ee8SDavid du Colombier runetol(Rune *r)
510*219b2ee8SDavid du Colombier {
511*219b2ee8SDavid du Colombier 	int c;
512*219b2ee8SDavid du Colombier 	long n;
513*219b2ee8SDavid du Colombier 
514*219b2ee8SDavid du Colombier 	n = 0;
515*219b2ee8SDavid du Colombier 	for(;; r++){
516*219b2ee8SDavid du Colombier 		c = *r;
517*219b2ee8SDavid du Colombier 		if(L'0'<=c && c<=L'9')
518*219b2ee8SDavid du Colombier 			c -= '0';
519*219b2ee8SDavid du Colombier 		else
520*219b2ee8SDavid du Colombier 			break;
521*219b2ee8SDavid du Colombier 		n = n*10 + c;
522*219b2ee8SDavid du Colombier 	}
523*219b2ee8SDavid du Colombier 	return n;
524*219b2ee8SDavid du Colombier }
525*219b2ee8SDavid du Colombier 
526*219b2ee8SDavid du Colombier /*
527*219b2ee8SDavid du Colombier  * See if there is a rune corresponding to the accented
528*219b2ee8SDavid du Colombier  * version of r with accent acc (acc in [LIGS..LIGE-1]),
529*219b2ee8SDavid du Colombier  * and return it if so, else return NONE.
530*219b2ee8SDavid du Colombier  */
531*219b2ee8SDavid du Colombier Rune
532*219b2ee8SDavid du Colombier liglookup(Rune acc, Rune r)
533*219b2ee8SDavid du Colombier {
534*219b2ee8SDavid du Colombier 	Rune *p;
535*219b2ee8SDavid du Colombier 
536*219b2ee8SDavid du Colombier 	if(acc < LIGS || acc >= LIGE)
537*219b2ee8SDavid du Colombier 		return NONE;
538*219b2ee8SDavid du Colombier 	for(p = ligtab[acc-LIGS].pairs; *p; p += 2)
539*219b2ee8SDavid du Colombier 		if(*p == r)
540*219b2ee8SDavid du Colombier 			return *(p+1);
541*219b2ee8SDavid du Colombier 	return NONE;
542*219b2ee8SDavid du Colombier }
543*219b2ee8SDavid du Colombier 
544*219b2ee8SDavid du Colombier /*
545*219b2ee8SDavid du Colombier  * Maintain a translation table stack (a translation table
546*219b2ee8SDavid du Colombier  * is an array of Runes indexed by bytes or 7-bit bytes).
547*219b2ee8SDavid du Colombier  * If starting is true, push the curtab onto the stack
548*219b2ee8SDavid du Colombier  * and return newtab; else pop the top of the stack and
549*219b2ee8SDavid du Colombier  * return it.
550*219b2ee8SDavid du Colombier  * If curtab is 0, initialize the stack and return.
551*219b2ee8SDavid du Colombier  */
552*219b2ee8SDavid du Colombier Rune *
553*219b2ee8SDavid du Colombier changett(Rune *curtab, Rune *newtab, int starting)
554*219b2ee8SDavid du Colombier {
555*219b2ee8SDavid du Colombier 	if(curtab == 0) {
556*219b2ee8SDavid du Colombier 		ntt = 0;
557*219b2ee8SDavid du Colombier 		return 0;
558*219b2ee8SDavid du Colombier 	}
559*219b2ee8SDavid du Colombier 	if(starting) {
560*219b2ee8SDavid du Colombier 		if(ntt >= asize(ttabstack)) {
561*219b2ee8SDavid du Colombier 			if(debug)
562*219b2ee8SDavid du Colombier 				err("translation stack overflow");
563*219b2ee8SDavid du Colombier 			return curtab;
564*219b2ee8SDavid du Colombier 		}
565*219b2ee8SDavid du Colombier 		ttabstack[ntt++] = curtab;
566*219b2ee8SDavid du Colombier 		return newtab;
567*219b2ee8SDavid du Colombier 	} else {
568*219b2ee8SDavid du Colombier 		if(ntt == 0) {
569*219b2ee8SDavid du Colombier 			if(debug)
570*219b2ee8SDavid du Colombier 				err("translation stack underflow");
571*219b2ee8SDavid du Colombier 			return curtab;
572*219b2ee8SDavid du Colombier 		}
573*219b2ee8SDavid du Colombier 		return ttabstack[--ntt];
574*219b2ee8SDavid du Colombier 	}
575*219b2ee8SDavid du Colombier }
576