xref: /Universal-ctags/main/kind.c (revision 7b586ba76f3545f85f037242b441dbed189413a7)
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