xref: /Universal-ctags/parsers/windres.c (revision 16a2541c0698bd8ee03c1be8172ef3191f6e695a)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO  *	windres.c
33ae02089SMasatake YAMATO  *
43ae02089SMasatake YAMATO  *	Copyright (c) 2013, Frank Fesevur <ffes(at)users.sourceforge.net>
53ae02089SMasatake YAMATO  *
63ae02089SMasatake YAMATO  *	This source code is released for free distribution under the terms of the
70ce38835Sviccuad  *	GNU General Public License version 2 or (at your option) any later version.
83ae02089SMasatake YAMATO  *
93ae02089SMasatake YAMATO  *	This module contains functions for generating tags for Windows Resource files.
103ae02089SMasatake YAMATO  */
113ae02089SMasatake YAMATO 
123ae02089SMasatake YAMATO #include "general.h"
133ae02089SMasatake YAMATO 
143ae02089SMasatake YAMATO #include <string.h>
153ae02089SMasatake YAMATO #include <ctype.h>
163ae02089SMasatake YAMATO 
173ae02089SMasatake YAMATO #include "parse.h"
183ae02089SMasatake YAMATO #include "read.h"
193db72c21SMasatake YAMATO #include "routines.h"
203ae02089SMasatake YAMATO 
213ae02089SMasatake YAMATO static int _blockDepth = 0;
223ae02089SMasatake YAMATO 
233ae02089SMasatake YAMATO typedef enum _WindResKinds
243ae02089SMasatake YAMATO {
253ae02089SMasatake YAMATO 	K_NONE = -1,
263ae02089SMasatake YAMATO 	K_DIALOG,
273ae02089SMasatake YAMATO 	K_MENU,
283ae02089SMasatake YAMATO 	K_ICON,
293ae02089SMasatake YAMATO 	K_BITMAP,
303ae02089SMasatake YAMATO 	K_CURSOR,
313ae02089SMasatake YAMATO 	K_FONT,
323ae02089SMasatake YAMATO 	K_VERSION,
333ae02089SMasatake YAMATO 	K_ACCELERATORS
343ae02089SMasatake YAMATO } ResKind;
353ae02089SMasatake YAMATO 
36e112e8abSMasatake YAMATO static kindDefinition ResKinds [] = {
37ce990805SThomas Braun 	{ true, 'd', "dialog",			"dialogs"		},
38ce990805SThomas Braun 	{ true, 'm', "menu",			"menus"			},
39ce990805SThomas Braun 	{ true, 'i', "icon",			"icons"			},
40ce990805SThomas Braun 	{ true, 'b', "bitmap",			"bitmaps"		},
41ce990805SThomas Braun 	{ true, 'c', "cursor",			"cursors"		},
42ce990805SThomas Braun 	{ true, 'f', "font",			"fonts"			},
43ce990805SThomas Braun 	{ true, 'v', "version",			"versions"		},
44ce990805SThomas Braun 	{ true, 'a', "accelerators",	"accelerators"	}
453ae02089SMasatake YAMATO };
463ae02089SMasatake YAMATO 
473ae02089SMasatake YAMATO typedef enum _WindResParserState
483ae02089SMasatake YAMATO {
493ae02089SMasatake YAMATO 	P_STATE_NONE,
503ae02089SMasatake YAMATO 	P_STATE_IN_COMMENT,
513ae02089SMasatake YAMATO 	P_STATE_IN_STATEMENTS,		/* Between first line of item and BEGIN/{ */
523ae02089SMasatake YAMATO 	P_STATE_IN_BLOCK,			/* In a BEGIN/END or {/} block */
533ae02089SMasatake YAMATO 	P_STATE_AT_END
543ae02089SMasatake YAMATO } ResParserState;
553ae02089SMasatake YAMATO 
makeResTag(vString * name,ResKind kind)563ae02089SMasatake YAMATO static void makeResTag(vString *name, ResKind kind)
573ae02089SMasatake YAMATO {
583ae02089SMasatake YAMATO 	vStringStripTrailing(name);
59*16a2541cSMasatake YAMATO 	makeSimpleTag(name, kind);
603ae02089SMasatake YAMATO 	vStringClear(name);
613ae02089SMasatake YAMATO }
623ae02089SMasatake YAMATO 
parseResDefinition(const unsigned char * line)633ae02089SMasatake YAMATO static ResParserState parseResDefinition(const unsigned char *line)
643ae02089SMasatake YAMATO {
653ae02089SMasatake YAMATO 	ResParserState state = P_STATE_NONE;
663ae02089SMasatake YAMATO 	vString *name, *type;
673ae02089SMasatake YAMATO 
683ae02089SMasatake YAMATO 	name = vStringNew();
693ae02089SMasatake YAMATO 	while (*line && !isspace((int) *line))
703ae02089SMasatake YAMATO 	{
713ae02089SMasatake YAMATO 		vStringPut(name, (int) *line);
723ae02089SMasatake YAMATO 		line++;
733ae02089SMasatake YAMATO 	}
743ae02089SMasatake YAMATO 
753ae02089SMasatake YAMATO 	while (*line && isspace((int) *line))
763ae02089SMasatake YAMATO 		line++;
773ae02089SMasatake YAMATO 
783ae02089SMasatake YAMATO 	type = vStringNew();
793ae02089SMasatake YAMATO 	while (*line && !isspace((int) *line))
803ae02089SMasatake YAMATO 	{
813ae02089SMasatake YAMATO 		vStringPut(type, (int) *line);
823ae02089SMasatake YAMATO 		line++;
833ae02089SMasatake YAMATO 	}
843ae02089SMasatake YAMATO 
853ae02089SMasatake YAMATO 	if (strcmp(vStringValue(type), "DIALOG") == 0 || strcmp(vStringValue(type), "DIALOGEX") == 0)
863ae02089SMasatake YAMATO 	{
873ae02089SMasatake YAMATO 		makeResTag(name, K_DIALOG);
883ae02089SMasatake YAMATO 		state = P_STATE_IN_STATEMENTS;
893ae02089SMasatake YAMATO 	}
903ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "MENU") == 0 || strcmp(vStringValue(type), "MENUEX") == 0)
913ae02089SMasatake YAMATO 	{
923ae02089SMasatake YAMATO 		makeResTag(name, K_MENU);
933ae02089SMasatake YAMATO 		state = P_STATE_IN_STATEMENTS;
943ae02089SMasatake YAMATO 	}
953ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "VERSIONINFO") == 0)
963ae02089SMasatake YAMATO 	{
973ae02089SMasatake YAMATO 		makeResTag(name, K_VERSION);
983ae02089SMasatake YAMATO 		state = P_STATE_IN_STATEMENTS;
993ae02089SMasatake YAMATO 	}
1003ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "ACCELERATORS") == 0)
1013ae02089SMasatake YAMATO 	{
1023ae02089SMasatake YAMATO 		makeResTag(name, K_ACCELERATORS);
1033ae02089SMasatake YAMATO 		state = P_STATE_IN_STATEMENTS;
1043ae02089SMasatake YAMATO 	}
1053ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "ICON") == 0)
1063ae02089SMasatake YAMATO 	{
1073ae02089SMasatake YAMATO 		makeResTag(name, K_ICON);
1083ae02089SMasatake YAMATO 		state = P_STATE_NONE;
1093ae02089SMasatake YAMATO 	}
1103ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "CURSOR") == 0)
1113ae02089SMasatake YAMATO 	{
1123ae02089SMasatake YAMATO 		makeResTag(name, K_CURSOR);
1133ae02089SMasatake YAMATO 		state = P_STATE_NONE;
1143ae02089SMasatake YAMATO 	}
1153ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "BITMAP") == 0)
1163ae02089SMasatake YAMATO 	{
1173ae02089SMasatake YAMATO 		makeResTag(name, K_BITMAP);
1183ae02089SMasatake YAMATO 		state = P_STATE_NONE;
1193ae02089SMasatake YAMATO 	}
1203ae02089SMasatake YAMATO 	else if (strcmp(vStringValue(type), "FONT") == 0)
1213ae02089SMasatake YAMATO 	{
1223ae02089SMasatake YAMATO 		makeResTag(name, K_FONT);
1233ae02089SMasatake YAMATO 		state = P_STATE_NONE;
1243ae02089SMasatake YAMATO 	}
1253ae02089SMasatake YAMATO 
1263ae02089SMasatake YAMATO 	vStringDelete(name);
1273ae02089SMasatake YAMATO 	vStringDelete(type);
1283ae02089SMasatake YAMATO 
1293ae02089SMasatake YAMATO 	return state;
1303ae02089SMasatake YAMATO }
1313ae02089SMasatake YAMATO 
parseResLine(const unsigned char * line,ResParserState state)1323ae02089SMasatake YAMATO static ResParserState parseResLine(const unsigned char *line, ResParserState state)
1333ae02089SMasatake YAMATO {
1341b312fe7SMasatake YAMATO 	while (*line != '\0')	/* readLineFromInputFile returns NULL terminated strings */
1353ae02089SMasatake YAMATO 	{
1363ae02089SMasatake YAMATO 		while (isspace((int) *line))
1373ae02089SMasatake YAMATO 			line++;
1383ae02089SMasatake YAMATO 
1393ae02089SMasatake YAMATO 		switch (state)
1403ae02089SMasatake YAMATO 		{
1413ae02089SMasatake YAMATO 			case P_STATE_NONE:
1423ae02089SMasatake YAMATO 			{
1433ae02089SMasatake YAMATO 				/* C-styled # line (#include, #define, etc), ignore rest of line */
1443ae02089SMasatake YAMATO 				if (*line == '#')
1453ae02089SMasatake YAMATO 				{
1463ae02089SMasatake YAMATO 					return P_STATE_NONE;
1473ae02089SMasatake YAMATO 				}
1483ae02089SMasatake YAMATO 				/* single line comment, ignore rest of line */
1493ae02089SMasatake YAMATO 				else if (*line == '/' && line[1] == '/')
1503ae02089SMasatake YAMATO 				{
1513ae02089SMasatake YAMATO 					return P_STATE_NONE;
1523ae02089SMasatake YAMATO 				}
1533ae02089SMasatake YAMATO 				/* multi-line comment */
1543ae02089SMasatake YAMATO 				else if( *line == '/' && line[1] == '*' )
1553ae02089SMasatake YAMATO 				{
1563ae02089SMasatake YAMATO 					state = P_STATE_IN_COMMENT;
1573ae02089SMasatake YAMATO 				}
1583ae02089SMasatake YAMATO 				else if (isalnum((int) *line))
1593ae02089SMasatake YAMATO 				{
1603ae02089SMasatake YAMATO 					return parseResDefinition(line);
1613ae02089SMasatake YAMATO 				}
1623ae02089SMasatake YAMATO 				break;
1633ae02089SMasatake YAMATO 			}
1643ae02089SMasatake YAMATO 			case P_STATE_IN_COMMENT:
1653ae02089SMasatake YAMATO 			{
1663ae02089SMasatake YAMATO 				if (*line == '*' && line[1] == '/')
1673ae02089SMasatake YAMATO 					state = P_STATE_NONE;
1683ae02089SMasatake YAMATO 				break;
1693ae02089SMasatake YAMATO 			}
1703ae02089SMasatake YAMATO 			case P_STATE_IN_STATEMENTS:
1713ae02089SMasatake YAMATO 			{
1723ae02089SMasatake YAMATO 				/* First BEGIN block */
1733ae02089SMasatake YAMATO 				if (*line == '{' || strcmp((const char *) line, "BEGIN") == 0)
1743ae02089SMasatake YAMATO 				{
1753ae02089SMasatake YAMATO 					_blockDepth = 1;
1763ae02089SMasatake YAMATO 					return P_STATE_IN_BLOCK;
1773ae02089SMasatake YAMATO 				}
1783ae02089SMasatake YAMATO 				break;
1793ae02089SMasatake YAMATO 			}
1803ae02089SMasatake YAMATO 			case P_STATE_IN_BLOCK:
1813ae02089SMasatake YAMATO 			{
1823ae02089SMasatake YAMATO 				/* Nested BEGIN blocks? */
1833ae02089SMasatake YAMATO 				if (*line == '{' || strcmp((const char *) line, "BEGIN") == 0)
1843ae02089SMasatake YAMATO 				{
1853ae02089SMasatake YAMATO 					_blockDepth++;
1863ae02089SMasatake YAMATO 				}
1873ae02089SMasatake YAMATO 				else if (*line == '}' || strcmp((const char *) line, "END") == 0)
1883ae02089SMasatake YAMATO 				{
1893ae02089SMasatake YAMATO 					if (_blockDepth == 1)
1903ae02089SMasatake YAMATO 						return P_STATE_NONE;
1913ae02089SMasatake YAMATO 					else
1923ae02089SMasatake YAMATO 						_blockDepth--;
1933ae02089SMasatake YAMATO 				}
1943ae02089SMasatake YAMATO 				break;
1953ae02089SMasatake YAMATO 			}
1963ae02089SMasatake YAMATO 			case P_STATE_AT_END:
1973ae02089SMasatake YAMATO 			{
1983ae02089SMasatake YAMATO 				return state;
1993ae02089SMasatake YAMATO 			}
2003ae02089SMasatake YAMATO 		}
2013ae02089SMasatake YAMATO 		if (line == NULL)
2023ae02089SMasatake YAMATO 			return P_STATE_AT_END;
2033ae02089SMasatake YAMATO 		line++;
2043ae02089SMasatake YAMATO 	}
2053ae02089SMasatake YAMATO 
2063ae02089SMasatake YAMATO 	return state;
2073ae02089SMasatake YAMATO }
2083ae02089SMasatake YAMATO 
findResTags(void)2093ae02089SMasatake YAMATO static void findResTags(void)
2103ae02089SMasatake YAMATO {
2113ae02089SMasatake YAMATO 	const unsigned char *line;
2123ae02089SMasatake YAMATO 	ResParserState state = P_STATE_NONE;
2133ae02089SMasatake YAMATO 	_blockDepth = 0;
2143ae02089SMasatake YAMATO 
2151b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile()) != NULL)
2163ae02089SMasatake YAMATO 	{
2173ae02089SMasatake YAMATO 		state = parseResLine(line, state);
2183ae02089SMasatake YAMATO 		if (state == P_STATE_AT_END)
2193ae02089SMasatake YAMATO 			return;
2203ae02089SMasatake YAMATO 	}
2213ae02089SMasatake YAMATO }
2223ae02089SMasatake YAMATO 
2233ae02089SMasatake YAMATO /* parser definition */
WindResParser(void)2243ae02089SMasatake YAMATO extern parserDefinition* WindResParser(void)
2253ae02089SMasatake YAMATO {
2263ae02089SMasatake YAMATO 	static const char *const extensions [] = { "rc", NULL };
2273ae02089SMasatake YAMATO 	parserDefinition* def = parserNew("WindRes");
22809ae690fSMasatake YAMATO 	def->kindTable	= ResKinds;
2293db72c21SMasatake YAMATO 	def->kindCount	= ARRAY_SIZE(ResKinds);
2303ae02089SMasatake YAMATO 	def->extensions	= extensions;
2313ae02089SMasatake YAMATO 	def->parser		= findResTags;
2323ae02089SMasatake YAMATO 	return def;
2333ae02089SMasatake YAMATO }
234