xref: /Universal-ctags/parsers/diff.c (revision 3671ad7255885a0c8f6ff4979d80c70f201ea411)
1d173714eSMasatake YAMATO /*
2d173714eSMasatake YAMATO *
3d173714eSMasatake YAMATO *   Copyright (c) 2000-2001, Darren Hiebert
4d173714eSMasatake YAMATO *
5d173714eSMasatake YAMATO *   This source code is released for free distribution under the terms of the
60ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
7d173714eSMasatake YAMATO *
8d173714eSMasatake YAMATO *   This module contains functions for generating tags for diff files (based on Sh parser).
9d173714eSMasatake YAMATO */
10d173714eSMasatake YAMATO 
11d173714eSMasatake YAMATO /*
12d173714eSMasatake YAMATO *   INCLUDE FILES
13d173714eSMasatake YAMATO */
14d173714eSMasatake YAMATO #include "general.h"	/* must always come first */
15d173714eSMasatake YAMATO 
16d173714eSMasatake YAMATO #include <ctype.h>
17d173714eSMasatake YAMATO #include <string.h>
18d173714eSMasatake YAMATO 
197049fd45SMasatake YAMATO #include "entry.h"
20d173714eSMasatake YAMATO #include "parse.h"
213db72c21SMasatake YAMATO #include "routines.h"
22d173714eSMasatake YAMATO #include "read.h"
23d173714eSMasatake YAMATO #include "vstring.h"
24d173714eSMasatake YAMATO 
25d173714eSMasatake YAMATO /*
26d173714eSMasatake YAMATO *   DATA DEFINITIONS
27d173714eSMasatake YAMATO */
28d173714eSMasatake YAMATO typedef enum {
29d173714eSMasatake YAMATO 	K_MODIFIED_FILE,
30d173714eSMasatake YAMATO 	K_NEW_FILE,
317049fd45SMasatake YAMATO 	K_DELETED_FILE,
32d173714eSMasatake YAMATO 	K_HUNK,
33d173714eSMasatake YAMATO } diffKind;
34d173714eSMasatake YAMATO 
35e112e8abSMasatake YAMATO static kindDefinition DiffKinds [] = {
36ce990805SThomas Braun 	{ true, 'm', "modifiedFile",  "modified files"},
37ce990805SThomas Braun 	{ true, 'n', "newFile",       "newly created files"},
38ce990805SThomas Braun 	{ true, 'd', "deletedFile",   "deleted files"},
39ce990805SThomas Braun 	{ true, 'h', "hunk",          "hunks"},
40d173714eSMasatake YAMATO };
41d173714eSMasatake YAMATO 
42d173714eSMasatake YAMATO enum {
43d173714eSMasatake YAMATO 	DIFF_DELIM_MINUS = 0,
44d173714eSMasatake YAMATO 	DIFF_DELIM_PLUS
45d173714eSMasatake YAMATO };
46d173714eSMasatake YAMATO 
47d173714eSMasatake YAMATO static const char *DiffDelims[2] = {
48d173714eSMasatake YAMATO 	"--- ",
49d173714eSMasatake YAMATO 	"+++ "
50d173714eSMasatake YAMATO };
51d173714eSMasatake YAMATO 
527049fd45SMasatake YAMATO static const char *HunkDelim[2] = {
537049fd45SMasatake YAMATO 	"@@ ",
547049fd45SMasatake YAMATO 	" @@",
557049fd45SMasatake YAMATO };
567049fd45SMasatake YAMATO 
57d173714eSMasatake YAMATO /*
58d173714eSMasatake YAMATO *   FUNCTION DEFINITIONS
59d173714eSMasatake YAMATO */
60d173714eSMasatake YAMATO 
stripAbsolute(const unsigned char * filename)61d173714eSMasatake YAMATO static const unsigned char *stripAbsolute (const unsigned char *filename)
62d173714eSMasatake YAMATO {
63d173714eSMasatake YAMATO 	const unsigned char *tmp;
64d173714eSMasatake YAMATO 
65d173714eSMasatake YAMATO 	/* strip any absolute path */
66d173714eSMasatake YAMATO 	if (*filename == '/' || *filename == '\\')
67d173714eSMasatake YAMATO 	{
68ce990805SThomas Braun 		bool skipSlash = true;
69d173714eSMasatake YAMATO 
70d173714eSMasatake YAMATO 		tmp = (const unsigned char*) strrchr ((const char*) filename,  '/');
71d173714eSMasatake YAMATO 		if (tmp == NULL)
72d173714eSMasatake YAMATO 		{	/* if no / is contained try \ in case of a Windows filename */
73d173714eSMasatake YAMATO 			tmp = (const unsigned char*) strrchr ((const char*) filename, '\\');
74d173714eSMasatake YAMATO 			if (tmp == NULL)
75d173714eSMasatake YAMATO 			{	/* last fallback, probably the filename doesn't contain a path, so take it */
76d173714eSMasatake YAMATO 				tmp = filename;
77ce990805SThomas Braun 				skipSlash = false;
78d173714eSMasatake YAMATO 			}
79d173714eSMasatake YAMATO 		}
80d173714eSMasatake YAMATO 
81d173714eSMasatake YAMATO 		/* skip the leading slash or backslash */
82d173714eSMasatake YAMATO 		if (skipSlash)
83d173714eSMasatake YAMATO 			tmp++;
84d173714eSMasatake YAMATO 	}
85d173714eSMasatake YAMATO 	else
86d173714eSMasatake YAMATO 		tmp = filename;
87d173714eSMasatake YAMATO 
88d173714eSMasatake YAMATO 	return tmp;
89d173714eSMasatake YAMATO }
90d173714eSMasatake YAMATO 
parseHunk(const unsigned char * cp,vString * hunk,int scope_index)917049fd45SMasatake YAMATO static int parseHunk (const unsigned char* cp, vString *hunk, int scope_index)
927049fd45SMasatake YAMATO {
937049fd45SMasatake YAMATO 	/*
947049fd45SMasatake YAMATO 	   example input: @@ -0,0 +1,134 @@
957049fd45SMasatake YAMATO 	   expected output: -0,0 +1,134
967049fd45SMasatake YAMATO 	*/
977049fd45SMasatake YAMATO 
987049fd45SMasatake YAMATO 	const char *next_delim;
997049fd45SMasatake YAMATO 	const char *start, *end;
1007049fd45SMasatake YAMATO 	const char *c;
101f6027918SMasatake YAMATO 	int i = CORK_NIL;
1027049fd45SMasatake YAMATO 
1037049fd45SMasatake YAMATO 	cp += 3;
1047049fd45SMasatake YAMATO 	start = (const char*)cp;
1057049fd45SMasatake YAMATO 
1067049fd45SMasatake YAMATO 	if (*start != '-')
1077049fd45SMasatake YAMATO 		return i;
1087049fd45SMasatake YAMATO 
1097049fd45SMasatake YAMATO 	next_delim = strstr ((const char*)cp, HunkDelim[1]);
1107049fd45SMasatake YAMATO 	if ((next_delim == NULL)
1117049fd45SMasatake YAMATO 	    || (! (start < next_delim )))
1127049fd45SMasatake YAMATO 		return i;
1137049fd45SMasatake YAMATO 	end = next_delim;
1147049fd45SMasatake YAMATO 	if (! ( '0' <= *( end - 1 ) && *( end - 1 ) <= '9'))
1157049fd45SMasatake YAMATO 		return i;
1167049fd45SMasatake YAMATO 	for (c = start; c < end; c++)
1177049fd45SMasatake YAMATO 		if (*c == '\t')
1187049fd45SMasatake YAMATO 			return i;
1197049fd45SMasatake YAMATO 	vStringNCopyS (hunk, start, end - start);
12016a2541cSMasatake YAMATO 	i = makeSimpleTag (hunk, K_HUNK);
1217049fd45SMasatake YAMATO 	tagEntryInfo *e =  getEntryInCorkQueue (i);
122*3671ad72SMasatake YAMATO 	if (e && scope_index > CORK_NIL)
1237049fd45SMasatake YAMATO 		e->extensionFields.scopeIndex = scope_index;
1247049fd45SMasatake YAMATO 	return i;
1257049fd45SMasatake YAMATO }
1267049fd45SMasatake YAMATO 
markTheLastTagAsDeletedFile(int scope_index)1277049fd45SMasatake YAMATO static void markTheLastTagAsDeletedFile (int scope_index)
1287049fd45SMasatake YAMATO {
1297049fd45SMasatake YAMATO 	tagEntryInfo *e =  getEntryInCorkQueue (scope_index);
130*3671ad72SMasatake YAMATO 
131*3671ad72SMasatake YAMATO 	if (e)
132f92e6bf2SMasatake YAMATO 		e->kindIndex = K_DELETED_FILE;
1337049fd45SMasatake YAMATO }
1347049fd45SMasatake YAMATO 
findDiffTags(void)135d173714eSMasatake YAMATO static void findDiffTags (void)
136d173714eSMasatake YAMATO {
137d173714eSMasatake YAMATO 	vString *filename = vStringNew ();
1387049fd45SMasatake YAMATO 	vString *hunk = vStringNew ();
139d173714eSMasatake YAMATO 	const unsigned char *line, *tmp;
140d173714eSMasatake YAMATO 	int delim = DIFF_DELIM_MINUS;
1412c584527SMasatake YAMATO 	diffKind kind;
142f6027918SMasatake YAMATO 	int scope_index = CORK_NIL;
143d173714eSMasatake YAMATO 
1441b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
145d173714eSMasatake YAMATO 	{
146d173714eSMasatake YAMATO 		const unsigned char* cp = line;
147d173714eSMasatake YAMATO 
148d173714eSMasatake YAMATO 		if (strncmp ((const char*) cp, DiffDelims[delim], 4u) == 0)
149d173714eSMasatake YAMATO 		{
150f6027918SMasatake YAMATO 			scope_index = CORK_NIL;
151d173714eSMasatake YAMATO 			cp += 4;
152d173714eSMasatake YAMATO 			if (isspace ((int) *cp)) continue;
153d173714eSMasatake YAMATO 			/* when original filename is /dev/null use the new one instead */
154d173714eSMasatake YAMATO 			if (delim == DIFF_DELIM_MINUS &&
155d173714eSMasatake YAMATO 				strncmp ((const char*) cp, "/dev/null", 9u) == 0 &&
156d173714eSMasatake YAMATO 				(cp[9] == 0 || isspace (cp[9])))
157d173714eSMasatake YAMATO 			{
158d173714eSMasatake YAMATO 				delim = DIFF_DELIM_PLUS;
159d173714eSMasatake YAMATO 				continue;
160d173714eSMasatake YAMATO 			}
161d173714eSMasatake YAMATO 
162d173714eSMasatake YAMATO 			tmp = stripAbsolute (cp);
163d173714eSMasatake YAMATO 
164d173714eSMasatake YAMATO 			if (tmp != NULL)
165d173714eSMasatake YAMATO 			{
166d173714eSMasatake YAMATO 				while (! isspace(*tmp) && *tmp != '\0')
167d173714eSMasatake YAMATO 				{
168d173714eSMasatake YAMATO 					vStringPut(filename, *tmp);
169d173714eSMasatake YAMATO 					tmp++;
170d173714eSMasatake YAMATO 				}
171d173714eSMasatake YAMATO 
1722c584527SMasatake YAMATO 				if (delim == DIFF_DELIM_PLUS)
1732c584527SMasatake YAMATO 					kind = K_NEW_FILE;
1742c584527SMasatake YAMATO 				else
1752c584527SMasatake YAMATO 					kind = K_MODIFIED_FILE;
17616a2541cSMasatake YAMATO 				scope_index = makeSimpleTag (filename, kind);
177d173714eSMasatake YAMATO 				vStringClear (filename);
178d173714eSMasatake YAMATO 			}
179d173714eSMasatake YAMATO 
180d173714eSMasatake YAMATO 			/* restore default delim */
181d173714eSMasatake YAMATO 			delim = DIFF_DELIM_MINUS;
182d173714eSMasatake YAMATO 		}
183f6027918SMasatake YAMATO 		else if ((scope_index > CORK_NIL)
1847049fd45SMasatake YAMATO 			 && (strncmp ((const char*) cp, DiffDelims[1], 4u) == 0))
1857049fd45SMasatake YAMATO 		{
1867049fd45SMasatake YAMATO 			cp += 4;
1877049fd45SMasatake YAMATO 			if (isspace ((int) *cp)) continue;
1887049fd45SMasatake YAMATO 			/* when modified filename is /dev/null, the original name is deleted. */
1897049fd45SMasatake YAMATO 			if (strncmp ((const char*) cp, "/dev/null", 9u) == 0 &&
1907049fd45SMasatake YAMATO 			    (cp[9] == 0 || isspace (cp[9])))
1917049fd45SMasatake YAMATO 				markTheLastTagAsDeletedFile (scope_index);
192d173714eSMasatake YAMATO 		}
1937049fd45SMasatake YAMATO 		else if (strncmp ((const char*) cp, HunkDelim[0], 3u) == 0)
1947049fd45SMasatake YAMATO 		{
195f6027918SMasatake YAMATO 			if (parseHunk (cp, hunk, scope_index) != CORK_NIL)
1967049fd45SMasatake YAMATO 				vStringClear (hunk);
1977049fd45SMasatake YAMATO 		}
1987049fd45SMasatake YAMATO 	}
1997049fd45SMasatake YAMATO 	vStringDelete (hunk);
200d173714eSMasatake YAMATO 	vStringDelete (filename);
201d173714eSMasatake YAMATO }
202d173714eSMasatake YAMATO 
DiffParser(void)203d173714eSMasatake YAMATO extern parserDefinition* DiffParser (void)
204d173714eSMasatake YAMATO {
205d173714eSMasatake YAMATO 	static const char *const extensions [] = { "diff", "patch", NULL };
206d173714eSMasatake YAMATO 	parserDefinition* const def = parserNew ("Diff");
20709ae690fSMasatake YAMATO 	def->kindTable      = DiffKinds;
2083db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (DiffKinds);
209d173714eSMasatake YAMATO 	def->extensions = extensions;
210d173714eSMasatake YAMATO 	def->parser     = findDiffTags;
2116b1a862eSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
212d173714eSMasatake YAMATO 	return def;
213d173714eSMasatake YAMATO }
214