1 /*
2 *
3 * Copyright (c) 2015, Red Hat, Inc.
4 * Copyright (c) 2015, Masatake YAMATO
5 *
6 * Author: Masatake YAMATO <yamato@redhat.com>
7 *
8 * This source code is released for free distribution under the terms of the
9 * GNU General Public License version 2 or (at your option) any later version.
10 *
11 */
12
13 #include "general.h"
14
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "colprint_p.h"
20 #include "ctags.h"
21 #include "debug.h"
22 #include "entry.h"
23 #include "kind.h"
24 #include "parse_p.h"
25 #include "options.h"
26 #include "ptrarray.h"
27 #include "routines.h"
28 #include "vstring.h"
29
30 typedef struct sRoleObject {
31 roleDefinition *def;
32 freeRoleDefFunc free;
33 } roleObject;
34
35 struct roleControlBlock {
36 roleObject *role;
37 unsigned int count;
38 int owner;
39 };
40
41 typedef struct sKindObject {
42 kindDefinition *def;
43 freeKindDefFunc free;
44 struct roleControlBlock *rcb;
45 ptrArray * dynamicSeparators;
46 } kindObject;
47
48 struct kindControlBlock {
49 kindObject *kind;
50 unsigned int count;
51 langType owner;
52 scopeSeparator defaultScopeSeparator;
53 scopeSeparator defaultRootScopeSeparator;
54 };
55
renderRole(const roleDefinition * const role,vString * b)56 extern const char *renderRole (const roleDefinition* const role, vString* b)
57 {
58 vStringCatS (b, role->name);
59 return vStringValue (b);
60 }
61
printKind(const kindDefinition * const kind,bool indent)62 extern void printKind (const kindDefinition* const kind, bool indent)
63 {
64 printf ("%s%c %s%s\n", indent ? " " : "", kind->letter,
65 kind->description != NULL ? kind->description :
66 (kind->name != NULL ? kind->name : ""),
67 kind->enabled ? "" : " [off]");
68 }
69
enableKind(kindDefinition * kind,bool enable)70 extern void enableKind (kindDefinition *kind, bool enable)
71 {
72 kindDefinition *slave;
73
74 if (kind->master)
75 enableKind (kind->master, enable);
76 else
77 {
78 kind->enabled = enable;
79 for (slave = kind->slave; slave; slave = slave->slave)
80 slave->enabled = enable;
81 }
82 }
83
enableRole(roleDefinition * role,bool enable)84 extern void enableRole (roleDefinition *role, bool enable)
85 {
86 role->enabled = enable;
87 }
88
initRoleObject(roleObject * robj,roleDefinition * rdef,freeRoleDefFunc freefunc,int roleId)89 static void initRoleObject (roleObject *robj, roleDefinition *rdef, freeRoleDefFunc freefunc, int roleId)
90 {
91 #ifdef DEBUG
92 size_t len = strlen (rdef->name);
93 for (int i = 0; i < len; i++)
94 Assert (isalnum (rdef->name [i]));
95 #endif
96 robj->def = rdef;
97 robj->free = freefunc;
98 robj->def->id = roleId;
99 }
100
allocRoleControlBlock(kindObject * kind)101 static struct roleControlBlock* allocRoleControlBlock (kindObject *kind)
102 {
103 unsigned int j;
104 struct roleControlBlock* rcb;
105
106 rcb = xMalloc(1, struct roleControlBlock);
107 rcb->count = kind->def->nRoles;
108 rcb->owner = kind->def->id;
109 rcb->role = xMalloc(rcb->count, roleObject);
110 for (j = 0; j < rcb->count; j++)
111 initRoleObject (rcb->role + j, kind->def->roles + j, NULL, j);
112
113 return rcb;
114 }
115
allocKindControlBlock(parserDefinition * parser)116 extern struct kindControlBlock* allocKindControlBlock (parserDefinition *parser)
117 {
118 unsigned int i;
119 struct kindControlBlock *kcb;
120
121 kcb = xMalloc (1, struct kindControlBlock);
122 kcb->kind = xMalloc (parser->kindCount, kindObject);
123 kcb->count = parser->kindCount;
124 kcb->owner = parser->id;
125
126 kcb->defaultScopeSeparator.parentKindIndex = KIND_WILDCARD_INDEX;
127 kcb->defaultScopeSeparator.separator = NULL;
128 if (parser->defaultScopeSeparator)
129 kcb->defaultScopeSeparator.separator = eStrdup (parser->defaultScopeSeparator);
130
131 kcb->defaultRootScopeSeparator.parentKindIndex = KIND_GHOST_INDEX;
132 kcb->defaultRootScopeSeparator.separator = NULL;
133 if (parser->defaultRootScopeSeparator)
134 kcb->defaultRootScopeSeparator.separator = eStrdup (parser->defaultRootScopeSeparator);
135
136 for (i = 0; i < parser->kindCount; ++i)
137 {
138 kindObject *kind = kcb->kind + i;
139 kind->def = parser->kindTable + i;
140
141 Assert (kind->def->letter != KIND_FILE_DEFAULT_LETTER);
142 Assert (kind->def->name == NULL /* SELF (RUNTIME) TEST NEEDS THIS. */
143 || strcmp(kind->def->name, KIND_FILE_DEFAULT_NAME));
144
145 kind->free = NULL;
146 kind->def->id = i;
147 kind->rcb = allocRoleControlBlock (kind);
148 kind->dynamicSeparators = NULL;
149 }
150
151 return kcb;
152 }
153
freeRoleControlBlock(struct roleControlBlock * rcb)154 static void freeRoleControlBlock (struct roleControlBlock *rcb)
155 {
156 unsigned int i;
157 for (i = 0; i < rcb->count; ++i)
158 {
159 if (rcb->role[i].free)
160 rcb->role [i].free (rcb->role [i].def);
161 }
162 eFreeNoNullCheck (rcb->role);
163 eFree (rcb);
164 }
165
freeKindControlBlock(struct kindControlBlock * kcb)166 extern void freeKindControlBlock (struct kindControlBlock* kcb)
167 {
168 unsigned int i;
169
170 for (i = 0; i < kcb->count; ++i)
171 {
172 if (kcb->kind [i].free)
173 kcb->kind [i].free (kcb->kind [i].def);
174 freeRoleControlBlock (kcb->kind [i].rcb);
175 if (kcb->kind [i].dynamicSeparators)
176 ptrArrayDelete(kcb->kind [i].dynamicSeparators);
177 }
178
179 if (kcb->defaultRootScopeSeparator.separator)
180 eFree((char *)kcb->defaultRootScopeSeparator.separator);
181 if (kcb->defaultScopeSeparator.separator)
182 eFree((char *)kcb->defaultScopeSeparator.separator);
183
184 if (kcb->kind)
185 eFree (kcb->kind);
186 eFree (kcb);
187 }
188
defineKind(struct kindControlBlock * kcb,kindDefinition * def,freeKindDefFunc freeKindDef)189 extern int defineKind (struct kindControlBlock* kcb, kindDefinition *def,
190 freeKindDefFunc freeKindDef)
191 {
192 def->id = kcb->count++;
193 kcb->kind = xRealloc (kcb->kind, kcb->count, kindObject);
194 kcb->kind [def->id].def = def;
195 kcb->kind [def->id].free = freeKindDef;
196 kcb->kind [def->id].rcb = allocRoleControlBlock(kcb->kind + def->id);
197 kcb->kind [def->id].dynamicSeparators = NULL;
198
199 verbose ("Add kind[%d] \"%c,%s,%s\" to %s\n", def->id,
200 def->letter, def->name, def->description,
201 getLanguageName (kcb->owner));
202
203 return def->id;
204 }
205
defineRole(struct kindControlBlock * kcb,int kindIndex,roleDefinition * def,freeRoleDefFunc freeRoleDef)206 extern int defineRole (struct kindControlBlock* kcb, int kindIndex,
207 roleDefinition *def, freeRoleDefFunc freeRoleDef)
208 {
209 struct roleControlBlock *rcb = kcb->kind[kindIndex].rcb;
210 int roleIndex = rcb->count++;
211
212 if (roleIndex == ROLE_MAX_COUNT)
213 {
214 rcb->count--;
215 error (FATAL, "Too many role definition for kind \"%s\" of language \"%s\" (> %d)",
216 kcb->kind[kindIndex].def->name,
217 getLanguageName (kcb->owner),
218 (int)(ROLE_MAX_COUNT - 1));
219 }
220
221 rcb->role = xRealloc (rcb->role, rcb->count, roleObject);
222 initRoleObject (rcb->role + roleIndex, def, freeRoleDef, roleIndex);
223
224 return roleIndex;
225 }
226
isRoleEnabled(struct kindControlBlock * kcb,int kindIndex,int roleIndex)227 extern bool isRoleEnabled (struct kindControlBlock* kcb, int kindIndex, int roleIndex)
228 {
229 roleDefinition *rdef = getRole (kcb, kindIndex, roleIndex);
230 return rdef->enabled;
231 }
232
countKinds(struct kindControlBlock * kcb)233 extern unsigned int countKinds (struct kindControlBlock* kcb)
234 {
235 return kcb->count;
236 }
237
countRoles(struct kindControlBlock * kcb,int kindIndex)238 extern unsigned int countRoles (struct kindControlBlock* kcb, int kindIndex)
239 {
240 return kcb->kind [kindIndex].rcb->count;
241 }
242
getKind(struct kindControlBlock * kcb,int kindIndex)243 extern kindDefinition *getKind (struct kindControlBlock* kcb, int kindIndex)
244 {
245 return kcb->kind [kindIndex].def;
246 }
247
getKindForLetter(struct kindControlBlock * kcb,char letter)248 extern kindDefinition *getKindForLetter (struct kindControlBlock* kcb, char letter)
249 {
250 unsigned int i;
251 kindDefinition * kdef;
252
253 for (i = 0; i < countKinds (kcb); ++i)
254 {
255 kdef = getKind (kcb, i);
256 if (kdef->letter == letter)
257 return kdef;
258 }
259 return NULL;
260 }
261
getKindForName(struct kindControlBlock * kcb,const char * name)262 extern kindDefinition *getKindForName (struct kindControlBlock* kcb, const char* name)
263 {
264 unsigned int i;
265 kindDefinition * kdef;
266
267 for (i = 0; i < countKinds (kcb); ++i)
268 {
269 kdef = getKind (kcb, i);
270 Assert(kdef);
271 if (kdef->name && (strcmp(kdef->name, name) == 0))
272 return kdef;
273 }
274 return NULL;
275 }
276
getKindIndexForLetter(struct kindControlBlock * kcb,char letter)277 extern int getKindIndexForLetter (struct kindControlBlock* kcb, char letter)
278 {
279 unsigned int i;
280 kindDefinition * kdef;
281
282 for (i = 0; i < countKinds (kcb); ++i)
283 {
284 kdef = getKind (kcb, i);
285 if (kdef->letter == letter)
286 return (unsigned int)i;
287 }
288 return KIND_GHOST_INDEX;
289 }
290
getKindIndexForName(struct kindControlBlock * kcb,const char * name)291 extern int getKindIndexForName (struct kindControlBlock* kcb, const char* name)
292 {
293 unsigned int i;
294 kindDefinition * kdef;
295
296 for (i = 0; i < countKinds (kcb); ++i)
297 {
298 kdef = getKind (kcb, i);
299 Assert(kdef);
300 if (kdef->name && (strcmp(kdef->name, name) == 0))
301 return (int)i;
302 }
303 return KIND_GHOST_INDEX;
304 }
305
getRole(struct kindControlBlock * kcb,int kindIndex,int roleIndex)306 extern roleDefinition* getRole(struct kindControlBlock* kcb, int kindIndex, int roleIndex)
307 {
308 struct roleControlBlock *rcb = kcb->kind[kindIndex].rcb;
309 return rcb->role [roleIndex].def;
310 }
311
getRoleForName(struct kindControlBlock * kcb,int kindIndex,const char * name)312 extern roleDefinition* getRoleForName(struct kindControlBlock* kcb,
313 int kindIndex, const char* name)
314 {
315 unsigned int i;
316 roleDefinition *rdef;
317
318 for (i = 0; i < countRoles (kcb, kindIndex); ++i)
319 {
320 rdef = getRole(kcb, kindIndex, i);
321 Assert(rdef);
322 if (rdef->name && (strcmp(rdef->name, name) == 0))
323 return rdef;
324 }
325 return NULL;
326 }
327
linkKinds(langType master,kindDefinition * masterKind,kindDefinition * slaveKind)328 static void linkKinds (langType master, kindDefinition *masterKind, kindDefinition *slaveKind)
329 {
330 kindDefinition *tail;
331
332 slaveKind->master = masterKind;
333
334 tail = slaveKind;
335 while (tail->slave)
336 {
337 tail->enabled = masterKind->enabled;
338 tail = tail->slave;
339 }
340
341 tail->slave = masterKind->slave;
342 masterKind->slave = slaveKind;
343
344 masterKind->syncWith = master;
345 slaveKind->syncWith = master;
346 }
347
linkKindDependency(struct kindControlBlock * masterKCB,struct kindControlBlock * slaveKCB)348 extern void linkKindDependency (struct kindControlBlock *masterKCB,
349 struct kindControlBlock *slaveKCB)
350 {
351 unsigned int k_slave, k_master;
352 kindDefinition *kind_slave, *kind_master;
353
354 for (k_slave = 0; k_slave < countKinds (slaveKCB); k_slave++)
355 {
356 kind_slave = getKind(slaveKCB, k_slave);
357 if (kind_slave->syncWith == LANG_AUTO)
358 {
359 for (k_master = 0; k_master < countKinds (masterKCB); k_master++)
360 {
361 kind_master = getKind(masterKCB, k_master);
362 if ((kind_slave->letter == kind_master->letter)
363 && (strcmp (kind_slave->name, kind_master->name) == 0))
364 {
365 linkKinds (masterKCB->owner, kind_master, kind_slave);
366 break;
367 }
368 }
369 }
370 }
371 }
372
scopeSeparatorDelete(void * data)373 static void scopeSeparatorDelete (void *data)
374 {
375 scopeSeparator *sep = data;
376 eFree ((void *)sep->separator);
377 sep->separator = NULL;
378 eFree (sep);
379 }
380
defineScopeSeparator(struct kindControlBlock * kcb,int kindIndex,int parentKindIndex,const char * separator)381 extern int defineScopeSeparator(struct kindControlBlock* kcb,
382 int kindIndex,
383 int parentKindIndex, const char *separator)
384 {
385 if (kindIndex == KIND_WILDCARD_INDEX)
386 {
387 if (parentKindIndex == KIND_WILDCARD_INDEX)
388 {
389 if (kcb->defaultScopeSeparator.separator)
390 eFree ((char *)kcb->defaultScopeSeparator.separator);
391 verbose ("Installing default separator for %s: %s\n",
392 getLanguageName (kcb->owner), separator);
393 kcb->defaultScopeSeparator.separator = eStrdup (separator);
394 }
395 else if (parentKindIndex == KIND_GHOST_INDEX)
396 {
397 if (kcb->defaultRootScopeSeparator.separator)
398 eFree ((char *)kcb->defaultRootScopeSeparator.separator);
399 verbose ("Installing default root separator for %s: %s\n",
400 getLanguageName (kcb->owner),
401 separator);
402 kcb->defaultRootScopeSeparator.separator = eStrdup (separator);
403 }
404 else
405 error (FATAL,
406 "Don't specify a real kind as parent when defining a default scope separator: %d",
407 parentKindIndex);
408 return 0;
409 }
410 Assert (kcb->count > kindIndex);
411 kindObject *kind = kcb->kind + kindIndex;
412
413 if (!kind->dynamicSeparators)
414 kind->dynamicSeparators = ptrArrayNew (scopeSeparatorDelete);
415
416 scopeSeparator *sep = xMalloc (1, scopeSeparator);
417 sep->parentKindIndex = parentKindIndex;
418 sep->separator = eStrdup(separator);
419 ptrArrayAdd (kind->dynamicSeparators, sep);
420
421 return 0;
422 }
423
getScopeSeparatorDynamic(kindObject * kobj,int parentKindIndex)424 static scopeSeparator *getScopeSeparatorDynamic(kindObject *kobj, int parentKindIndex)
425 {
426 scopeSeparator *sep;
427
428 if (kobj->dynamicSeparators)
429 {
430 for (unsigned int i = ptrArrayCount (kobj->dynamicSeparators); 0 < i ; i--)
431 {
432 sep = ptrArrayItem (kobj->dynamicSeparators, i - 1);
433 if (sep->parentKindIndex == parentKindIndex)
434 return sep;
435 }
436 }
437 return NULL;
438 }
439
getScopeSeparatorStatic(kindDefinition * kdef,int parentKindIndex)440 static const scopeSeparator *getScopeSeparatorStatic(kindDefinition *kdef, int parentKindIndex)
441 {
442 scopeSeparator *table = kdef->separators;
443
444 if (table == NULL)
445 return NULL;
446
447 while (table - kdef->separators < (int)kdef->separatorCount)
448 {
449 if (table->parentKindIndex == parentKindIndex)
450 return table;
451
452 /* If a caller wants a root separator for kdef,
453 we should not return a wildcard table. */
454 if (parentKindIndex != KIND_GHOST_INDEX
455 && table->parentKindIndex == KIND_WILDCARD_INDEX)
456 return table;
457
458 table++;
459 }
460
461 return NULL;
462 }
463
getScopeSeparator(struct kindControlBlock * kcb,int kindIndex,int parentKindIndex)464 extern const scopeSeparator *getScopeSeparator(struct kindControlBlock* kcb,
465 int kindIndex, int parentKindIndex)
466 {
467 Assert (kindIndex != KIND_GHOST_INDEX);
468 Assert (kindIndex != KIND_FILE_INDEX);
469 Assert (kindIndex != KIND_WILDCARD_INDEX);
470
471 Assert (parentKindIndex != KIND_WILDCARD_INDEX);
472 Assert (parentKindIndex != KIND_FILE_INDEX);
473 /* A caller specifies KIND_GHOST_INDEX for parentKindIndex when it
474 * wants root separator. */
475
476 Assert (kcb->count > kindIndex);
477 kindObject *kobj = kcb->kind + kindIndex;
478 const scopeSeparator *sep;
479
480 sep = getScopeSeparatorDynamic (kobj, parentKindIndex);
481 if (sep)
482 return sep;
483
484 sep = getScopeSeparatorStatic (kobj->def, parentKindIndex);
485 if (sep)
486 return sep;
487
488 /* Cannot find a suitable sep definition.
489 * Use default one. */
490 if (parentKindIndex == KIND_GHOST_INDEX)
491 {
492 if (kcb->defaultRootScopeSeparator.separator)
493 return &kcb->defaultRootScopeSeparator;
494 return NULL;
495 }
496 else
497 {
498 if (kcb->defaultScopeSeparator.separator)
499 return &kcb->defaultScopeSeparator;
500
501 static scopeSeparator defaultSeparator = {
502 .separator = ".",
503 .parentKindIndex = KIND_WILDCARD_INDEX,
504 };
505 return &defaultSeparator;
506 }
507 }
508
509 #ifdef DEBUG
doesParserUseKind(struct kindControlBlock * kcb,char letter)510 extern bool doesParserUseKind (struct kindControlBlock* kcb, char letter)
511 {
512 unsigned int k;
513 kindDefinition *kdef;
514
515 for (k = 0; k < countKinds (kcb); k++)
516 {
517 kdef = getKind(kcb, k);
518 if (kdef->letter == letter)
519 return true;
520 }
521 return false;
522 }
523 #endif
524
kindColprintTableNew(void)525 extern struct colprintTable * kindColprintTableNew (void)
526 {
527 return colprintTableNew ("L:LANGUAGE", "L:LETTER", "L:NAME", "L:ENABLED",
528 "L:REFONLY", "L:NROLES", "L:MASTER",
529 "L:DESCRIPTION",
530 NULL);
531 }
532
kindColprintFillLine(struct colprintLine * line,const char * langName,kindDefinition * kdef)533 static void kindColprintFillLine (struct colprintLine *line,
534 const char *langName,
535 kindDefinition *kdef)
536 {
537 langType lang = getNamedLanguage (langName, 0);
538 unsigned int count = countLanguageRoles(lang, kdef->id);
539 colprintLineAppendColumnCString (line, langName);
540 colprintLineAppendColumnChar (line, kdef->letter);
541 colprintLineAppendColumnCString (line, kdef->name
542 ? kdef->name
543 : "ThisShouldNotBePrintedKindNameMustBeGiven");
544 colprintLineAppendColumnBool (line, kdef->enabled);
545 colprintLineAppendColumnBool (line, kdef->referenceOnly);
546 colprintLineAppendColumnInt (line, count);
547 colprintLineAppendColumnCString (line, (kdef->master
548 || kdef->slave ) ?
549 getLanguageName (kdef->syncWith): RSV_NONE);
550 colprintLineAppendColumnCString (line, kdef->description? kdef->description: "NO DESCRIPTION GIVEN");
551 }
552
kindColprintAddLanguageLines(struct colprintTable * table,struct kindControlBlock * kcb)553 extern void kindColprintAddLanguageLines (struct colprintTable *table,
554 struct kindControlBlock* kcb)
555 {
556 const char *lang = getLanguageName (kcb->owner);
557 for (unsigned int i = 0; i < countKinds (kcb); i++)
558 {
559 kindDefinition *kdef = getKind (kcb, i);
560 struct colprintLine *line = colprintTableGetNewLine(table);
561
562 kindColprintFillLine (line, lang, kdef);
563 }
564 }
565
kindColprintCompareLines(struct colprintLine * a,struct colprintLine * b)566 static int kindColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
567 {
568 const char *a_parser = colprintLineGetColumn (a, 0);
569 const char *b_parser = colprintLineGetColumn (b, 0);
570 const char *a_letter;
571 const char *b_letter;
572 int r;
573
574 r = strcmp (a_parser, b_parser);
575 if (r != 0)
576 return r;
577
578 a_letter = colprintLineGetColumn (a, 1);
579 b_letter = colprintLineGetColumn (b, 1);
580 r = strcmp (a_letter, b_letter);
581 if (r != 0)
582 return r;
583
584 return 0;
585 }
586
kindColprintTablePrint(struct colprintTable * table,bool noparser,bool withListHeader,bool machinable,FILE * fp)587 extern void kindColprintTablePrint (struct colprintTable *table, bool noparser,
588 bool withListHeader, bool machinable, FILE *fp)
589 {
590 colprintTableSort (table, kindColprintCompareLines);
591 colprintTablePrint (table, noparser? 1: 0, withListHeader, machinable, fp);
592 }
593
594
roleColprintTableNew(void)595 extern struct colprintTable * roleColprintTableNew (void)
596 {
597 return colprintTableNew ("L:LANGUAGE", "L:KIND(L/N)", "L:NAME",
598 "L:ENABLED", "L:DESCRIPTION", NULL);
599 }
600
roleColprintAddRoles(struct colprintTable * table,struct kindControlBlock * kcb,const char * kindspecs)601 extern void roleColprintAddRoles (struct colprintTable *table, struct kindControlBlock *kcb,
602 const char *kindspecs)
603 {
604 const char* lang;
605 vString *kind_l_and_n;
606
607 lang = getLanguageName (kcb->owner);
608 kind_l_and_n = vStringNew ();
609 for (const char *c = kindspecs; *c != '\0'; c++)
610 {
611 const char *kname = NULL;
612 size_t kname_len;
613
614 if (*c == '{')
615 {
616 const char *start = c + 1;
617 const char *end = strchr(c, '}');
618
619 if (!end)
620 error (FATAL, "'{' is not closed with '}' in \"%s\"", c);
621 if (start == end)
622 error (FATAL, "empty kind name is given in \"%s\"", c);
623
624 kname = start;
625 kname_len = end - start;
626 c = end;
627 }
628
629 for (unsigned int i = 0; i < countKinds (kcb); i++)
630 {
631 const kindDefinition *k = getKind (kcb, i);
632
633 if ((kname
634 && strlen (k->name) == kname_len
635 && strncmp (k->name, kname, kname_len) == 0)
636 || (!kname && *c == k->letter)
637 || (!kname && *c == KIND_WILDCARD_LETTER))
638 {
639 unsigned int nRoles = countRoles(kcb, i);
640 for (unsigned int j = 0; j < nRoles; j++)
641 {
642 const roleDefinition *r = getRole (kcb, i, j);
643 struct colprintLine *line = colprintTableGetNewLine(table);
644
645 colprintLineAppendColumnCString (line, lang);
646
647 vStringPut (kind_l_and_n, k->letter);
648 vStringPut (kind_l_and_n, '/');
649 vStringCatS (kind_l_and_n, k->name);
650 colprintLineAppendColumnVString (line, kind_l_and_n);
651 vStringClear (kind_l_and_n);
652
653 colprintLineAppendColumnCString (line, r->name);
654 colprintLineAppendColumnCString (line,
655 r->enabled ? "on" : "off");
656 colprintLineAppendColumnCString (line, r->description);
657 }
658 if (! (!kname && *c == KIND_WILDCARD_LETTER))
659 break;
660 }
661 }
662 }
663 vStringDelete (kind_l_and_n);
664 #if 0
665 if ((i == countKinds (kcb)) && (*c != KIND_WILDCARD) && (!allowMissingKind))
666 error (FATAL, "No such letter kind in %s: %c\n", lang->name, *c);
667 #endif
668 }
669
roleColprintCompareLines(struct colprintLine * a,struct colprintLine * b)670 static int roleColprintCompareLines(struct colprintLine *a, struct colprintLine *b)
671 {
672 int r;
673
674 const char *a_parser, *b_parser;
675 a_parser = colprintLineGetColumn (a, 0);
676 b_parser = colprintLineGetColumn (b, 0);
677
678 r = strcmp(a_parser, b_parser);
679 if (r != 0)
680 return r;
681
682 const char *a_kindln, *b_kindln;
683 a_kindln = colprintLineGetColumn (a, 1);
684 b_kindln = colprintLineGetColumn (b, 1);
685
686 r = strcmp(a_kindln, b_kindln);
687 if (r != 0)
688 return r;
689
690 const char *a_role, *b_role;
691 a_role = colprintLineGetColumn (a, 2);
692 b_role = colprintLineGetColumn (b, 2);
693
694 return strcmp(a_role, b_role);
695 }
696
roleColprintTablePrint(struct colprintTable * table,bool noparser,bool withListHeader,bool machinable,FILE * fp)697 extern void roleColprintTablePrint (struct colprintTable *table, bool noparser,
698 bool withListHeader, bool machinable, FILE *fp)
699 {
700 colprintTableSort (table, roleColprintCompareLines);
701 colprintTablePrint (table, noparser? 1: 0, withListHeader, machinable, fp);
702 }
703