xref: /Universal-ctags/main/fmt.c (revision c0421c5ec596b5f2a3e1a16a61d6ee3368a68842)
14a63fecaSMasatake YAMATO /*
24a63fecaSMasatake YAMATO  *
34a63fecaSMasatake YAMATO  *  Copyright (c) 2015, Red Hat, Inc.
44a63fecaSMasatake YAMATO  *  Copyright (c) 2015, Masatake YAMATO
54a63fecaSMasatake YAMATO  *
64a63fecaSMasatake YAMATO  *  Author: Masatake YAMATO <yamato@redhat.com>
74a63fecaSMasatake YAMATO  *
84a63fecaSMasatake YAMATO  *   This source code is released for free distribution under the terms of the
94a63fecaSMasatake YAMATO  *   GNU General Public License version 2 or (at your option) any later version.
104a63fecaSMasatake YAMATO  *
114a63fecaSMasatake YAMATO  */
124a63fecaSMasatake YAMATO 
134a63fecaSMasatake YAMATO #include "general.h"
1444fdd1c7SMasatake YAMATO #include "debug.h"
158cbf052bSMasatake YAMATO #include "entry_p.h"
16d45725c1SMasatake YAMATO #include "fmt_p.h"
174a63fecaSMasatake YAMATO #include "field.h"
18c08c70d0SMasatake YAMATO #include "field_p.h"
198f2569d8SMasatake YAMATO #include "parse.h"
204a63fecaSMasatake YAMATO #include "routines.h"
214a63fecaSMasatake YAMATO #include <string.h>
224a63fecaSMasatake YAMATO #include <errno.h>
234a63fecaSMasatake YAMATO 
244a63fecaSMasatake YAMATO typedef union uFmtSpec {
254a63fecaSMasatake YAMATO 	char *const_str;
264a63fecaSMasatake YAMATO 	struct {
27efae38f9SMasatake YAMATO 		fieldType ftype;
284a63fecaSMasatake YAMATO 		int width;
29830b3c66SMasatake YAMATO 		char *raw_fmtstr;
304a63fecaSMasatake YAMATO 	} field;
314a63fecaSMasatake YAMATO } fmtSpec;
324a63fecaSMasatake YAMATO 
334a63fecaSMasatake YAMATO struct sFmtElement {
344a63fecaSMasatake YAMATO 	union uFmtSpec spec;
35509a47dbSJiří Techet 	int (* printer) (fmtSpec*, MIO* fp, const tagEntryInfo *);
364a63fecaSMasatake YAMATO 	struct sFmtElement *next;
374a63fecaSMasatake YAMATO };
384a63fecaSMasatake YAMATO 
printLiteral(fmtSpec * fspec,MIO * fp,const tagEntryInfo * tag CTAGS_ATTR_UNUSED)398ccb7ee9SJiří Techet static int printLiteral (fmtSpec* fspec, MIO* fp, const tagEntryInfo * tag CTAGS_ATTR_UNUSED)
404a63fecaSMasatake YAMATO {
41509a47dbSJiří Techet 	return mio_puts (fp, fspec->const_str);
424a63fecaSMasatake YAMATO }
434a63fecaSMasatake YAMATO 
isParserFieldCompatibleWithFtype(const tagField * pfield,int baseFtype)44ce990805SThomas Braun static bool isParserFieldCompatibleWithFtype (const tagField *pfield, int baseFtype)
458660d347SMasatake YAMATO {
468660d347SMasatake YAMATO 	do {
478660d347SMasatake YAMATO 		if (pfield->ftype == baseFtype)
48ce990805SThomas Braun 			return true;
498660d347SMasatake YAMATO 		baseFtype = nextSiblingField (baseFtype);
508660d347SMasatake YAMATO 	} while (baseFtype != FIELD_UNKNOWN);
51ce990805SThomas Braun 	return false;
528660d347SMasatake YAMATO }
538660d347SMasatake YAMATO 
printTagField(fmtSpec * fspec,MIO * fp,const tagEntryInfo * tag)54509a47dbSJiří Techet static int printTagField (fmtSpec* fspec, MIO* fp, const tagEntryInfo * tag)
554a63fecaSMasatake YAMATO {
564a63fecaSMasatake YAMATO 	int i;
574a63fecaSMasatake YAMATO 	int width = fspec->field.width;
5844fdd1c7SMasatake YAMATO 	int ftype;
59c88e59d9SMasatake YAMATO 	const char* str = NULL;
6044fdd1c7SMasatake YAMATO 
6144fdd1c7SMasatake YAMATO 	ftype = fspec->field.ftype;
6244fdd1c7SMasatake YAMATO 
63546d15f5SMasatake YAMATO 	if (isCommonField (ftype))
645e272693SMasatake YAMATO 		str = renderField (ftype, tag, NO_PARSER_FIELD);
65546d15f5SMasatake YAMATO 	else
6644fdd1c7SMasatake YAMATO 	{
6744fdd1c7SMasatake YAMATO 		unsigned int findex;
684e9e52c2SMasatake YAMATO 		const tagField *f;
6944fdd1c7SMasatake YAMATO 
7044fdd1c7SMasatake YAMATO 		for (findex = 0; findex < tag->usedParserFields; findex++)
7144fdd1c7SMasatake YAMATO 		{
729353c835SMasatake YAMATO 			f = getParserFieldForIndex(tag, findex);
734e9e52c2SMasatake YAMATO 			if (isParserFieldCompatibleWithFtype (f, ftype))
7444fdd1c7SMasatake YAMATO 				break;
7544fdd1c7SMasatake YAMATO 		}
7644fdd1c7SMasatake YAMATO 
778660d347SMasatake YAMATO 		if (findex == tag->usedParserFields)
784d5ee6f7SMasatake YAMATO 			str = "";
794e9e52c2SMasatake YAMATO 		else if (isFieldEnabled (f->ftype))
80322d6c7bSMasatake YAMATO 		{
81322d6c7bSMasatake YAMATO 			unsigned int dt = getFieldDataType (f->ftype);
82322d6c7bSMasatake YAMATO 			if (dt & FIELDTYPE_STRING)
83322d6c7bSMasatake YAMATO 			{
845e272693SMasatake YAMATO 				str = renderField (f->ftype, tag, findex);
85322d6c7bSMasatake YAMATO 				if ((dt & FIELDTYPE_BOOL) && str[0] == '\0')
86322d6c7bSMasatake YAMATO 				{
87322d6c7bSMasatake YAMATO 					/* TODO: FIELD_NULL_LETTER_STRING */
88322d6c7bSMasatake YAMATO 					str = "-";
89322d6c7bSMasatake YAMATO 				}
90322d6c7bSMasatake YAMATO 			}
91322d6c7bSMasatake YAMATO 			else if (dt & FIELDTYPE_BOOL)
92322d6c7bSMasatake YAMATO 				str = getFieldName (f->ftype);
93322d6c7bSMasatake YAMATO 			else
94322d6c7bSMasatake YAMATO 			{
95322d6c7bSMasatake YAMATO 				/* Not implemented */
96322d6c7bSMasatake YAMATO 				AssertNotReached ();
97322d6c7bSMasatake YAMATO 				str = "CTAGS INTERNAL BUG!";
98322d6c7bSMasatake YAMATO 			}
99322d6c7bSMasatake YAMATO 		}
1008660d347SMasatake YAMATO 	}
1014d5ee6f7SMasatake YAMATO 
102c88e59d9SMasatake YAMATO 	if (str == NULL)
103c88e59d9SMasatake YAMATO 		str = "";
104c88e59d9SMasatake YAMATO 
105830b3c66SMasatake YAMATO 	if (width)
106830b3c66SMasatake YAMATO 		i = mio_printf (fp, fspec->field.raw_fmtstr, width, str);
1074a63fecaSMasatake YAMATO 	else
1084a63fecaSMasatake YAMATO 	{
109509a47dbSJiří Techet 		mio_puts (fp, str);
1104a63fecaSMasatake YAMATO 		i = strlen (str);
1114a63fecaSMasatake YAMATO 	}
1124a63fecaSMasatake YAMATO 	return i;
1134a63fecaSMasatake YAMATO }
1144a63fecaSMasatake YAMATO 
queueLiteral(fmtElement ** last,char * literal)1154a63fecaSMasatake YAMATO static fmtElement** queueLiteral (fmtElement **last, char *literal)
1164a63fecaSMasatake YAMATO {
1174a63fecaSMasatake YAMATO 	fmtElement *cur = xMalloc (1, fmtElement);
1184a63fecaSMasatake YAMATO 
1194a63fecaSMasatake YAMATO 	cur->spec.const_str = literal;
1204a63fecaSMasatake YAMATO 	cur->printer = printLiteral;
1214a63fecaSMasatake YAMATO 	cur->next = NULL;
1224a63fecaSMasatake YAMATO 	*last = cur;
1234a63fecaSMasatake YAMATO 	return &(cur->next);
1244a63fecaSMasatake YAMATO }
1254a63fecaSMasatake YAMATO 
1262a2978a3SMasatake YAMATO /* `getLanguageComponentInFieldName' is used as part of the option parameter
1272a2978a3SMasatake YAMATO    for --_xformat option.
1282a2978a3SMasatake YAMATO 
1292a2978a3SMasatake YAMATO    It splits the value of fullName into a language part and a field name part.
1302a2978a3SMasatake YAMATO    Here the two parts are combined with `.'.
1312a2978a3SMasatake YAMATO 
1322a2978a3SMasatake YAMATO    If it cannot find a period, it returns LANG_IGNORE and sets
1332a2978a3SMasatake YAMATO    fullname to *fieldName.
1342a2978a3SMasatake YAMATO 
1352a2978a3SMasatake YAMATO    If lang part if `*', it returns LANG_AUTO and sets the field
1362a2978a3SMasatake YAMATO    name part to *fieldName.
1372a2978a3SMasatake YAMATO 
1382a2978a3SMasatake YAMATO    Though a period is found but no parser (langType) is found for
1392a2978a3SMasatake YAMATO    the language parser, this function returns LANG_IGNORE and sets
1402a2978a3SMasatake YAMATO    NULL to *fieldName.
1412a2978a3SMasatake YAMATO 
1422a2978a3SMasatake YAMATO    A proper parser is found, this function returns langType for the
1432a2978a3SMasatake YAMATO    parser and sets the field name part to *fieldName. */
getLanguageComponentInFieldName(const char * fullName,const char ** fieldName)1442a2978a3SMasatake YAMATO static langType getLanguageComponentInFieldName (const char *fullName,
1452a2978a3SMasatake YAMATO 						 const char **fieldName)
1462a2978a3SMasatake YAMATO {
1472a2978a3SMasatake YAMATO 	const char *tmp;
1482a2978a3SMasatake YAMATO 	langType language;
1492a2978a3SMasatake YAMATO 
1502a2978a3SMasatake YAMATO 	tmp = strchr (fullName, '.');
1512a2978a3SMasatake YAMATO 	if (tmp)
1522a2978a3SMasatake YAMATO 	{
1532a2978a3SMasatake YAMATO 		size_t len = tmp - fullName;
1542a2978a3SMasatake YAMATO 
1552a2978a3SMasatake YAMATO 		if (len == 1 && fullName[0] == '*')
1562a2978a3SMasatake YAMATO 		{
1572a2978a3SMasatake YAMATO 			language = LANG_AUTO;
1582a2978a3SMasatake YAMATO 			*fieldName = tmp + 1;
1592a2978a3SMasatake YAMATO 		}
1602a2978a3SMasatake YAMATO 		else if (len == 0)
1612a2978a3SMasatake YAMATO 		{
1622a2978a3SMasatake YAMATO 			language = LANG_IGNORE;
1632a2978a3SMasatake YAMATO 			*fieldName = tmp + 1;
1642a2978a3SMasatake YAMATO 		}
1652a2978a3SMasatake YAMATO 		else
1662a2978a3SMasatake YAMATO 		{
1672a2978a3SMasatake YAMATO 			language = getNamedLanguage (fullName, len);
1682a2978a3SMasatake YAMATO 			if (language == LANG_IGNORE)
1692a2978a3SMasatake YAMATO 				*fieldName = NULL;
1702a2978a3SMasatake YAMATO 			else
1712a2978a3SMasatake YAMATO 				*fieldName = tmp + 1;
1722a2978a3SMasatake YAMATO 		}
1732a2978a3SMasatake YAMATO 	}
1742a2978a3SMasatake YAMATO 	else
1752a2978a3SMasatake YAMATO 	{
1762a2978a3SMasatake YAMATO 		language = LANG_IGNORE;
1772a2978a3SMasatake YAMATO 		*fieldName = fullName;
1782a2978a3SMasatake YAMATO 	}
1792a2978a3SMasatake YAMATO 	return language;
1802a2978a3SMasatake YAMATO }
1812a2978a3SMasatake YAMATO 
queueTagField(fmtElement ** last,long width,bool truncation,char field_letter,const char * field_name)18218d5414aSMasatake YAMATO static fmtElement** queueTagField (fmtElement **last, long width, bool truncation,
18318d5414aSMasatake YAMATO 								   char field_letter, const char *field_name)
1844a63fecaSMasatake YAMATO {
1854a63fecaSMasatake YAMATO 	fieldType ftype;
1864a63fecaSMasatake YAMATO 	fmtElement *cur;
1878f2569d8SMasatake YAMATO 	langType language;
1884a63fecaSMasatake YAMATO 
18944fdd1c7SMasatake YAMATO 	if (field_letter == NUL_FIELD_LETTER)
1908f2569d8SMasatake YAMATO 	{
1918f2569d8SMasatake YAMATO 		const char *f;
1928f2569d8SMasatake YAMATO 
1938f2569d8SMasatake YAMATO 		language = getLanguageComponentInFieldName (field_name, &f);
1948660d347SMasatake YAMATO 		if (f == NULL)
1958660d347SMasatake YAMATO 			error (FATAL, "No suitable parser for field name: %s", field_name);
1968f2569d8SMasatake YAMATO 		ftype = getFieldTypeForNameAndLanguage (f, language);
1978f2569d8SMasatake YAMATO 	}
19844fdd1c7SMasatake YAMATO 	else
1998f2569d8SMasatake YAMATO 	{
2008f2569d8SMasatake YAMATO 		language = LANG_IGNORE;
2014a63fecaSMasatake YAMATO 		ftype = getFieldTypeForOption (field_letter);
2028f2569d8SMasatake YAMATO 	}
20344fdd1c7SMasatake YAMATO 
2044a63fecaSMasatake YAMATO 	if (ftype == FIELD_UNKNOWN)
20544fdd1c7SMasatake YAMATO 	{
20644fdd1c7SMasatake YAMATO 		if (field_letter == NUL_FIELD_LETTER)
20744fdd1c7SMasatake YAMATO 			error (FATAL, "No such field name: %s", field_name);
20844fdd1c7SMasatake YAMATO 		else
2094a63fecaSMasatake YAMATO 			error (FATAL, "No such field letter: %c", field_letter);
21044fdd1c7SMasatake YAMATO 	}
2114a63fecaSMasatake YAMATO 
2125e272693SMasatake YAMATO 	if (!doesFieldHaveRenderer (ftype, false))
21344fdd1c7SMasatake YAMATO 	{
21444fdd1c7SMasatake YAMATO 		Assert (field_letter != NUL_FIELD_LETTER);
2154a63fecaSMasatake YAMATO 		error (FATAL, "The field cannot be printed in format output: %c", field_letter);
21644fdd1c7SMasatake YAMATO 	}
2174a63fecaSMasatake YAMATO 
2184a63fecaSMasatake YAMATO 	cur = xMalloc (1, fmtElement);
2194a63fecaSMasatake YAMATO 
2204a63fecaSMasatake YAMATO 	cur->spec.field.width = width;
221efae38f9SMasatake YAMATO 	cur->spec.field.ftype = ftype;
222830b3c66SMasatake YAMATO 
223830b3c66SMasatake YAMATO 	if (width < 0)
224830b3c66SMasatake YAMATO 	{
225830b3c66SMasatake YAMATO 		cur->spec.field.width *= -1;
226830b3c66SMasatake YAMATO 		cur->spec.field.raw_fmtstr = (truncation? "%-.*s": "%-*s");
227830b3c66SMasatake YAMATO 	}
228830b3c66SMasatake YAMATO 	else if (width > 0)
229830b3c66SMasatake YAMATO 		cur->spec.field.raw_fmtstr = (truncation? "%.*s": "%*s");
230830b3c66SMasatake YAMATO 	else
231830b3c66SMasatake YAMATO 		cur->spec.field.raw_fmtstr = NULL;
2324a63fecaSMasatake YAMATO 
233*c0421c5eSMasatake YAMATO 	enableField (ftype, true);
2348f2569d8SMasatake YAMATO 	if (language == LANG_AUTO)
2358f2569d8SMasatake YAMATO 	{
2368f2569d8SMasatake YAMATO 		fieldType ftype_next = ftype;
237a6c7c87fSMasatake YAMATO 
238a6c7c87fSMasatake YAMATO 		while ((ftype_next = nextSiblingField (ftype_next)) != FIELD_UNKNOWN)
239*c0421c5eSMasatake YAMATO 			enableField (ftype_next, true);
2408f2569d8SMasatake YAMATO 	}
2414a63fecaSMasatake YAMATO 
2424a63fecaSMasatake YAMATO 	cur->printer = printTagField;
2434a63fecaSMasatake YAMATO 	cur->next = NULL;
2444a63fecaSMasatake YAMATO 	*last = cur;
2454a63fecaSMasatake YAMATO 	return &(cur->next);
2464a63fecaSMasatake YAMATO }
2474a63fecaSMasatake YAMATO 
fmtNew(const char * fmtString)2484a63fecaSMasatake YAMATO extern fmtElement *fmtNew (const char*  fmtString)
2494a63fecaSMasatake YAMATO {
2504a63fecaSMasatake YAMATO 	int i;
2514a63fecaSMasatake YAMATO 	vString *literal = NULL;
2524a63fecaSMasatake YAMATO 	fmtElement *code  = NULL;
2534a63fecaSMasatake YAMATO 	fmtElement **last = &code;
254ce990805SThomas Braun 	bool found_percent = false;
2554a63fecaSMasatake YAMATO 	long column_width;
2564a63fecaSMasatake YAMATO 	const char*  cursor;
2574a63fecaSMasatake YAMATO 
2584a63fecaSMasatake YAMATO 	cursor = fmtString;
2594a63fecaSMasatake YAMATO 
2604a63fecaSMasatake YAMATO 	for (i = 0; cursor[i] != '\0'; ++i)
2614a63fecaSMasatake YAMATO 	{
2624a63fecaSMasatake YAMATO 		if (found_percent)
2634a63fecaSMasatake YAMATO 		{
264ce990805SThomas Braun 			found_percent = false;
2654a63fecaSMasatake YAMATO 			if (cursor[i] == '%')
2664a63fecaSMasatake YAMATO 			{
2674a63fecaSMasatake YAMATO 				if (literal == NULL)
2684a63fecaSMasatake YAMATO 					literal = vStringNew ();
2694a63fecaSMasatake YAMATO 				vStringPut (literal, cursor[i]);
2704a63fecaSMasatake YAMATO 			}
2714a63fecaSMasatake YAMATO 			else
2724a63fecaSMasatake YAMATO 			{
2734a63fecaSMasatake YAMATO 				int justification_right = 1;
27418d5414aSMasatake YAMATO 				bool truncation = false;
2754a63fecaSMasatake YAMATO 				vString *width = NULL;
2764a63fecaSMasatake YAMATO 				if (literal)
2774a63fecaSMasatake YAMATO 				{
2784a63fecaSMasatake YAMATO 					char* l = vStringDeleteUnwrap (literal);
2794a63fecaSMasatake YAMATO 					literal = NULL;
2804a63fecaSMasatake YAMATO 					last = queueLiteral (last, l);
2814a63fecaSMasatake YAMATO 				}
2824a63fecaSMasatake YAMATO 				if (cursor [i] == '-')
2834a63fecaSMasatake YAMATO 				{
2844a63fecaSMasatake YAMATO 					justification_right = -1;
2854a63fecaSMasatake YAMATO 					i++;
2864a63fecaSMasatake YAMATO 
2874a63fecaSMasatake YAMATO 					if (cursor [i] == '\0')
2884a63fecaSMasatake YAMATO 						error (FATAL, "unexpectedly terminated just after '-': \"%s\"", fmtString);
2894a63fecaSMasatake YAMATO 
2904a63fecaSMasatake YAMATO 				}
29118d5414aSMasatake YAMATO 				if (cursor [i] == '.')
29218d5414aSMasatake YAMATO 				{
29318d5414aSMasatake YAMATO 					truncation = true;
29418d5414aSMasatake YAMATO 					i++;
29518d5414aSMasatake YAMATO 
29618d5414aSMasatake YAMATO 					if (cursor [i] == '\0')
29718d5414aSMasatake YAMATO 						error (FATAL, "unexpectedly terminated just after '.': \"%s\"", fmtString);
29818d5414aSMasatake YAMATO 				}
2994a63fecaSMasatake YAMATO 
3004a63fecaSMasatake YAMATO 				while ( '0' <= cursor[i] && cursor[i] <= '9' )
3014a63fecaSMasatake YAMATO 				{
3024a63fecaSMasatake YAMATO 					if (width == NULL)
3034a63fecaSMasatake YAMATO 						width = vStringNew ();
3044a63fecaSMasatake YAMATO 					vStringPut (width, cursor[i]);
3054a63fecaSMasatake YAMATO 					i++;
3064a63fecaSMasatake YAMATO 
3074a63fecaSMasatake YAMATO 					if (cursor [i] == '\0')
3084a63fecaSMasatake YAMATO 						error (FATAL, "unexpectedly terminated during parsing column width: \"%s\"", fmtString);
3094a63fecaSMasatake YAMATO 				}
3104a63fecaSMasatake YAMATO 
3114a63fecaSMasatake YAMATO 				if (justification_right == -1 && width == NULL)
3124a63fecaSMasatake YAMATO 					error (FATAL, "no column width given after '-': \"%s\"", fmtString);
3134a63fecaSMasatake YAMATO 
3144a63fecaSMasatake YAMATO 				column_width = 0;
3154a63fecaSMasatake YAMATO 				if (width)
3164a63fecaSMasatake YAMATO 				{
317fa94dd09SThomas Braun 					if(!strToLong (vStringValue (width), 0, &column_width))
318759d281dSK.Takata 						error (FATAL | PERROR, "converting failed: %s", vStringValue (width));
3194a63fecaSMasatake YAMATO 					vStringDelete (width);
3204a63fecaSMasatake YAMATO 					width = NULL;
3214a63fecaSMasatake YAMATO 					column_width *= justification_right;
3224a63fecaSMasatake YAMATO 				}
3234a63fecaSMasatake YAMATO 
32444fdd1c7SMasatake YAMATO 				if (cursor[i] == '{')
32544fdd1c7SMasatake YAMATO 				{
32644fdd1c7SMasatake YAMATO 					vString *field_name = vStringNew ();
32744fdd1c7SMasatake YAMATO 
32844fdd1c7SMasatake YAMATO 					i++;
32944fdd1c7SMasatake YAMATO 					for (; cursor[i] != '}'; i++)
33044fdd1c7SMasatake YAMATO 						vStringPut (field_name, cursor[i]);
33144fdd1c7SMasatake YAMATO 
33218d5414aSMasatake YAMATO 					last = queueTagField (last, column_width, truncation,
33318d5414aSMasatake YAMATO 										  NUL_FIELD_LETTER, vStringValue (field_name));
33444fdd1c7SMasatake YAMATO 
33544fdd1c7SMasatake YAMATO 					vStringDelete (field_name);
33644fdd1c7SMasatake YAMATO 				}
33744fdd1c7SMasatake YAMATO 				else
33818d5414aSMasatake YAMATO 					last = queueTagField (last, column_width, truncation,
33918d5414aSMasatake YAMATO 										  cursor[i], NULL);
3404a63fecaSMasatake YAMATO 			}
3414a63fecaSMasatake YAMATO 
3424a63fecaSMasatake YAMATO 		}
3434a63fecaSMasatake YAMATO 		else
3444a63fecaSMasatake YAMATO 		{
3454a63fecaSMasatake YAMATO 			if (cursor[i] == '%')
346ce990805SThomas Braun 				found_percent = true;
3474a63fecaSMasatake YAMATO 			else
3484a63fecaSMasatake YAMATO 			{
3494a63fecaSMasatake YAMATO 				if (literal == NULL)
3504a63fecaSMasatake YAMATO 					literal = vStringNew ();
3514a63fecaSMasatake YAMATO 
3524a63fecaSMasatake YAMATO 				vStringPut (literal, cursor[i]);
3534a63fecaSMasatake YAMATO 			}
3544a63fecaSMasatake YAMATO 		}
3554a63fecaSMasatake YAMATO 	}
3564a63fecaSMasatake YAMATO 	if (literal)
3574a63fecaSMasatake YAMATO 	{
3584a63fecaSMasatake YAMATO 		char* l = vStringDeleteUnwrap (literal);
3594a63fecaSMasatake YAMATO 		literal = NULL;
3604a63fecaSMasatake YAMATO 		last = queueLiteral (last, l);
3614a63fecaSMasatake YAMATO 	}
3624a63fecaSMasatake YAMATO 	return code;
3634a63fecaSMasatake YAMATO }
3644a63fecaSMasatake YAMATO 
fmtPrint(fmtElement * fmtelts,MIO * fp,const tagEntryInfo * tag)365509a47dbSJiří Techet extern int fmtPrint   (fmtElement * fmtelts, MIO* fp, const tagEntryInfo *tag)
3664a63fecaSMasatake YAMATO {
3674a63fecaSMasatake YAMATO 	fmtElement *f = fmtelts;
3684a63fecaSMasatake YAMATO 	int i = 0;
3694a63fecaSMasatake YAMATO 	while (f)
3704a63fecaSMasatake YAMATO 	{
3714a63fecaSMasatake YAMATO 		i += f->printer (&(f->spec), fp, tag);
3724a63fecaSMasatake YAMATO 		f = f->next;
3734a63fecaSMasatake YAMATO 	}
3744a63fecaSMasatake YAMATO 	return i;
3754a63fecaSMasatake YAMATO }
3764a63fecaSMasatake YAMATO 
fmtDelete(fmtElement * fmtelts)3774a63fecaSMasatake YAMATO extern void fmtDelete  (fmtElement * fmtelts)
3784a63fecaSMasatake YAMATO {
3794a63fecaSMasatake YAMATO 	fmtElement *f = fmtelts;
3804a63fecaSMasatake YAMATO 	fmtElement *next;
3814a63fecaSMasatake YAMATO 
3824a63fecaSMasatake YAMATO 	while (f)
3834a63fecaSMasatake YAMATO 	{
3844a63fecaSMasatake YAMATO 		next = f->next;
3854a63fecaSMasatake YAMATO 		if (f->printer == printLiteral)
3864a63fecaSMasatake YAMATO 		{
3874a63fecaSMasatake YAMATO 			eFree (f->spec.const_str);
3884a63fecaSMasatake YAMATO 			f->spec.const_str = NULL;
3894a63fecaSMasatake YAMATO 		}
3904a63fecaSMasatake YAMATO 		f->next = NULL;
3914a63fecaSMasatake YAMATO 		eFree (f);
3924a63fecaSMasatake YAMATO 		f = next;
3934a63fecaSMasatake YAMATO 	}
3944a63fecaSMasatake YAMATO }
395