xref: /Universal-ctags/parsers/sh.c (revision 3671ad7255885a0c8f6ff4979d80c70f201ea411)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2000-2002, Darren Hiebert
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains functions for generating tags for scripts for the
83ae02089SMasatake YAMATO *   Bourne shell (and its derivatives, the Korn and Z shells).
93ae02089SMasatake YAMATO */
103ae02089SMasatake YAMATO 
113ae02089SMasatake YAMATO /*
123ae02089SMasatake YAMATO *   INCLUDE FILES
133ae02089SMasatake YAMATO */
143ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
153ae02089SMasatake YAMATO 
163ae02089SMasatake YAMATO #include <string.h>
173ae02089SMasatake YAMATO 
1875cd0d29SMasatake YAMATO #include "entry.h"
1968a945e2SMasatake YAMATO #include "kind.h"
203ae02089SMasatake YAMATO #include "parse.h"
213ae02089SMasatake YAMATO #include "read.h"
2228c711c1SMasatake YAMATO #include "promise.h"
233ae02089SMasatake YAMATO #include "routines.h"
243ae02089SMasatake YAMATO #include "vstring.h"
2568a945e2SMasatake YAMATO #include "xtag.h"
263ae02089SMasatake YAMATO 
273ae02089SMasatake YAMATO /*
283ae02089SMasatake YAMATO *   DATA DEFINITIONS
293ae02089SMasatake YAMATO */
303ae02089SMasatake YAMATO typedef enum {
316fece2a1SMasatake YAMATO 	K_NOTHING = -1,		/* place holder. Never appears on tags file. */
323ae02089SMasatake YAMATO 	K_ALIAS,
33cade7679SMasatake YAMATO 	K_FUNCTION,
34cade7679SMasatake YAMATO 	K_SOURCE,
3575cd0d29SMasatake YAMATO 	K_HEREDOCLABEL,
363ae02089SMasatake YAMATO } shKind;
373ae02089SMasatake YAMATO 
3868a945e2SMasatake YAMATO typedef enum {
3920037dfaSMasatake YAMATO 	R_SCRIPT_LOADED,
40d9be7434SMasatake YAMATO } shScriptRole;
4168a945e2SMasatake YAMATO 
4213457258SMasatake YAMATO static roleDefinition ShScriptRoles [] = {
43ce990805SThomas Braun 	{ true, "loaded", "loaded" },
4468a945e2SMasatake YAMATO };
4568a945e2SMasatake YAMATO 
4633e70ac9SMasatake YAMATO typedef enum {
4733e70ac9SMasatake YAMATO 	R_HEREDOC_ENDMARKER,
4833e70ac9SMasatake YAMATO } shHeredocRole;
4933e70ac9SMasatake YAMATO 
5013457258SMasatake YAMATO static roleDefinition ShHeredocRoles [] = {
5133e70ac9SMasatake YAMATO 	{ true, "endmarker", "end marker" },
5233e70ac9SMasatake YAMATO };
5333e70ac9SMasatake YAMATO 
54e112e8abSMasatake YAMATO static kindDefinition ShKinds [] = {
55ce990805SThomas Braun 	{ true, 'a', "alias", "aliases"},
56ce990805SThomas Braun 	{ true, 'f', "function", "functions"},
57ce990805SThomas Braun 	{ true, 's', "script", "script files",
58ce990805SThomas Braun 	  .referenceOnly = true, ATTACH_ROLES (ShScriptRoles) },
5933e70ac9SMasatake YAMATO 	{ true, 'h', "heredoc", "label for here document",
6033e70ac9SMasatake YAMATO 	  .referenceOnly = false, ATTACH_ROLES (ShHeredocRoles) },
613ae02089SMasatake YAMATO };
623ae02089SMasatake YAMATO 
633ae02089SMasatake YAMATO /*
643ae02089SMasatake YAMATO *   FUNCTION DEFINITIONS
653ae02089SMasatake YAMATO */
663ae02089SMasatake YAMATO 
isFileChar(int c)67ce990805SThomas Braun static bool isFileChar  (int c)
68cade7679SMasatake YAMATO {
69cade7679SMasatake YAMATO 	return (isalnum (c)
70cade7679SMasatake YAMATO 		|| c == '_' || c == '-'
71cade7679SMasatake YAMATO 		|| c == '/' || c == '.'
72cade7679SMasatake YAMATO 		|| c == '+' || c == '^'
73cade7679SMasatake YAMATO 		|| c == '%' || c == '@'
74cade7679SMasatake YAMATO 		|| c == '~');
75cade7679SMasatake YAMATO }
76cade7679SMasatake YAMATO 
isIdentChar(int c)77ce990805SThomas Braun static bool isIdentChar (int c)
783ae02089SMasatake YAMATO {
793ae02089SMasatake YAMATO 	return (isalnum (c) || c == '_' || c == '-');
803ae02089SMasatake YAMATO }
813ae02089SMasatake YAMATO 
82984c5277SColomban Wendling /* bash allows all kinds of crazy stuff as the identifier after 'function' */
isBashFunctionChar(int c)83ce990805SThomas Braun static bool isBashFunctionChar (int c)
84984c5277SColomban Wendling {
85984c5277SColomban Wendling 	return (c > 1 /* NUL and SOH are disallowed */ && c != 0x7f &&
86984c5277SColomban Wendling 	        /* blanks are disallowed, but VT and FF (and CR to some extent, but
87984c5277SColomban Wendling 	         * let's not fall into the pit of craziness) */
88984c5277SColomban Wendling 	        c != ' ' && c != '\t' && c != '\n' && c != '\r' &&
89984c5277SColomban Wendling 	        c != '"' && c != '\'' && c != '$' && c != '`' && c != '\\' &&
90984c5277SColomban Wendling 	        c != '&' && c != ';' &&
91984c5277SColomban Wendling 	        c != '(' && c != ')' &&
92984c5277SColomban Wendling 	        c != '<' && c != '>');
93984c5277SColomban Wendling }
94984c5277SColomban Wendling 
skipDoubleString(const unsigned char * cp)953ae02089SMasatake YAMATO static const unsigned char *skipDoubleString (const unsigned char *cp)
963ae02089SMasatake YAMATO {
973ae02089SMasatake YAMATO 	const unsigned char* prev = cp;
983ae02089SMasatake YAMATO 	cp++;
993ae02089SMasatake YAMATO 	while ((*cp != '"' || *prev == '\\') && *cp != '\0')
1003ae02089SMasatake YAMATO 	{
1013ae02089SMasatake YAMATO 		prev = cp;
1023ae02089SMasatake YAMATO 		cp++;
1033ae02089SMasatake YAMATO 	}
1043ae02089SMasatake YAMATO 	return cp;
1053ae02089SMasatake YAMATO }
1063ae02089SMasatake YAMATO 
skipSingleString(const unsigned char * cp)1073ae02089SMasatake YAMATO static const unsigned char *skipSingleString (const unsigned char *cp)
1083ae02089SMasatake YAMATO {
1093ae02089SMasatake YAMATO 	cp++;
1103ae02089SMasatake YAMATO 	while (*cp != '\'' && *cp != '\0')
1113ae02089SMasatake YAMATO 		cp++;
1123ae02089SMasatake YAMATO 	return cp;
1133ae02089SMasatake YAMATO }
1143ae02089SMasatake YAMATO 
isEnvCommand(const vString * cmd)11528c711c1SMasatake YAMATO static bool isEnvCommand (const vString *cmd)
11628c711c1SMasatake YAMATO {
11728c711c1SMasatake YAMATO 	const char *lc = vStringValue(cmd);
11828c711c1SMasatake YAMATO 	const char * tmp = baseFilename (lc);
11928c711c1SMasatake YAMATO 
12028c711c1SMasatake YAMATO 	return (strcmp(tmp, "env") == 0);
12128c711c1SMasatake YAMATO }
12228c711c1SMasatake YAMATO 
readDestfileName(const unsigned char * cp,vString * destfile)1231e8e6f84SMasatake YAMATO static int readDestfileName (const unsigned char *cp, vString *destfile)
1241e8e6f84SMasatake YAMATO {
1251e8e6f84SMasatake YAMATO 	const unsigned char *origin = cp;
1261e8e6f84SMasatake YAMATO 
1271e8e6f84SMasatake YAMATO 	while (isspace ((int) *cp))
1281e8e6f84SMasatake YAMATO 		++cp;
1291e8e6f84SMasatake YAMATO 
1301e8e6f84SMasatake YAMATO 	/* >... */
1311e8e6f84SMasatake YAMATO 	if (*cp != '>')
1321e8e6f84SMasatake YAMATO 		return 0;
1331e8e6f84SMasatake YAMATO 
1341e8e6f84SMasatake YAMATO 	/* >>... */
1351e8e6f84SMasatake YAMATO 	if (*cp == '>')
1361e8e6f84SMasatake YAMATO 		++cp;
1371e8e6f84SMasatake YAMATO 
1381e8e6f84SMasatake YAMATO 	while (isspace ((int) *cp))
1391e8e6f84SMasatake YAMATO 		++cp;
1401e8e6f84SMasatake YAMATO 
1411e8e6f84SMasatake YAMATO 	if (!isFileChar ((int) *cp))
1421e8e6f84SMasatake YAMATO 		return 0;
1431e8e6f84SMasatake YAMATO 
1441e8e6f84SMasatake YAMATO 	vStringClear(destfile);
1451e8e6f84SMasatake YAMATO 	do {
1461e8e6f84SMasatake YAMATO 		vStringPut (destfile, (int) *cp);
1471e8e6f84SMasatake YAMATO 		++cp;
1481e8e6f84SMasatake YAMATO 	} while (isFileChar ((int) *cp));
1491e8e6f84SMasatake YAMATO 
1501e8e6f84SMasatake YAMATO 	if (vStringLength(destfile) > 0)
1511e8e6f84SMasatake YAMATO 		return cp - origin;
1521e8e6f84SMasatake YAMATO 
1531e8e6f84SMasatake YAMATO 	return 0;
1541e8e6f84SMasatake YAMATO }
1551e8e6f84SMasatake YAMATO 
1562e9c0d96SMasatake YAMATO struct hereDocParsingState {
1572e9c0d96SMasatake YAMATO 	vString *args[2];
1582e9c0d96SMasatake YAMATO 	vString *destfile;
1592e9c0d96SMasatake YAMATO 	langType sublang;
1602e9c0d96SMasatake YAMATO 	unsigned long startLine;
1614ebd1ab1SMasatake YAMATO 
1624ebd1ab1SMasatake YAMATO 	int corkIndex;
1632e9c0d96SMasatake YAMATO };
1642e9c0d96SMasatake YAMATO 
hdocStateInit(struct hereDocParsingState * hstate)1652e9c0d96SMasatake YAMATO static void hdocStateInit (struct hereDocParsingState *hstate)
1662e9c0d96SMasatake YAMATO {
1672e9c0d96SMasatake YAMATO 	hstate->args[0] = vStringNew ();
1682e9c0d96SMasatake YAMATO 	hstate->args[1] = vStringNew ();
1692e9c0d96SMasatake YAMATO 	hstate->destfile = vStringNew ();
1702e9c0d96SMasatake YAMATO 
1714ebd1ab1SMasatake YAMATO 	hstate->corkIndex = CORK_NIL;
1722e9c0d96SMasatake YAMATO 	hstate->sublang = LANG_IGNORE;
1732e9c0d96SMasatake YAMATO }
1742e9c0d96SMasatake YAMATO 
hdocStateClear(struct hereDocParsingState * hstate)1752e9c0d96SMasatake YAMATO static void hdocStateClear (struct hereDocParsingState *hstate)
1762e9c0d96SMasatake YAMATO {
1772e9c0d96SMasatake YAMATO 	vStringClear (hstate->args[0]);
1782e9c0d96SMasatake YAMATO 	vStringClear (hstate->args[1]);
1792e9c0d96SMasatake YAMATO 	vStringClear (hstate->destfile);
1802e9c0d96SMasatake YAMATO }
1812e9c0d96SMasatake YAMATO 
hdocStateFini(struct hereDocParsingState * hstate)1822e9c0d96SMasatake YAMATO static void hdocStateFini (struct hereDocParsingState *hstate)
1832e9c0d96SMasatake YAMATO {
1842e9c0d96SMasatake YAMATO 	vStringDelete (hstate->args[0]);
1852e9c0d96SMasatake YAMATO 	vStringDelete (hstate->args[1]);
1862e9c0d96SMasatake YAMATO 	vStringDelete (hstate->destfile);
1872e9c0d96SMasatake YAMATO }
1882e9c0d96SMasatake YAMATO 
hdocStateUpdateArgs(struct hereDocParsingState * hstate,vString * name)1892e9c0d96SMasatake YAMATO static void hdocStateUpdateArgs (struct hereDocParsingState *hstate,
1902e9c0d96SMasatake YAMATO 										   vString *name)
1912e9c0d96SMasatake YAMATO {
1922e9c0d96SMasatake YAMATO 	if (vStringIsEmpty(hstate->args[0]))
1932e9c0d96SMasatake YAMATO 		vStringCopy(hstate->args[0], name);
1942e9c0d96SMasatake YAMATO 	else if (vStringIsEmpty(hstate->args[1]))
1952e9c0d96SMasatake YAMATO 		vStringCopy(hstate->args[1], name);
1962e9c0d96SMasatake YAMATO }
1972e9c0d96SMasatake YAMATO 
hdocStateMakePromiseMaybe(struct hereDocParsingState * hstate)1982e9c0d96SMasatake YAMATO static void hdocStateMakePromiseMaybe (struct hereDocParsingState *hstate)
1992e9c0d96SMasatake YAMATO {
2002e9c0d96SMasatake YAMATO 	if (hstate->sublang != LANG_IGNORE)
2012e9c0d96SMasatake YAMATO 		makePromise (getLanguageName(hstate->sublang),
2022e9c0d96SMasatake YAMATO 					 hstate->startLine, 0,
2032e9c0d96SMasatake YAMATO 					 getInputLineNumber(), 0,
2042e9c0d96SMasatake YAMATO 					 0);
2052e9c0d96SMasatake YAMATO 	hstate->sublang = LANG_IGNORE;
2062e9c0d96SMasatake YAMATO }
2072e9c0d96SMasatake YAMATO 
hdocStateRecordStartlineFromDestfileMaybe(struct hereDocParsingState * hstate)2082e9c0d96SMasatake YAMATO static void hdocStateRecordStartlineFromDestfileMaybe (struct hereDocParsingState *hstate)
2092e9c0d96SMasatake YAMATO {
2102e9c0d96SMasatake YAMATO 	const char *f = vStringValue(hstate->destfile);
2112e9c0d96SMasatake YAMATO 
2122e9c0d96SMasatake YAMATO 	if (hstate->sublang != LANG_IGNORE)
2132e9c0d96SMasatake YAMATO 		return;
2142e9c0d96SMasatake YAMATO 
2152e9c0d96SMasatake YAMATO 	hstate->sublang = getLanguageForFilename (f, 0);
2162e9c0d96SMasatake YAMATO 	if (hstate->sublang != LANG_IGNORE)
2172e9c0d96SMasatake YAMATO 		hstate->startLine = getInputLineNumber () + 1;
2182e9c0d96SMasatake YAMATO 	vStringClear (hstate->destfile);
2192e9c0d96SMasatake YAMATO }
2202e9c0d96SMasatake YAMATO 
hdocStateRecordStatelineMaybe(struct hereDocParsingState * hstate)2212e9c0d96SMasatake YAMATO static void hdocStateRecordStatelineMaybe (struct hereDocParsingState *hstate)
2222e9c0d96SMasatake YAMATO {
2232e9c0d96SMasatake YAMATO 	if (!vStringIsEmpty(hstate->args[0]))
2242e9c0d96SMasatake YAMATO 	{
2252e9c0d96SMasatake YAMATO 		const char *cmd;
2262e9c0d96SMasatake YAMATO 
2272e9c0d96SMasatake YAMATO 		cmd = vStringValue(hstate->args[0]);
2282e9c0d96SMasatake YAMATO 		if (isEnvCommand (hstate->args[0]))
2292e9c0d96SMasatake YAMATO 		{
2302e9c0d96SMasatake YAMATO 			cmd = NULL;
2312e9c0d96SMasatake YAMATO 			if (!vStringIsEmpty(hstate->args[1]))
2322e9c0d96SMasatake YAMATO 				cmd = vStringValue(hstate->args[1]);
2332e9c0d96SMasatake YAMATO 		}
2342e9c0d96SMasatake YAMATO 
235141b1920SMasatake YAMATO 		if (cmd)
236141b1920SMasatake YAMATO 		{
2372e9c0d96SMasatake YAMATO 			hstate->sublang = getLanguageForCommand (cmd, 0);
2382e9c0d96SMasatake YAMATO 			if (hstate->sublang != LANG_IGNORE)
2392e9c0d96SMasatake YAMATO 				hstate->startLine = getInputLineNumber () + 1;
2402e9c0d96SMasatake YAMATO 		}
241141b1920SMasatake YAMATO 	}
2422e9c0d96SMasatake YAMATO 
2432e9c0d96SMasatake YAMATO 	if (vStringLength(hstate->destfile) > 0)
2442e9c0d96SMasatake YAMATO 		hdocStateRecordStartlineFromDestfileMaybe (hstate);
2452e9c0d96SMasatake YAMATO }
2462e9c0d96SMasatake YAMATO 
hdocStateReadDestfileName(struct hereDocParsingState * hstate,const unsigned char * cp,const vString * const hereDocDelimiter)2472e9c0d96SMasatake YAMATO static int hdocStateReadDestfileName (struct hereDocParsingState *hstate,
2482e9c0d96SMasatake YAMATO 									  const unsigned char* cp,
2492e9c0d96SMasatake YAMATO 									  const vString *const hereDocDelimiter)
2502e9c0d96SMasatake YAMATO {
2512e9c0d96SMasatake YAMATO 	int d = readDestfileName (cp, hstate->destfile);
2522e9c0d96SMasatake YAMATO 
2532e9c0d96SMasatake YAMATO 	if (d > 0 && hereDocDelimiter)
2542e9c0d96SMasatake YAMATO 		hdocStateRecordStartlineFromDestfileMaybe (hstate);
2552e9c0d96SMasatake YAMATO 
2562e9c0d96SMasatake YAMATO 	return d;
2572e9c0d96SMasatake YAMATO }
2582e9c0d96SMasatake YAMATO 
hdocStateUpdateTag(struct hereDocParsingState * hstate,unsigned long endLine)2594ebd1ab1SMasatake YAMATO static void hdocStateUpdateTag (struct hereDocParsingState *hstate, unsigned long endLine)
2604ebd1ab1SMasatake YAMATO {
2614ebd1ab1SMasatake YAMATO 	tagEntryInfo *tag = getEntryInCorkQueue (hstate->corkIndex);
262*3671ad72SMasatake YAMATO 	if (tag)
263*3671ad72SMasatake YAMATO 	{
2644ebd1ab1SMasatake YAMATO 		tag->extensionFields.endLine = endLine;
2654ebd1ab1SMasatake YAMATO 		hstate->corkIndex = CORK_NIL;
2664ebd1ab1SMasatake YAMATO 	}
2674ebd1ab1SMasatake YAMATO }
2684ebd1ab1SMasatake YAMATO 
findShTags(void)2693ae02089SMasatake YAMATO static void findShTags (void)
2703ae02089SMasatake YAMATO {
2713ae02089SMasatake YAMATO 	vString *name = vStringNew ();
2723ae02089SMasatake YAMATO 	const unsigned char *line;
2733ae02089SMasatake YAMATO 	vString *hereDocDelimiter = NULL;
274ce990805SThomas Braun 	bool hereDocIndented = false;
275ce990805SThomas Braun 	bool (* check_char)(int);
2763ae02089SMasatake YAMATO 
2772e9c0d96SMasatake YAMATO 	struct hereDocParsingState hstate;
2782e9c0d96SMasatake YAMATO 	hdocStateInit (&hstate);
27928c711c1SMasatake YAMATO 
2801b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
2813ae02089SMasatake YAMATO 	{
2823ae02089SMasatake YAMATO 		const unsigned char* cp = line;
2836fece2a1SMasatake YAMATO 		shKind found_kind = K_NOTHING;
2843ae02089SMasatake YAMATO 
2853ae02089SMasatake YAMATO 		if (hereDocDelimiter)
2863ae02089SMasatake YAMATO 		{
2873ae02089SMasatake YAMATO 			if (hereDocIndented)
2883ae02089SMasatake YAMATO 			{
2893ae02089SMasatake YAMATO 				while (*cp == '\t')
2903ae02089SMasatake YAMATO 					cp++;
2913ae02089SMasatake YAMATO 			}
2925daf04e3SMasatake YAMATO 			if ((strncmp ((const char *) cp, vStringValue (hereDocDelimiter), vStringLength (hereDocDelimiter)) == 0)
2935daf04e3SMasatake YAMATO 				&& ((*(cp + vStringLength (hereDocDelimiter)) == '\0')
2945daf04e3SMasatake YAMATO 					|| isspace (*(cp + vStringLength (hereDocDelimiter)) )))
2953ae02089SMasatake YAMATO 			{
2964ebd1ab1SMasatake YAMATO 				hdocStateUpdateTag (&hstate, getInputLineNumber ());
2972e9c0d96SMasatake YAMATO 				hdocStateMakePromiseMaybe (&hstate);
29828c711c1SMasatake YAMATO 
29933e70ac9SMasatake YAMATO 				if (!vStringIsEmpty(hereDocDelimiter))
30033e70ac9SMasatake YAMATO 					makeSimpleRefTag(hereDocDelimiter, K_HEREDOCLABEL, R_HEREDOC_ENDMARKER);
3013ae02089SMasatake YAMATO 				vStringDelete (hereDocDelimiter);
3023ae02089SMasatake YAMATO 				hereDocDelimiter = NULL;
3033ae02089SMasatake YAMATO 			}
3043ae02089SMasatake YAMATO 			continue;
3053ae02089SMasatake YAMATO 		}
3063ae02089SMasatake YAMATO 
3072e9c0d96SMasatake YAMATO 		hdocStateClear (&hstate);
3083ae02089SMasatake YAMATO 		while (*cp != '\0')
3093ae02089SMasatake YAMATO 		{
3103ae02089SMasatake YAMATO 			/* jump over whitespace */
3113ae02089SMasatake YAMATO 			while (isspace ((int)*cp))
3123ae02089SMasatake YAMATO 				cp++;
3133ae02089SMasatake YAMATO 
3143ae02089SMasatake YAMATO 			/* jump over strings */
3153ae02089SMasatake YAMATO 			if (*cp == '"')
3163ae02089SMasatake YAMATO 				cp = skipDoubleString (cp);
3173ae02089SMasatake YAMATO 			else if (*cp == '\'')
3183ae02089SMasatake YAMATO 				cp = skipSingleString (cp);
3193ae02089SMasatake YAMATO 			/* jump over comments */
3203ae02089SMasatake YAMATO 			else if (*cp == '#')
3213ae02089SMasatake YAMATO 				break;
3223ae02089SMasatake YAMATO 			/* jump over here-documents */
3233ae02089SMasatake YAMATO 			else if (cp[0] == '<' && cp[1] == '<')
3243ae02089SMasatake YAMATO 			{
3253ae02089SMasatake YAMATO 				const unsigned char *start, *end;
326ce990805SThomas Braun 				bool trimEscapeSequences = false;
327ce990805SThomas Braun 				bool quoted = false;
3283ae02089SMasatake YAMATO 				cp += 2;
3293ae02089SMasatake YAMATO 				/* an optional "-" strips leading tabulations from the heredoc lines */
3303ae02089SMasatake YAMATO 				if (*cp != '-')
331ce990805SThomas Braun 					hereDocIndented = false;
3323ae02089SMasatake YAMATO 				else
3333ae02089SMasatake YAMATO 				{
334ce990805SThomas Braun 					hereDocIndented = true;
3353ae02089SMasatake YAMATO 					cp++;
3363ae02089SMasatake YAMATO 				}
3373ae02089SMasatake YAMATO 				while (isspace (*cp))
3383ae02089SMasatake YAMATO 					cp++;
3393ae02089SMasatake YAMATO 				start = end = cp;
3403ae02089SMasatake YAMATO 				/* the delimiter can be surrounded by quotes */
3413ae02089SMasatake YAMATO 				if (*cp == '"')
3423ae02089SMasatake YAMATO 				{
3433ae02089SMasatake YAMATO 					start++;
3443ae02089SMasatake YAMATO 					end = cp = skipDoubleString (cp);
3453ae02089SMasatake YAMATO 					/* we need not to worry about variable substitution, they
3463ae02089SMasatake YAMATO 					 * don't happen in heredoc delimiter definition */
347ce990805SThomas Braun 					trimEscapeSequences = true;
348ce990805SThomas Braun 					quoted = true;
3493ae02089SMasatake YAMATO 				}
3503ae02089SMasatake YAMATO 				else if (*cp == '\'')
3513ae02089SMasatake YAMATO 				{
3523ae02089SMasatake YAMATO 					start++;
3533ae02089SMasatake YAMATO 					end = cp = skipSingleString (cp);
354ce990805SThomas Braun 					quoted = true;
3553ae02089SMasatake YAMATO 				}
3563ae02089SMasatake YAMATO 				else
3573ae02089SMasatake YAMATO 				{
3583ae02089SMasatake YAMATO 					while (isIdentChar ((int) *cp))
3593ae02089SMasatake YAMATO 						cp++;
3603ae02089SMasatake YAMATO 					end = cp;
3613ae02089SMasatake YAMATO 				}
3623ae02089SMasatake YAMATO 				if (end > start || quoted)
3633ae02089SMasatake YAMATO 				{
3643ae02089SMasatake YAMATO 					/* The input may be broken as a shell script but we need to avoid
3653ae02089SMasatake YAMATO 					   memory leaking. */
3663ae02089SMasatake YAMATO 					if (hereDocDelimiter)
3673ae02089SMasatake YAMATO 						vStringClear(hereDocDelimiter);
3683ae02089SMasatake YAMATO 					else
3693ae02089SMasatake YAMATO 						hereDocDelimiter = vStringNew ();
3703ae02089SMasatake YAMATO 					for (; end > start; start++)
3713ae02089SMasatake YAMATO 					{
3723ae02089SMasatake YAMATO 						if (trimEscapeSequences && *start == '\\')
3733ae02089SMasatake YAMATO 							start++;
3743ae02089SMasatake YAMATO 						vStringPut (hereDocDelimiter, *start);
3753ae02089SMasatake YAMATO 					}
37675cd0d29SMasatake YAMATO 					if (vStringLength(hereDocDelimiter) > 0)
3774ebd1ab1SMasatake YAMATO 						hstate.corkIndex = makeSimpleTag(hereDocDelimiter, K_HEREDOCLABEL);
37828c711c1SMasatake YAMATO 
3792e9c0d96SMasatake YAMATO 					hdocStateRecordStatelineMaybe(&hstate);
3803ae02089SMasatake YAMATO 				}
3813ae02089SMasatake YAMATO 			}
3823ae02089SMasatake YAMATO 
383ec5981f7SMasatake YAMATO 			check_char = isBashFunctionChar;
384984c5277SColomban Wendling 
3853ae02089SMasatake YAMATO 			if (strncmp ((const char*) cp, "function", (size_t) 8) == 0  &&
3863ae02089SMasatake YAMATO 				isspace ((int) cp [8]))
3873ae02089SMasatake YAMATO 			{
3886fece2a1SMasatake YAMATO 				found_kind = K_FUNCTION;
3893ae02089SMasatake YAMATO 				cp += 8;
3903ae02089SMasatake YAMATO 			}
3913ae02089SMasatake YAMATO 			else if (strncmp ((const char*) cp, "alias", (size_t) 5) == 0  &&
3923ae02089SMasatake YAMATO 				isspace ((int) cp [5]))
3933ae02089SMasatake YAMATO 			{
394ec5981f7SMasatake YAMATO 				check_char = isIdentChar;
3956fece2a1SMasatake YAMATO 				found_kind = K_ALIAS;
3963ae02089SMasatake YAMATO 				cp += 5;
3973ae02089SMasatake YAMATO 			}
3981c6b351dSMasatake YAMATO 			else if (cp [0] == '.'
399cade7679SMasatake YAMATO 				    && isspace((int) cp [1]))
400cade7679SMasatake YAMATO 			{
401cade7679SMasatake YAMATO 				found_kind = K_SOURCE;
402cade7679SMasatake YAMATO 				++cp;
4031c6b351dSMasatake YAMATO 				check_char = isFileChar;
404cade7679SMasatake YAMATO 			}
405cade7679SMasatake YAMATO 			else if (strncmp ((const char*) cp, "source", (size_t) 6) == 0
406cade7679SMasatake YAMATO 					 && isspace((int) cp [6]))
407cade7679SMasatake YAMATO 			{
408cade7679SMasatake YAMATO 				found_kind = K_SOURCE;
409cade7679SMasatake YAMATO 				cp += 6;
410984c5277SColomban Wendling 				check_char = isFileChar;
41168a945e2SMasatake YAMATO 			}
4121c6b351dSMasatake YAMATO 
41304a13492SMasatake YAMATO 			if (found_kind != K_NOTHING)
414cade7679SMasatake YAMATO 				while (isspace ((int) *cp))
415cade7679SMasatake YAMATO 					++cp;
416cade7679SMasatake YAMATO 
417cade7679SMasatake YAMATO 			// Get the name of the function, alias or file to be read by source
418cade7679SMasatake YAMATO 			if (! check_char ((int) *cp))
4193ae02089SMasatake YAMATO 			{
4206fece2a1SMasatake YAMATO 				found_kind = K_NOTHING;
4211e8e6f84SMasatake YAMATO 
4222e9c0d96SMasatake YAMATO 				int d = hdocStateReadDestfileName (&hstate, cp,
4232e9c0d96SMasatake YAMATO 												   hereDocDelimiter);
4242b265048SMasatake YAMATO 				if (d > 0)
4252b265048SMasatake YAMATO 					cp += d;
4262b265048SMasatake YAMATO 				else if (*cp != '\0')
4273ae02089SMasatake YAMATO 					++cp;
4283ae02089SMasatake YAMATO 				continue;
4293ae02089SMasatake YAMATO 			}
430cade7679SMasatake YAMATO 			while (check_char ((int) *cp))
4313ae02089SMasatake YAMATO 			{
4323ae02089SMasatake YAMATO 				vStringPut (name, (int) *cp);
4333ae02089SMasatake YAMATO 				++cp;
4343ae02089SMasatake YAMATO 			}
4353ae02089SMasatake YAMATO 
4363ae02089SMasatake YAMATO 			while (isspace ((int) *cp))
4373ae02089SMasatake YAMATO 				++cp;
438cade7679SMasatake YAMATO 
439cade7679SMasatake YAMATO 			if ((found_kind != K_SOURCE)
440cade7679SMasatake YAMATO 			    && *cp == '(')
4413ae02089SMasatake YAMATO 			{
4423ae02089SMasatake YAMATO 				++cp;
4433ae02089SMasatake YAMATO 				while (isspace ((int) *cp))
4443ae02089SMasatake YAMATO 					++cp;
4453ae02089SMasatake YAMATO 				if (*cp == ')')
4463ae02089SMasatake YAMATO 				{
4476fece2a1SMasatake YAMATO 					found_kind = K_FUNCTION;
4483ae02089SMasatake YAMATO 					++cp;
4493ae02089SMasatake YAMATO 				}
4503ae02089SMasatake YAMATO 			}
45168a945e2SMasatake YAMATO 
4526fece2a1SMasatake YAMATO 			if (found_kind != K_NOTHING)
4533ae02089SMasatake YAMATO 			{
45468a945e2SMasatake YAMATO 				if (found_kind == K_SOURCE)
45520037dfaSMasatake YAMATO 						makeSimpleRefTag (name, K_SOURCE, R_SCRIPT_LOADED);
45668a945e2SMasatake YAMATO 				else
45716a2541cSMasatake YAMATO 					makeSimpleTag (name, found_kind);
4586fece2a1SMasatake YAMATO 				found_kind = K_NOTHING;
4593ae02089SMasatake YAMATO 			}
46028c711c1SMasatake YAMATO 			else if (!hereDocDelimiter)
4612e9c0d96SMasatake YAMATO 				hdocStateUpdateArgs (&hstate, name);
4623ae02089SMasatake YAMATO 			vStringClear (name);
4633ae02089SMasatake YAMATO 		}
4643ae02089SMasatake YAMATO 	}
4652e9c0d96SMasatake YAMATO 	hdocStateFini (&hstate);
4663ae02089SMasatake YAMATO 	vStringDelete (name);
4673ae02089SMasatake YAMATO 	if (hereDocDelimiter)
4683ae02089SMasatake YAMATO 		vStringDelete (hereDocDelimiter);
4693ae02089SMasatake YAMATO }
4703ae02089SMasatake YAMATO 
ShParser(void)4713ae02089SMasatake YAMATO extern parserDefinition* ShParser (void)
4723ae02089SMasatake YAMATO {
4733ae02089SMasatake YAMATO 	static const char *const extensions [] = {
4743ae02089SMasatake YAMATO 		"sh", "SH", "bsh", "bash", "ksh", "zsh", "ash", NULL
4753ae02089SMasatake YAMATO 	};
4763ae02089SMasatake YAMATO 	static const char *const aliases [] = {
4773ae02089SMasatake YAMATO 		"sh", "bash", "ksh", "zsh", "ash",
4783ae02089SMasatake YAMATO 		/* major mode name in emacs */
4793ae02089SMasatake YAMATO 		"shell-script",
4803ae02089SMasatake YAMATO 		NULL
4813ae02089SMasatake YAMATO 	};
4823ae02089SMasatake YAMATO 	parserDefinition* def = parserNew ("Sh");
48309ae690fSMasatake YAMATO 	def->kindTable      = ShKinds;
4843db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (ShKinds);
4853ae02089SMasatake YAMATO 	def->extensions = extensions;
4863ae02089SMasatake YAMATO 	def->aliases = aliases;
4873ae02089SMasatake YAMATO 	def->parser     = findShTags;
4886b1a862eSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
4893ae02089SMasatake YAMATO 	return def;
4903ae02089SMasatake YAMATO }
491