1 /*
2 *   $Id: php.c 734 2009-08-20 23:33:54Z jafl $
3 *
4 *   Copyright (c) 2000, Jesus Castagnetto <jmcastagnetto@zkey.com>
5 *
6 *   This source code is released for free distribution under the terms of the
7 *   GNU General Public License.
8 *
9 *   This module contains functions for generating tags for the PHP web page
10 *   scripting language. Only recognizes functions and classes, not methods or
11 *   variables.
12 *
13 *   Parsing PHP defines by Pavel Hlousek <pavel.hlousek@seznam.cz>, Apr 2003.
14 */
15 
16 /*
17 *   INCLUDE FILES
18 */
19 #include "general.h"  /* must always come first */
20 
21 #include <string.h>
22 
23 #include "parse.h"
24 #include "read.h"
25 #include "vstring.h"
26 
27 /*
28 *   DATA DEFINITIONS
29 */
30 typedef enum {
31 	K_CLASS, K_DEFINE, K_FUNCTION, K_VARIABLE
32 } phpKind;
33 
34 #if 0
35 static kindOption PhpKinds [] = {
36 	{ TRUE, 'c', "class",    "classes" },
37 	{ TRUE, 'd', "define",   "constant definitions" },
38 	{ TRUE, 'f', "function", "functions" },
39 	{ TRUE, 'v', "variable", "variables" }
40 };
41 #endif
42 
43 /*
44 *   FUNCTION DEFINITIONS
45 */
46 
47 /* JavaScript patterns are duplicated in jscript.c */
48 
49 /*
50  * Cygwin doesn't support non-ASCII characters in character classes.
51  * This isn't a good solution to the underlying problem, because we're still
52  * making assumptions about the character encoding.
53  * Really, these regular expressions need to concentrate on what marks the
54  * end of an identifier, and we need something like iconv to take into
55  * account the user's locale (or an override on the command-line.)
56  */
57 #ifdef __CYGWIN__
58 #define ALPHA "[:alpha:]"
59 #define ALNUM "[:alnum:]"
60 #else
61 #define ALPHA "A-Za-z\x7f-\xff"
62 #define ALNUM "0-9A-Za-z\x7f-\xff"
63 #endif
64 
installPHPRegex(const langType language)65 static void installPHPRegex (const langType language)
66 {
67 	addTagRegex(language, "^[ \t]*((final|abstract)[ \t]+)*class[ \t]+([" ALPHA "_][" ALNUM "_]*)",
68 		"\\3", "c,class,classes", NULL);
69 	addTagRegex(language, "^[ \t]*interface[ \t]+([" ALPHA "_][" ALNUM "_]*)",
70 		"\\1", "i,interface,interfaces", NULL);
71 	addTagRegex(language, "^[ \t]*define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)",
72 		"\\1", "d,define,constant definitions", NULL);
73 	addTagRegex(language, "^[ \t]*((static|public|protected|private)[ \t]+)*function[ \t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)",
74 		"\\3", "f,function,functions", NULL);
75 	addTagRegex(language, "^[ \t]*(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=",
76 		"\\2", "v,variable,variables", NULL);
77 	addTagRegex(language, "^[ \t]*((var|public|protected|private|static)[ \t]+)+\\$([" ALPHA "_][" ALNUM "_]*)[ \t]*[=;]",
78 		"\\3", "v,variable,variables", NULL);
79 
80 	/* function regex is covered by PHP regex */
81 	addTagRegex (language, "(^|[ \t])([A-Za-z0-9_]+)[ \t]*[=:][ \t]*function[ \t]*\\(",
82 		"\\2", "j,jsfunction,javascript functions", NULL);
83 	addTagRegex (language, "(^|[ \t])([A-Za-z0-9_.]+)\\.([A-Za-z0-9_]+)[ \t]*=[ \t]*function[ \t]*\\(",
84 		"\\2.\\3", "j,jsfunction,javascript functions", NULL);
85 	addTagRegex (language, "(^|[ \t])([A-Za-z0-9_.]+)\\.([A-Za-z0-9_]+)[ \t]*=[ \t]*function[ \t]*\\(",
86 		"\\3", "j,jsfunction,javascript functions", NULL);
87 }
88 
89 /* Create parser definition structure */
PhpParser(void)90 extern parserDefinition* PhpParser (void)
91 {
92 	static const char *const extensions [] = { "php", "php3", "phtml", NULL };
93 	parserDefinition* def = parserNew ("PHP");
94 	def->extensions = extensions;
95 	def->initialize = installPHPRegex;
96 	def->regex      = TRUE;
97 	return def;
98 }
99 
100 #if 0
101 
102 static boolean isLetter(const int c)
103 {
104 	return (boolean)(isalpha(c) || (c >= 127  &&  c <= 255));
105 }
106 
107 static boolean isVarChar1(const int c)
108 {
109 	return (boolean)(isLetter (c)  ||  c == '_');
110 }
111 
112 static boolean isVarChar(const int c)
113 {
114 	return (boolean)(isVarChar1 (c) || isdigit (c));
115 }
116 
117 static void findPhpTags (void)
118 {
119 	vString *name = vStringNew ();
120 	const unsigned char *line;
121 
122 	while ((line = fileReadLine ()) != NULL)
123 	{
124 		const unsigned char *cp = line;
125 		const char* f;
126 
127 		while (isspace (*cp))
128 			cp++;
129 
130 		if (*(const char*)cp == '$'  &&  isVarChar1 (*(const char*)(cp+1)))
131 		{
132 			cp += 1;
133 			vStringClear (name);
134 			while (isVarChar ((int) *cp))
135 			{
136 				vStringPut (name, (int) *cp);
137 				++cp;
138 			}
139 			while (isspace ((int) *cp))
140 				++cp;
141 			if (*(const char*) cp == '=')
142 			{
143 				vStringTerminate (name);
144 				makeSimpleTag (name, PhpKinds, K_VARIABLE);
145 				vStringClear (name);
146 			}
147 		}
148 		else if ((f = strstr ((const char*) cp, "function")) != NULL &&
149 			(f == (const char*) cp || isspace ((int) f [-1])) &&
150 			isspace ((int) f [8]))
151 		{
152 			cp = ((const unsigned char *) f) + 8;
153 
154 			while (isspace ((int) *cp))
155 				++cp;
156 
157 			if (*cp == '&')	/* skip reference character and following whitespace */
158 			{
159 				cp++;
160 
161 				while (isspace ((int) *cp))
162 					++cp;
163 			}
164 
165 			vStringClear (name);
166 			while (isalnum ((int) *cp)  ||  *cp == '_')
167 			{
168 				vStringPut (name, (int) *cp);
169 				++cp;
170 			}
171 			vStringTerminate (name);
172 			makeSimpleTag (name, PhpKinds, K_FUNCTION);
173 			vStringClear (name);
174 		}
175 		else if (strncmp ((const char*) cp, "class", (size_t) 5) == 0 &&
176 				 isspace ((int) cp [5]))
177 		{
178 			cp += 5;
179 
180 			while (isspace ((int) *cp))
181 				++cp;
182 			vStringClear (name);
183 			while (isalnum ((int) *cp)  ||  *cp == '_')
184 			{
185 				vStringPut (name, (int) *cp);
186 				++cp;
187 			}
188 			vStringTerminate (name);
189 			makeSimpleTag (name, PhpKinds, K_CLASS);
190 			vStringClear (name);
191 		}
192 		else if (strncmp ((const char*) cp, "define", (size_t) 6) == 0 &&
193 				 ! isalnum ((int) cp [6]))
194 		{
195 			cp += 6;
196 
197 			while (isspace ((int) *cp))
198 				++cp;
199 			if (*cp != '(')
200 				continue;
201 			++cp;
202 
203 			while (isspace ((int) *cp))
204 				++cp;
205 			if ((*cp == '\'') || (*cp == '"'))
206 				++cp;
207 			else if (! ((*cp == '_')  || isalnum ((int) *cp)))
208 				continue;
209 
210 			vStringClear (name);
211 			while (isalnum ((int) *cp)  ||  *cp == '_')
212 			{
213 				vStringPut (name, (int) *cp);
214 				++cp;
215 			}
216 			vStringTerminate (name);
217 			makeSimpleTag (name, PhpKinds, K_DEFINE);
218 			vStringClear (name);
219 		}
220 	}
221 	vStringDelete (name);
222 }
223 
224 extern parserDefinition* PhpParser (void)
225 {
226 	static const char *const extensions [] = { "php", "php3", "phtml", NULL };
227 	parserDefinition* def = parserNew ("PHP");
228 	def->kinds      = PhpKinds;
229 	def->kindCount  = KIND_COUNT (PhpKinds);
230 	def->extensions = extensions;
231 	def->parser     = findPhpTags;
232 	return def;
233 }
234 
235 #endif
236 
237 /* vi:set tabstop=4 shiftwidth=4: */
238