1 /*
2 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /**
17 * @file picoktab.c
18 *
19 * symbol tables needed at runtime
20 *
21 * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
22 * All rights reserved.
23 *
24 * History:
25 * - 2009-04-20 -- initial version
26 *
27 */
28
29 #include "picoos.h"
30 #include "picodbg.h"
31 #include "picoknow.h"
32 #include "picobase.h"
33 #include "picoktab.h"
34 #include "picodata.h"
35
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39 #if 0
40 }
41 #endif
42
43
44 /** @todo : the following would be better part of a knowledge base.
45 * Make sure it is consistent with the phoneme symbol table used in the lingware */
46
47 /* PLANE_PHONEMES */
48
49 /* PLANE_POS */
50
51 /* PLANE_PB_STRENGTHS */
52
53 /* PLANE_ACCENTS */
54
55 /* PLANE_INTERN */
56 #define PICOKTAB_TMPID_PHONSTART '\x26' /* 38 '&' */
57 #define PICOKTAB_TMPID_PHONTERM '\x23' /* 35 '#' */
58
59
60 /* ************************************************************/
61 /* fixed ids */
62 /* ************************************************************/
63
64
ktabIdsInitialize(register picoknow_KnowledgeBase this,picoos_Common common)65 static pico_status_t ktabIdsInitialize(register picoknow_KnowledgeBase this,
66 picoos_Common common)
67 {
68 picoktab_FixedIds ids;
69
70 PICODBG_DEBUG(("start"));
71
72 if (NULL == this || NULL == this->subObj) {
73 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
74 NULL, NULL);
75 }
76 ids = (picoktab_FixedIds) this->subObj;
77
78 ids->phonStartId = PICOKTAB_TMPID_PHONSTART;
79 ids->phonTermId = PICOKTAB_TMPID_PHONTERM;
80 return PICO_OK;
81 }
82
83
ktabIdsSubObjDeallocate(register picoknow_KnowledgeBase this,picoos_MemoryManager mm)84 static pico_status_t ktabIdsSubObjDeallocate(register picoknow_KnowledgeBase this,
85 picoos_MemoryManager mm)
86 {
87 if (NULL != this) {
88 picoos_deallocate(mm, (void *) &this->subObj);
89 }
90 return PICO_OK;
91 }
92
picoktab_specializeIdsKnowledgeBase(picoknow_KnowledgeBase this,picoos_Common common)93 pico_status_t picoktab_specializeIdsKnowledgeBase(picoknow_KnowledgeBase this,
94 picoos_Common common)
95 {
96 if (NULL == this) {
97 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
98 NULL, NULL);
99 }
100 this->subDeallocate = ktabIdsSubObjDeallocate;
101 this->subObj = picoos_allocate(common->mm, sizeof(picoktab_fixed_ids_t));
102 if (NULL == this->subObj) {
103 return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
104 NULL, NULL);
105 }
106 return ktabIdsInitialize(this, common);
107 }
108
picoktab_getFixedIds(picoknow_KnowledgeBase this)109 picoktab_FixedIds picoktab_getFixedIds(picoknow_KnowledgeBase this)
110 {
111 return ((NULL == this) ? NULL : ((picoktab_FixedIds) this->subObj));
112 }
113
114
picoktab_newFixedIds(picoos_MemoryManager mm)115 picoktab_FixedIds picoktab_newFixedIds(picoos_MemoryManager mm)
116 {
117 picoktab_FixedIds this = (picoktab_FixedIds) picoos_allocate(mm,sizeof(*this));
118 if (NULL != this) {
119 /* initialize */
120 }
121 return this;
122 }
123
124
picoktab_disposeFixedIds(picoos_MemoryManager mm,picoktab_FixedIds * this)125 void picoktab_disposeFixedIds(picoos_MemoryManager mm, picoktab_FixedIds * this)
126 {
127 if (NULL != (*this)) {
128 /* terminate */
129 picoos_deallocate(mm,(void *)this);
130 }
131 }
132
133
134
135 /* ************************************************************/
136 /* Graphs */
137 /* ************************************************************/
138
139 /* overview binary file format for graphs kb:
140
141 graphs-kb = NROFSENTRIES SIZEOFSENTRY ofstable graphs
142
143 NROFSENTRIES : 2 bytes, number of entries in offset table
144 SIZEOFSENTRY : 1 byte, size of one entry in offset table
145
146 ofstable = {OFFSET}=NROFSENTRIES (contains NROFSENTRIES entries of OFFSET)
147
148 OFFSET: SIZEOFSENTRY bytes, offset to baseaddress of graphs-kb to entry in graphs
149
150 graphs = {graph}=NROFSENTRIES (contains NROFSENTRIES entries of graph)
151
152 graph = PROPSET FROM TO [TOKENTYPE] [TOKENSUBTYPE] [VALUE] [LOWERCASE] [GRAPHSUBS1] [GRAPHSUBS2]
153
154 FROM : 1..4 unsigned bytes, UTF8 character without terminating 0
155 TO : 1..4 unsigned bytes, UTF8 character without terminating 0
156 PROPSET : 1 unsigned byte, least significant bit : has TO field
157 next bit : has TOKENTYPE
158 next bit : has TOKENSUBTYPE
159 next bit : has VALUE
160 next bit : has LOWERCASE
161 next bit : has GRAPHSUBS1
162 next bit : has GRAPHSUBS2
163 next bit : has PUNC
164
165 TOKENTYPE : 1 unsigned byte
166 TOKENSUBTYPE : 1 unsigned byte
167 VALUE : 1 unsigned byte
168 LOWERCASE : 1..4 unsigned bytes, UTF8 character without terminating 0
169 GRAPHSUBS1 : 1..4 unsigned bytes, UTF8 character without terminating 0
170 GRAPHSUBS2 : 1..4 unsigned bytes, UTF8 character without terminating 0
171 PUNC : 1 unsigned byte
172 */
173
174 static picoos_uint32 ktab_propOffset (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 prop);
175
176 #define KTAB_START_GRAPHS_NR_OFFSET 0
177 #define KTAB_START_GRAPHS_SIZE_OFFSET 2
178 #define KTAB_START_GRAPHS_OFFSET_TABLE 3
179 #define KTAB_START_GRAPHS_GRAPH_TABLE 0
180
181 /* bitmasks to extract the grapheme properties info from the property set */
182 #define KTAB_GRAPH_PROPSET_TO ((picoos_uint8)'\x01')
183 #define KTAB_GRAPH_PROPSET_TOKENTYPE ((picoos_uint8)'\x02')
184 #define KTAB_GRAPH_PROPSET_TOKENSUBTYPE ((picoos_uint8)'\x04')
185 #define KTAB_GRAPH_PROPSET_VALUE ((picoos_uint8)'\x08')
186 #define KTAB_GRAPH_PROPSET_LOWERCASE ((picoos_uint8)'\x010')
187 #define KTAB_GRAPH_PROPSET_GRAPHSUBS1 ((picoos_uint8)'\x020')
188 #define KTAB_GRAPH_PROPSET_GRAPHSUBS2 ((picoos_uint8)'\x040')
189 #define KTAB_GRAPH_PROPSET_PUNCT ((picoos_uint8)'\x080')
190
191
192 typedef struct ktabgraphs_subobj *ktabgraphs_SubObj;
193
194 typedef struct ktabgraphs_subobj {
195 picoos_uint16 nrOffset;
196 picoos_uint16 sizeOffset;
197
198 picoos_uint8 * offsetTable;
199 picoos_uint8 * graphTable;
200 } ktabgraphs_subobj_t;
201
202
203
ktabGraphsInitialize(register picoknow_KnowledgeBase this,picoos_Common common)204 static pico_status_t ktabGraphsInitialize(register picoknow_KnowledgeBase this,
205 picoos_Common common) {
206 ktabgraphs_subobj_t * ktabgraphs;
207
208 PICODBG_DEBUG(("start"));
209
210 if (NULL == this || NULL == this->subObj) {
211 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
212 NULL, NULL);
213 }
214 ktabgraphs = (ktabgraphs_subobj_t *) this->subObj;
215 ktabgraphs->nrOffset = ((int)(this->base[KTAB_START_GRAPHS_NR_OFFSET])) + 256*(int)(this->base[KTAB_START_GRAPHS_NR_OFFSET+1]);
216 ktabgraphs->sizeOffset = (int)(this->base[KTAB_START_GRAPHS_SIZE_OFFSET]);
217 ktabgraphs->offsetTable = &(this->base[KTAB_START_GRAPHS_OFFSET_TABLE]);
218 ktabgraphs->graphTable = &(this->base[KTAB_START_GRAPHS_GRAPH_TABLE]);
219 return PICO_OK;
220 }
221
ktabGraphsSubObjDeallocate(register picoknow_KnowledgeBase this,picoos_MemoryManager mm)222 static pico_status_t ktabGraphsSubObjDeallocate(register picoknow_KnowledgeBase this,
223 picoos_MemoryManager mm) {
224 if (NULL != this) {
225 picoos_deallocate(mm, (void *) &this->subObj);
226 }
227 return PICO_OK;
228 }
229
230
picoktab_specializeGraphsKnowledgeBase(picoknow_KnowledgeBase this,picoos_Common common)231 pico_status_t picoktab_specializeGraphsKnowledgeBase(picoknow_KnowledgeBase this,
232 picoos_Common common) {
233 if (NULL == this) {
234 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
235 NULL, NULL);
236 }
237 this->subDeallocate = ktabGraphsSubObjDeallocate;
238 this->subObj = picoos_allocate(common->mm, sizeof(ktabgraphs_subobj_t));
239 if (NULL == this->subObj) {
240 return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
241 NULL, NULL);
242 }
243 return ktabGraphsInitialize(this, common);
244 }
245
246
picoktab_getGraphs(picoknow_KnowledgeBase this)247 picoktab_Graphs picoktab_getGraphs(picoknow_KnowledgeBase this) {
248 if (NULL == this) {
249 return NULL;
250 } else {
251 return (picoktab_Graphs) this->subObj;
252 }
253 }
254
255
256 /* Graphs methods */
257
picoktab_hasVowellikeProp(const picoktab_Graphs this,const picoos_uint8 * graph,const picoos_uint8 graphlenmax)258 picoos_uint8 picoktab_hasVowellikeProp(const picoktab_Graphs this,
259 const picoos_uint8 *graph,
260 const picoos_uint8 graphlenmax) {
261
262 picoos_uint8 ui8App;
263 picoos_uint32 graphsOffset;
264 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
265
266 ui8App = graphlenmax; /* avoid warning "var not used in this function"*/
267
268 graphsOffset = picoktab_graphOffset (this, (picoos_uchar *)graph);
269 return g->graphTable[graphsOffset + ktab_propOffset (this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE)] == PICODATA_ITEMINFO1_TOKTYPE_LETTERV;
270 }
271
272
ktab_getStrProp(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uint32 propOffset,picoos_uchar * str)273 static void ktab_getStrProp (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 propOffset, picoos_uchar * str)
274 {
275 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
276 picoos_uint32 i, l;
277
278 i = 0;
279 l = picobase_det_utf8_length(g->graphTable[graphsOffset+propOffset]);
280 while (i<l) {
281 str[i] = g->graphTable[graphsOffset+propOffset+i];
282 i++;
283 }
284 str[l] = 0;
285 }
286
287
ktab_propOffset(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uint32 prop)288 static picoos_uint32 ktab_propOffset(const picoktab_Graphs this,
289 picoos_uint32 graphsOffset, picoos_uint32 prop)
290 /* Returns offset of property 'prop' inside the graph with offset 'graphsOffset' in graphs table;
291 If the property is found, a value > 0 is returned otherwise 0 */
292 {
293 picoos_uint32 n = 0;
294 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
295
296 if ((g->graphTable[graphsOffset] & prop) == prop) {
297 n = n + 1; /* overread PROPSET field */
298 n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread FROM field */
299 if (prop > KTAB_GRAPH_PROPSET_TO) {
300 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TO)
301 == KTAB_GRAPH_PROPSET_TO) {
302 n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread TO field */
303 }
304 } else {
305 return n;
306 }
307 if (prop > KTAB_GRAPH_PROPSET_TOKENTYPE) {
308 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENTYPE)
309 == KTAB_GRAPH_PROPSET_TOKENTYPE) {
310 n = n + 1; /* overread TOKENTYPE field */
311 }
312 } else {
313 return n;
314 }
315 if (prop > KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
316 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENSUBTYPE)
317 == KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
318 n = n + 1; /* overread stokentype field */
319 }
320 } else {
321 return n;
322 }
323 if (prop > KTAB_GRAPH_PROPSET_VALUE) {
324 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_VALUE)
325 == KTAB_GRAPH_PROPSET_VALUE) {
326 n = n + 1; /* overread value field */
327 }
328 } else {
329 return n;
330 }
331 if (prop > KTAB_GRAPH_PROPSET_LOWERCASE) {
332 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_LOWERCASE)
333 == KTAB_GRAPH_PROPSET_LOWERCASE) {
334 n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread lowercase field */
335 }
336 } else {
337 return n;
338 }
339 if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
340 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS1)
341 == KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
342 n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs1 field */
343 }
344 } else {
345 return n;
346 }
347 if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
348 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS2)
349 == KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
350 n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs2 field */
351 }
352 } else {
353 return n;
354 }
355 if (prop > KTAB_GRAPH_PROPSET_PUNCT) {
356 if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_PUNCT)
357 == KTAB_GRAPH_PROPSET_PUNCT) {
358 n = n + 1; /* overread value field */
359 }
360 } else {
361 return n;
362 }
363 }
364
365 return n;
366 }
367
368
picoktab_graphOffset(const picoktab_Graphs this,picoos_uchar * utf8graph)369 picoos_uint32 picoktab_graphOffset (const picoktab_Graphs this, picoos_uchar * utf8graph)
370 { ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
371 picoos_int32 a, b, m;
372 picoos_uint32 graphsOffset;
373 picoos_uint32 propOffset;
374 picobase_utf8char from;
375 picobase_utf8char to;
376 picoos_bool utfGEfrom;
377 picoos_bool utfLEto;
378
379 if (g->nrOffset > 0) {
380 a = 0;
381 b = g->nrOffset-1;
382 do {
383 m = (a+b) / 2;
384
385 /* get offset to graph[m] */
386 if (g->sizeOffset == 1) {
387 graphsOffset = g->offsetTable[g->sizeOffset*m];
388 }
389 else {
390 graphsOffset = g->offsetTable[g->sizeOffset*m ] +
391 256*g->offsetTable[g->sizeOffset*m + 1];
392 /* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i %i", m, g->offsetTable[g->sizeOffset*m], g->offsetTable[g->sizeOffset*m + 1], graphsOffset));
393 */
394 }
395
396 /* get FROM and TO field of graph[m] */
397 ktab_getStrProp(this, graphsOffset, 1, from);
398 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TO);
399 if (propOffset > 0) {
400 ktab_getStrProp(this, graphsOffset, propOffset, to);
401 }
402 else {
403 picoos_strcpy((picoos_char *)to, (picoos_char *)from);
404 }
405
406 /* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i '%s' '%s' '%s'", a, m, b, from, utf8graph, to));
407 */
408 utfGEfrom = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)from) >= 0;
409 utfLEto = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)to) <= 0;
410
411 if (utfGEfrom && utfLEto) {
412 /* PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' found", utf8graph));
413 */
414 return graphsOffset;
415 }
416 if (!utfGEfrom) {
417 b = m-1;
418 }
419 else if (!utfLEto) {
420 a = m+1;
421 }
422 } while (a<=b);
423 }
424 PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' not found", utf8graph));
425 return 0;
426 }
427
428
429
430
picoktab_getIntPropTokenType(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uint8 * stokenType)431 picoos_bool picoktab_getIntPropTokenType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * stokenType)
432 {
433 picoos_uint32 propOffset;
434 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
435
436 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE);
437 if (propOffset > 0) {
438 *stokenType = (picoos_uint8)(g->graphTable[graphsOffset+propOffset]);
439 return TRUE;
440 }
441 else {
442 return FALSE;
443 }
444 }
445
446
picoktab_getIntPropTokenSubType(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_int8 * stokenSubType)447 picoos_bool picoktab_getIntPropTokenSubType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_int8 * stokenSubType)
448 {
449 picoos_uint32 propOffset;
450 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
451
452 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENSUBTYPE);
453 if (propOffset > 0) {
454 *stokenSubType = (picoos_int8)(g->graphTable[graphsOffset+propOffset]);
455 return TRUE;
456 }
457 else {
458 return FALSE;
459 }
460 }
461
picoktab_getIntPropValue(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uint32 * value)462 picoos_bool picoktab_getIntPropValue (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 * value)
463 {
464 picoos_uint32 propOffset;
465 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
466
467 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_VALUE);
468 if (propOffset > 0) {
469 *value = (picoos_uint32)(g->graphTable[graphsOffset+propOffset]);
470 return TRUE;
471 }
472 else {
473 return FALSE;
474 }
475 }
476
477
picoktab_getIntPropPunct(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uint8 * info1,picoos_uint8 * info2)478 picoos_bool picoktab_getIntPropPunct (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * info1, picoos_uint8 * info2)
479 {
480 picoos_uint32 propOffset;
481 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
482
483 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_PUNCT);
484 if (propOffset > 0) {
485 if (g->graphTable[graphsOffset+propOffset] == 2) {
486 *info1 = PICODATA_ITEMINFO1_PUNC_SENTEND;
487 }
488 else {
489 *info1 = PICODATA_ITEMINFO1_PUNC_PHRASEEND;
490 }
491 if (g->graphTable[graphsOffset+1] == '.') {
492 *info2 = PICODATA_ITEMINFO2_PUNC_SENT_T;
493 }
494 else if (g->graphTable[graphsOffset+1] == '?') {
495 *info2 = PICODATA_ITEMINFO2_PUNC_SENT_Q;
496 }
497 else if (g->graphTable[graphsOffset+1] == '!') {
498 *info2 = PICODATA_ITEMINFO2_PUNC_SENT_E;
499 }
500 else {
501 *info2 = PICODATA_ITEMINFO2_PUNC_PHRASE;
502 }
503 return TRUE;
504 }
505 else {
506 return FALSE;
507 }
508 }
509
510
picoktab_getStrPropLowercase(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uchar * lowercase)511 picoos_bool picoktab_getStrPropLowercase (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * lowercase)
512 {
513 picoos_uint32 propOffset;
514
515 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_LOWERCASE);
516 if (propOffset > 0) {
517 ktab_getStrProp(this, graphsOffset, propOffset, lowercase);
518 return TRUE;
519 }
520 else {
521 return FALSE;
522 }
523 }
524
525
picoktab_getStrPropGraphsubs1(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uchar * graphsubs1)526 picoos_bool picoktab_getStrPropGraphsubs1 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs1)
527 {
528 picoos_uint32 propOffset;
529
530 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS1);
531 if (propOffset > 0) {
532 ktab_getStrProp(this, graphsOffset, propOffset, graphsubs1);
533 return TRUE;
534 }
535 else {
536 return FALSE;
537 }
538 }
539
540
picoktab_getStrPropGraphsubs2(const picoktab_Graphs this,picoos_uint32 graphsOffset,picoos_uchar * graphsubs2)541 picoos_bool picoktab_getStrPropGraphsubs2 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs2)
542 {
543 picoos_uint32 propOffset;
544
545 propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS2);
546 if (propOffset > 0) {
547 ktab_getStrProp(this, graphsOffset, propOffset, graphsubs2);
548 return TRUE;
549 }
550 else {
551 return FALSE;
552 }
553 }
554 /* *****************************************************************/
555 /* used for tools */
556
ktab_getUtf8(picoos_uchar ** pos,picoos_uchar * to)557 static void ktab_getUtf8 (picoos_uchar ** pos, picoos_uchar * to)
558 {
559 picoos_uint32 l;
560 l = picobase_det_utf8_length(**pos);
561 while (l>0) {
562 *(to++) = *((*pos)++);
563 l--;
564 }
565 *to = 0;
566 }
567
picoktab_graphsGetNumEntries(const picoktab_Graphs this)568 picoos_uint16 picoktab_graphsGetNumEntries(const picoktab_Graphs this)
569 {
570 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
571 return g->nrOffset;
572 }
573
picoktab_graphsGetGraphInfo(const picoktab_Graphs this,picoos_uint16 graphIndex,picoos_uchar * from,picoos_uchar * to,picoos_uint8 * propset,picoos_uint8 * stokenType,picoos_uint8 * stokenSubType,picoos_uint8 * value,picoos_uchar * lowercase,picoos_uchar * graphsubs1,picoos_uchar * graphsubs2,picoos_uint8 * punct)574 void picoktab_graphsGetGraphInfo(const picoktab_Graphs this,
575 picoos_uint16 graphIndex, picoos_uchar * from, picoos_uchar * to,
576 picoos_uint8 * propset,
577 picoos_uint8 * stokenType, picoos_uint8 * stokenSubType,
578 picoos_uint8 * value, picoos_uchar * lowercase,
579 picoos_uchar * graphsubs1, picoos_uchar * graphsubs2,
580 picoos_uint8 * punct) {
581 ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
582 picoos_uint32 graphsOffset;
583 picoos_uint8 * pos;
584
585 /* calculate offset of graph[graphIndex] */
586 if (g->sizeOffset == 1) {
587 graphsOffset = g->offsetTable[graphIndex];
588 } else {
589 graphsOffset = g->offsetTable[2 * graphIndex]
590 + (g->offsetTable[2 * graphIndex + 1] << 8);
591 }
592 pos = &(g->graphTable[graphsOffset]);
593 *propset = *pos;
594
595 pos++; /* advance to FROM */
596 ktab_getUtf8(&pos, from); /* get FROM and advance */
597 if ((*propset) & KTAB_GRAPH_PROPSET_TO) {
598 ktab_getUtf8(&pos, to); /* get TO and advance */
599 } else {
600 picoos_strcpy((picoos_char *)to, (picoos_char *)from);
601 }
602 if ((*propset) & KTAB_GRAPH_PROPSET_TOKENTYPE) {
603 (*stokenType) = *(pos++); /* get TOKENTYPE and advance */
604 } else {
605 (*stokenType) = -1;
606 }
607 if ((*propset) & KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
608 (*stokenSubType) = *(pos++); /* get TOKENSUBTYPE and advance */
609 } else {
610 (*stokenSubType) = -1;
611 }
612 if ((*propset) & KTAB_GRAPH_PROPSET_VALUE) {
613 (*value) = *(pos++); /* get VALUE and advance */
614 } else {
615 (*value) = -1;
616 }
617 if ((*propset) & KTAB_GRAPH_PROPSET_LOWERCASE) {
618 ktab_getUtf8(&pos, lowercase); /* get LOWERCASE and advance */
619 } else {
620 lowercase[0] = NULLC;
621 }
622 if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
623 ktab_getUtf8(&pos, graphsubs1); /* get GRAPHSUBS1 and advance */
624 } else {
625 graphsubs1[0] = NULLC;
626 }
627 if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
628 ktab_getUtf8(&pos, graphsubs2); /* get GRAPHSUBS2 and advance */
629 } else {
630 graphsubs2[0] = NULLC;
631 }
632 if ((*propset) & KTAB_GRAPH_PROPSET_PUNCT) {
633 (*punct) = *(pos++); /* get PUNCT and advance */
634 } else {
635 (*punct) = -1;
636 }
637 }
638
639 /* ************************************************************/
640 /* Phones */
641 /* ************************************************************/
642
643 /* overview binary file format for phones kb:
644
645 phones-kb = specids propertytable
646
647 specids = PRIMSTRESSID1 SECSTRESSID1 SYLLBOUNDID1 PAUSEID1 WORDBOUNDID1
648 RESERVE1 RESERVE1 RESERVE1
649
650 propertytable = {PHONEPROP2}=256
651
652 PRIMSTRESSID1: one byte, ID of primary stress
653 SECSTRESSID1: one byte, ID of secondary stress
654 SYLLBOUNDID1: one byte, ID of syllable boundary
655 PAUSEID1: one byte, ID of pause
656 RESERVE1: reserved for future use
657
658 PHONEPROP2: one byte, max. of 256 phones directly access this table
659 to check a property for a phone; binary properties
660 encoded (1 bit per prop)
661 least significant bit: vowel
662 next bit: diphth
663 next bit: glott
664 next bit: nonsyllvowel
665 next bit: syllcons
666 3 bits spare
667 */
668
669 #define KTAB_START_SPECIDS 0
670 #define KTAB_IND_PRIMSTRESS 0
671 #define KTAB_IND_SECSTRESS 1
672 #define KTAB_IND_SYLLBOUND 2
673 #define KTAB_IND_PAUSE 3
674 #define KTAB_IND_WORDBOUND 4
675
676 #define KTAB_START_PROPS 8
677
678
679 typedef struct ktabphones_subobj *ktabphones_SubObj;
680
681 typedef struct ktabphones_subobj {
682 picoos_uint8 *specids;
683 picoos_uint8 *props;
684 } ktabphones_subobj_t;
685
686
687 /* bitmasks to extract the property info from props */
688 #define KTAB_PPROP_VOWEL '\x01'
689 #define KTAB_PPROP_DIPHTH '\x02'
690 #define KTAB_PPROP_GLOTT '\x04'
691 #define KTAB_PPROP_NONSYLLVOWEL '\x08'
692 #define KTAB_PPROP_SYLLCONS '\x10'
693
694
ktabPhonesInitialize(register picoknow_KnowledgeBase this,picoos_Common common)695 static pico_status_t ktabPhonesInitialize(register picoknow_KnowledgeBase this,
696 picoos_Common common) {
697 ktabphones_subobj_t * ktabphones;
698
699 PICODBG_DEBUG(("start"));
700
701 if (NULL == this || NULL == this->subObj) {
702 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
703 NULL, NULL);
704 }
705 ktabphones = (ktabphones_subobj_t *) this->subObj;
706 ktabphones->specids = &(this->base[KTAB_START_SPECIDS]);
707 ktabphones->props = &(this->base[KTAB_START_PROPS]);
708 return PICO_OK;
709 }
710
ktabPhonesSubObjDeallocate(register picoknow_KnowledgeBase this,picoos_MemoryManager mm)711 static pico_status_t ktabPhonesSubObjDeallocate(register picoknow_KnowledgeBase this,
712 picoos_MemoryManager mm) {
713 if (NULL != this) {
714 picoos_deallocate(mm, (void *) &this->subObj);
715 }
716 return PICO_OK;
717 }
718
picoktab_specializePhonesKnowledgeBase(picoknow_KnowledgeBase this,picoos_Common common)719 pico_status_t picoktab_specializePhonesKnowledgeBase(picoknow_KnowledgeBase this,
720 picoos_Common common) {
721 if (NULL == this) {
722 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
723 NULL, NULL);
724 }
725 this->subDeallocate = ktabPhonesSubObjDeallocate;
726 this->subObj = picoos_allocate(common->mm, sizeof(ktabphones_subobj_t));
727 if (NULL == this->subObj) {
728 return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
729 NULL, NULL);
730 }
731 return ktabPhonesInitialize(this, common);
732 }
733
picoktab_getPhones(picoknow_KnowledgeBase this)734 picoktab_Phones picoktab_getPhones(picoknow_KnowledgeBase this) {
735 if (NULL == this) {
736 return NULL;
737 } else {
738 return (picoktab_Phones) this->subObj;
739 }
740 }
741
742
743 /* Phones methods */
744
picoktab_hasVowelProp(const picoktab_Phones this,const picoos_uint8 ch)745 picoos_uint8 picoktab_hasVowelProp(const picoktab_Phones this,
746 const picoos_uint8 ch) {
747 return (KTAB_PPROP_VOWEL & ((ktabphones_SubObj)this)->props[ch]);
748 }
picoktab_hasDiphthProp(const picoktab_Phones this,const picoos_uint8 ch)749 picoos_uint8 picoktab_hasDiphthProp(const picoktab_Phones this,
750 const picoos_uint8 ch) {
751 return (KTAB_PPROP_DIPHTH & ((ktabphones_SubObj)this)->props[ch]);
752 }
picoktab_hasGlottProp(const picoktab_Phones this,const picoos_uint8 ch)753 picoos_uint8 picoktab_hasGlottProp(const picoktab_Phones this,
754 const picoos_uint8 ch) {
755 return (KTAB_PPROP_GLOTT & ((ktabphones_SubObj)this)->props[ch]);
756 }
picoktab_hasNonsyllvowelProp(const picoktab_Phones this,const picoos_uint8 ch)757 picoos_uint8 picoktab_hasNonsyllvowelProp(const picoktab_Phones this,
758 const picoos_uint8 ch) {
759 return (KTAB_PPROP_NONSYLLVOWEL & ((ktabphones_SubObj)this)->props[ch]);
760 }
picoktab_hasSyllconsProp(const picoktab_Phones this,const picoos_uint8 ch)761 picoos_uint8 picoktab_hasSyllconsProp(const picoktab_Phones this,
762 const picoos_uint8 ch) {
763 return (KTAB_PPROP_SYLLCONS & ((ktabphones_SubObj)this)->props[ch]);
764 }
765
picoktab_isSyllCarrier(const picoktab_Phones this,const picoos_uint8 ch)766 picoos_bool picoktab_isSyllCarrier(const picoktab_Phones this,
767 const picoos_uint8 ch) {
768 picoos_uint8 props;
769 props = ((ktabphones_SubObj)this)->props[ch];
770 return (((KTAB_PPROP_VOWEL & props) &&
771 !(KTAB_PPROP_NONSYLLVOWEL & props))
772 || (KTAB_PPROP_SYLLCONS & props));
773 }
774
picoktab_isPrimstress(const picoktab_Phones this,const picoos_uint8 ch)775 picoos_bool picoktab_isPrimstress(const picoktab_Phones this,
776 const picoos_uint8 ch) {
777 return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS]);
778 }
picoktab_isSecstress(const picoktab_Phones this,const picoos_uint8 ch)779 picoos_bool picoktab_isSecstress(const picoktab_Phones this,
780 const picoos_uint8 ch) {
781 return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS]);
782 }
picoktab_isSyllbound(const picoktab_Phones this,const picoos_uint8 ch)783 picoos_bool picoktab_isSyllbound(const picoktab_Phones this,
784 const picoos_uint8 ch) {
785 return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND]);
786 }
picoktab_isWordbound(const picoktab_Phones this,const picoos_uint8 ch)787 picoos_bool picoktab_isWordbound(const picoktab_Phones this,
788 const picoos_uint8 ch) {
789 return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND]);
790 }
picoktab_isPause(const picoktab_Phones this,const picoos_uint8 ch)791 picoos_bool picoktab_isPause(const picoktab_Phones this,
792 const picoos_uint8 ch) {
793 return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE]);
794 }
795
picoktab_getPrimstressID(const picoktab_Phones this)796 picoos_uint8 picoktab_getPrimstressID(const picoktab_Phones this) {
797 return ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS];
798 }
picoktab_getSecstressID(const picoktab_Phones this)799 picoos_uint8 picoktab_getSecstressID(const picoktab_Phones this) {
800 return ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS];
801 }
picoktab_getSyllboundID(const picoktab_Phones this)802 picoos_uint8 picoktab_getSyllboundID(const picoktab_Phones this) {
803 return ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND];
804 }
picoktab_getWordboundID(const picoktab_Phones this)805 picoos_uint8 picoktab_getWordboundID(const picoktab_Phones this) {
806 return ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND];
807 }
picoktab_getPauseID(const picoktab_Phones this)808 picoos_uint8 picoktab_getPauseID(const picoktab_Phones this) {
809 return ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE];
810 }
811
812 /* ************************************************************/
813 /* Pos */
814 /* ************************************************************/
815
816 /* overview binary file format for pos kb:
817
818 pos-kb = header posids
819 header = {COUNT2 OFFS2}=8
820 posids = {POSID1 {PARTID1}0:8}1:
821
822 where POSID1 is the value of the (combined) part-of-speech symbol,
823 and {PARTID1} are the symbol values of its components (empty if it
824 is not a combined symbol). The {PARTID1} list is sorted.
825 Part-of-speech symbols with equal number of components are grouped
826 together.
827
828 The header contains information about these groups:
829
830 COUNT2 specifies the number of elements in the group, and OFFS2
831 specifies the offset (relative to the beginning of the kb) where
832 the group data starts, i.e.:
833
834 25 32 -> 25 not-combined elements, starting at offset 32
835 44 57 -> 44 elements composed of 2 symbols, starting at offset 57
836 23 189 -> 23 elements composed of 3 symbols, starting at offset 189
837 ...
838
839 Currently, each symbol may be composed of up to 8 other symbols.
840 Therefore, the header has 8 entries, too. The header starts with
841 the unique POS list, and then in increasing order, 2 symbols, 3
842 symbols,...
843
844 Zur Anschauung die ge-printf-te Version:
845
846 25 32
847 44 57
848 23 189
849 12 281
850 4 341
851 1 365
852 0 0
853 0 0
854 33 |
855 34 |
856 35 |
857 60 |
858 etc.
859 36 | 35 60
860 50 | 35 95
861 51 | 35 97
862 58 | 35 120
863 59 | 35 131
864 61 | 60 75
865 63 | 60 95
866 64 | 60 97
867 etc.
868 42 | 35 60 117
869 44 | 35 60 131
870 45 | 35 73 97
871 48 | 35 84 97
872 54 | 35 97 131
873 56 | 35 113 120
874 57 | 35 117 120
875 62 | 60 84 122
876 etc.
877 */
878
879 typedef struct ktabpos_subobj *ktabpos_SubObj;
880
881 typedef struct ktabpos_subobj {
882 picoos_uint16 nrcomb[PICOKTAB_MAXNRPOS_IN_COMB];
883 picoos_uint8 *nrcombstart[PICOKTAB_MAXNRPOS_IN_COMB];
884 } ktabpos_subobj_t;
885
886
ktabPosInitialize(register picoknow_KnowledgeBase this,picoos_Common common)887 static pico_status_t ktabPosInitialize(register picoknow_KnowledgeBase this,
888 picoos_Common common) {
889 ktabpos_subobj_t *ktabpos;
890 picoos_uint16 osprev;
891 picoos_uint16 os, pos;
892 picoos_uint8 i;
893
894 PICODBG_DEBUG(("start"));
895
896 if (NULL == this || NULL == this->subObj) {
897 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
898 NULL, NULL);
899 }
900 ktabpos = (ktabpos_subobj_t *)this->subObj;
901
902 os = 0;
903 for (i = 0, pos = 0; i < PICOKTAB_MAXNRPOS_IN_COMB; i++, pos += 4) {
904 ktabpos->nrcomb[i] = ((picoos_uint16)(this->base[pos+1])) << 8 |
905 this->base[pos];
906 if (ktabpos->nrcomb[i] > 0) {
907 osprev = os;
908 os = ((picoos_uint16)(this->base[pos+3])) << 8 | this->base[pos+2];
909 ktabpos->nrcombstart[i] = &(this->base[os]);
910 PICODBG_TRACE(("i %d, pos %d, nr %d, osprev %d, os %d", i, pos,
911 ktabpos->nrcomb[i], osprev, os));
912 if (osprev >= os) {
913 /* cannot be, in a valid kb */
914 return picoos_emRaiseException(common->em,
915 PICO_EXC_FILE_CORRUPT,
916 NULL, NULL);
917 }
918 } else {
919 if (i == 0) {
920 /* cannot be, in a valid kb */
921 return picoos_emRaiseException(common->em,
922 PICO_EXC_FILE_CORRUPT,
923 NULL, NULL);
924 }
925 ktabpos->nrcombstart[i] = NULL;
926 }
927 }
928 return PICO_OK;
929 }
930
ktabPosSubObjDeallocate(register picoknow_KnowledgeBase this,picoos_MemoryManager mm)931 static pico_status_t ktabPosSubObjDeallocate(register picoknow_KnowledgeBase this,
932 picoos_MemoryManager mm) {
933 if (NULL != this) {
934 picoos_deallocate(mm, (void *) &this->subObj);
935 }
936 return PICO_OK;
937 }
938
picoktab_specializePosKnowledgeBase(picoknow_KnowledgeBase this,picoos_Common common)939 pico_status_t picoktab_specializePosKnowledgeBase(picoknow_KnowledgeBase this,
940 picoos_Common common) {
941 if (NULL == this) {
942 return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
943 NULL, NULL);
944 }
945 this->subDeallocate = ktabPosSubObjDeallocate;
946 this->subObj = picoos_allocate(common->mm, sizeof(ktabpos_subobj_t));
947 if (NULL == this->subObj) {
948 return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
949 NULL, NULL);
950 }
951 return ktabPosInitialize(this, common);
952 }
953
picoktab_getPos(picoknow_KnowledgeBase this)954 picoktab_Pos picoktab_getPos(picoknow_KnowledgeBase this) {
955 if (NULL == this) {
956 return NULL;
957 } else {
958 return (picoktab_Pos) this->subObj;
959 }
960 }
961
962
963 /* Pos methods */
964
ktab_isEqualPosGroup(const picoos_uint8 * grp1,const picoos_uint8 * grp2,picoos_uint8 len)965 static picoos_int16 ktab_isEqualPosGroup(const picoos_uint8 *grp1,
966 const picoos_uint8 *grp2,
967 picoos_uint8 len)
968 {
969 /* if both, grp1 and grp2 would be sorted in ascending order
970 we could implement a function picoktab_comparePosGroup in
971 a similar manner as strcmp */
972
973 picoos_uint16 i, j, equal;
974
975 equal = 1;
976
977 i = 0;
978 while (equal && (i < len)) {
979 /* search grp1[i] in grp2 */
980 j = 0;
981 while ((j < len) && (grp1[i] != grp2[j])) {
982 j++;
983 }
984 equal = (j < len);
985 i++;
986 }
987
988 return equal;
989 }
990
991
picoktab_isUniquePos(const picoktab_Pos this,const picoos_uint8 pos)992 picoos_bool picoktab_isUniquePos(const picoktab_Pos this,
993 const picoos_uint8 pos) {
994 ktabpos_subobj_t *ktabpos;
995 picoos_uint16 i;
996
997 /* speed-up possible with e.g. binary search */
998
999 ktabpos = (ktabpos_subobj_t *)this;
1000 PICODBG_TRACE(("pos %d, nrcombinations %d", pos, ktabpos->nrcomb[0]));
1001 i = 0;
1002 while ((i < ktabpos->nrcomb[0]) && (pos > ktabpos->nrcombstart[0][i])) {
1003 PICODBG_TRACE(("compare with pos %d at position %d",
1004 ktabpos->nrcombstart[0][i], pos, i));
1005 i++;
1006 }
1007 return ((i < ktabpos->nrcomb[0]) && (pos == ktabpos->nrcombstart[0][i]));
1008 }
1009
1010
picoktab_isPartOfPosGroup(const picoktab_Pos this,const picoos_uint8 pos,const picoos_uint8 posgroup)1011 picoos_bool picoktab_isPartOfPosGroup(const picoktab_Pos this,
1012 const picoos_uint8 pos,
1013 const picoos_uint8 posgroup)
1014 {
1015 ktabpos_subobj_t *ktabpos;
1016 picoos_uint8 *grp;
1017 picoos_uint16 i, j, n, s, grplen;
1018 picoos_uint8 *e;
1019 picoos_uint8 found;
1020
1021 ktabpos = (ktabpos_subobj_t *) this;
1022
1023 grp = NULL;
1024 found = FALSE;
1025 grplen = 0;
1026
1027 /* currently, a linear search is required to find 'posgroup'; the
1028 knowledge base should be extended to allow for a faster search */
1029
1030 /* treat case i==0, grplen==0, ie. pos == posgroup */
1031 if (pos == posgroup) {
1032 found = TRUE;
1033 }
1034
1035 i = 1;
1036 while ((grp == NULL) && (i < PICOKTAB_MAXNRPOS_IN_COMB)) {
1037 n = ktabpos->nrcomb[i]; /* number of entries */
1038 e = ktabpos->nrcombstart[i]; /* ptr to first entry */
1039 s = i + 2; /* size of an entry in bytes */
1040 /* was with while starting at 0:
1041 s = i > 0 ? i + 2 : 1;
1042 */
1043 j = 0;
1044 while ((grp == NULL) && (j < n)) {
1045 if (posgroup == e[0]) {
1046 grp = e + 1;
1047 grplen = s - 1;
1048 }
1049 e += s;
1050 j++;
1051 }
1052 i++;
1053 }
1054
1055 /* test if 'pos' is contained in the components of 'posgroup' */
1056 if (grp != NULL) {
1057 for (i = 0; !found && (i < grplen); i++) {
1058 if (pos == grp[i]) {
1059 found = TRUE;
1060 }
1061 }
1062
1063 /* just a way to test picoktab_getPosGroup */
1064 /*
1065 PICODBG_ASSERT(picoktab_getPosGroup(this, grp, grplen) == posgroup);
1066 */
1067 }
1068
1069 return found;
1070 }
1071
1072
picoktab_getPosGroup(const picoktab_Pos this,const picoos_uint8 * poslist,const picoos_uint8 poslistlen)1073 picoos_uint8 picoktab_getPosGroup(const picoktab_Pos this,
1074 const picoos_uint8 *poslist,
1075 const picoos_uint8 poslistlen)
1076 {
1077 picoos_uint8 poscomb;
1078 ktabpos_subobj_t *ktabpos;
1079 picoos_uint16 i, j, n, s;
1080 picoos_uint8 *e;
1081
1082 ktabpos = (ktabpos_subobj_t *) this;
1083 poscomb = 0;
1084
1085 if ((poslistlen > 0) && (poslistlen <= PICOKTAB_MAXNRPOS_IN_COMB)) {
1086 i = poslistlen - 1;
1087 if (i > 0) {
1088 n = ktabpos->nrcomb[i]; /* number of entries */
1089 e = ktabpos->nrcombstart[i]; /* ptr to first entry */
1090 s = i + 2; /* size of an entry in bytes */
1091 j = 0;
1092 while (!poscomb && (j < n)) {
1093 if (ktab_isEqualPosGroup(poslist, e + 1, poslistlen)) {
1094 poscomb = *e;
1095 }
1096 e += s;
1097 j++;
1098 }
1099 if (!poscomb) {
1100 /* combination not found; shouldn't occur if lingware OK! */
1101 /* contingency solution: take first */
1102 PICODBG_WARN(("dynamically created POS combination not found in table; taking first (%i)",poslist[0]));
1103 poscomb = poslist[0];
1104 }
1105 } else { /* not a composed POS */
1106 poscomb = poslist[0];
1107 }
1108 }
1109
1110 return poscomb;
1111 }
1112
1113 #ifdef __cplusplus
1114 }
1115 #endif
1116
1117
1118 /* end */
1119