C# patch Daniel Tang.
[external/ragel.git] / common / common.cpp
1 /*
2  *  Copyright 2006-2007 Adrian Thurston <thurston@cs.queensu.ca>
3  */
4
5 /*  This file is part of Ragel.
6  *
7  *  Ragel is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  Ragel is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  * 
17  *  You should have received a copy of the GNU General Public License
18  *  along with Ragel; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
20  */
21
22 #include "pcheck.h"
23 #include "common.h"
24 #include "stdlib.h"
25 #include <string.h>
26 #include <assert.h>
27
28 HostType hostTypesC[] =
29 {
30         { "char",     0,       "char",    true,   CHAR_MIN,  CHAR_MAX,   sizeof(char) },
31         { "unsigned", "char",  "uchar",   false,  0,         UCHAR_MAX,  sizeof(unsigned char) },
32         { "short",    0,       "short",   true,   SHRT_MIN,  SHRT_MAX,   sizeof(short) },
33         { "unsigned", "short", "ushort",  false,  0,         USHRT_MAX,  sizeof(unsigned short) },
34         { "int",      0,       "int",     true,   INT_MIN,   INT_MAX,    sizeof(int) },
35         { "unsigned", "int",   "uint",    false,  0,         UINT_MAX,   sizeof(unsigned int) },
36         { "long",     0,       "long",    true,   LONG_MIN,  LONG_MAX,   sizeof(long) },
37         { "unsigned", "long",  "ulong",   false,  0,         ULONG_MAX,  sizeof(unsigned long) }
38 };
39
40 HostType hostTypesD[] =
41 {
42         { "byte",    0,  "byte",    true,   CHAR_MIN,  CHAR_MAX,    1 },
43         { "ubyte",   0,  "ubyte",   false,  0,         UCHAR_MAX,   1 },
44         { "char",    0,  "char",    false,  0,         UCHAR_MAX,   1 },
45         { "short",   0,  "short",   true,   SHRT_MIN,  SHRT_MAX,    2 },
46         { "ushort",  0,  "ushort",  false,  0,         USHRT_MAX,   2 },
47         { "wchar",   0,  "wchar",   false,  0,         USHRT_MAX,   2 },
48         { "int",     0,  "int",     true,   INT_MIN,   INT_MAX,     4 },
49         { "uint",    0,  "uint",    false,  0,         UINT_MAX,    4 },
50         { "dchar",   0,  "dchar",   false,  0,         UINT_MAX,    4 }
51 };
52
53 HostType hostTypesJava[] = 
54 {
55         { "byte",    0,  "byte",   true,   CHAR_MIN,  CHAR_MAX,    1 },
56         { "short",   0,  "short",  true,   SHRT_MIN,  SHRT_MAX,    2 },
57         { "char",    0,  "char",   false,  0,         USHRT_MAX,   2 },
58         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
59 };
60
61 /* What are the appropriate types for ruby? */
62 HostType hostTypesRuby[] = 
63 {
64         { "char",    0,  "char",   true,   CHAR_MIN,  CHAR_MAX,    1 },
65         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
66 };
67
68 HostType hostTypesCSharp[] =
69 {
70         { "sbyte",    0, "sbyte",   true,   CHAR_MIN,  CHAR_MAX,    1 },
71         { "byte",   0,   "byte",    false,  0,         UCHAR_MAX,   1 },
72         { "short",   0,  "short",   true,   SHRT_MIN,  SHRT_MAX,    2 },
73         { "ushort",  0,  "ushort",  false,  0,         USHRT_MAX,   2 },
74         { "char",    0,  "char",    false,  0,         USHRT_MAX,   2 },
75         { "int",     0,  "int",     true,   INT_MIN,   INT_MAX,     4 },
76         { "uint",    0,  "uint",    false,  0,         UINT_MAX,    4 },
77         { "long",    0,  "long",    true,   LONG_MIN,  LONG_MAX,    8 },
78         { "ulong",   0,  "ulong",   false,  0,         ULONG_MAX,   8 }
79 };
80
81 HostLang hostLangC =    { HostLang::C,    hostTypesC,    8, hostTypesC+0,    true };
82 HostLang hostLangD =    { HostLang::D,    hostTypesD,    9, hostTypesD+2,    true };
83 HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
84 HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
85 HostLang hostLangCSharp = { HostLang::CSharp, hostTypesCSharp, 9, hostTypesCSharp+4, true };
86
87 HostLang *hostLang = &hostLangC;
88
89 HostType *findAlphType( char *s1 )
90 {
91         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
92                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
93                                 hostLang->hostTypes[i].data2 == 0 )
94                 {
95                         return hostLang->hostTypes + i;
96                 }
97         }
98
99         return 0;
100 }
101
102 HostType *findAlphType( char *s1, char *s2 )
103 {
104         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
105                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
106                                 hostLang->hostTypes[i].data2 != 0 && 
107                                 strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
108                 {
109                         return hostLang->hostTypes + i;
110                 }
111         }
112
113         return 0;
114 }
115
116 HostType *findAlphTypeInternal( char *s1 )
117 {
118         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
119                 if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
120                         return hostLang->hostTypes + i;
121         }
122
123         return 0;
124 }
125
126 /* Construct a new parameter checker with for paramSpec. */
127 ParamCheck::ParamCheck( const char *paramSpec, int argc, char **argv )
128 :
129         state(noparam),
130         argOffset(0),
131         curArg(0),
132         iCurArg(1),
133         paramSpec(paramSpec), 
134         argc(argc), 
135         argv(argv)
136 {
137 }
138
139 /* Check a single option. Returns the index of the next parameter.  Sets p to
140  * the arg character if valid, 0 otherwise.  Sets parg to the parameter arg if
141  * there is one, NULL otherwise. */
142 bool ParamCheck::check()
143 {
144         bool requiresParam;
145
146         if ( iCurArg >= argc ) {            /* Off the end of the arg list. */
147                 state = noparam;
148                 return false;
149         }
150
151         if ( argOffset != 0 && *argOffset == 0 ) {
152                 /* We are at the end of an arg string. */
153                 iCurArg += 1;
154                 if ( iCurArg >= argc ) {
155                         state = noparam;
156                         return false;
157                 }
158                 argOffset = 0;
159         }
160
161         if ( argOffset == 0 ) {
162                 /* Set the current arg. */
163                 curArg = argv[iCurArg];
164
165                 /* We are at the beginning of an arg string. */
166                 if ( argv[iCurArg] == 0 ||        /* Argv[iCurArg] is null. */
167                          argv[iCurArg][0] != '-' ||   /* Not a param. */
168                          argv[iCurArg][1] == 0 ) {    /* Only a dash. */
169                         parameter = 0;
170                         parameterArg = 0;
171
172                         iCurArg += 1;
173                         state = noparam;
174                         return true;
175                 }
176                 argOffset = argv[iCurArg] + 1;
177         }
178
179         /* Get the arg char. */
180         char argChar = *argOffset;
181         
182         /* Loop over all the parms and look for a match. */
183         const char *pSpec = paramSpec;
184         while ( *pSpec != 0 ) {
185                 char pSpecChar = *pSpec;
186
187                 /* If there is a ':' following the char then
188                  * it requires a parm.  If a parm is required
189                  * then move ahead two in the parmspec. Otherwise
190                  * move ahead one in the parm spec. */
191                 if ( pSpec[1] == ':' ) {
192                         requiresParam = true;
193                         pSpec += 2;
194                 }
195                 else {
196                         requiresParam = false;
197                         pSpec += 1;
198                 }
199
200                 /* Do we have a match. */
201                 if ( argChar == pSpecChar ) {
202                         if ( requiresParam ) {
203                                 if ( argOffset[1] == 0 ) {
204                                         /* The param must follow. */
205                                         if ( iCurArg + 1 == argc ) {
206                                                 /* We are the last arg so there
207                                                  * cannot be a parameter to it. */
208                                                 parameter = argChar;
209                                                 parameterArg = 0;
210                                                 iCurArg += 1;
211                                                 argOffset = 0;
212                                                 state = invalid;
213                                                 return true;
214                                         }
215                                         else {
216                                                 /* the parameter to the arg is the next arg. */
217                                                 parameter = pSpecChar;
218                                                 parameterArg = argv[iCurArg + 1];
219                                                 iCurArg += 2;
220                                                 argOffset = 0;
221                                                 state = match;
222                                                 return true;
223                                         }
224                                 }
225                                 else {
226                                         /* The param for the arg is built in. */
227                                         parameter = pSpecChar;
228                                         parameterArg = argOffset + 1;
229                                         iCurArg += 1;
230                                         argOffset = 0;
231                                         state = match;
232                                         return true;
233                                 }
234                         }
235                         else {
236                                 /* Good, we matched the parm and no
237                                  * arg is required. */
238                                 parameter = pSpecChar;
239                                 parameterArg = 0;
240                                 argOffset += 1;
241                                 state = match;
242                                 return true;
243                         }
244                 }
245         }
246
247         /* We did not find a match. Bad Argument. */
248         parameter = argChar;
249         parameterArg = 0;
250         argOffset += 1;
251         state = invalid;
252         return true;
253 }
254
255 /* Counts newlines before sending sync. */
256 int output_filter::sync( )
257 {
258         line += 1;
259         return std::filebuf::sync();
260 }
261
262 /* Counts newlines before sending data out to file. */
263 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
264 {
265         for ( int i = 0; i < n; i++ ) {
266                 if ( s[i] == '\n' )
267                         line += 1;
268         }
269         return std::filebuf::xsputn( s, n );
270 }
271
272 /* Scans a string looking for the file extension. If there is a file
273  * extension then pointer returned points to inside the string
274  * passed in. Otherwise returns null. */
275 char *findFileExtension( char *stemFile )
276 {
277         char *ppos = stemFile + strlen(stemFile) - 1;
278
279         /* Scan backwards from the end looking for the first dot.
280          * If we encounter a '/' before the first dot, then stop the scan. */
281         while ( 1 ) {
282                 /* If we found a dot or got to the beginning of the string then
283                  * we are done. */
284                 if ( ppos == stemFile || *ppos == '.' )
285                         break;
286
287                 /* If we hit a / then there is no extension. Done. */
288                 if ( *ppos == '/' ) {
289                         ppos = stemFile;
290                         break;
291                 }
292                 ppos--;
293         } 
294
295         /* If we got to the front of the string then bail we 
296          * did not find an extension  */
297         if ( ppos == stemFile )
298                 ppos = 0;
299
300         return ppos;
301 }
302
303 /* Make a file name from a stem. Removes the old filename suffix and
304  * replaces it with a new one. Returns a newed up string. */
305 char *fileNameFromStem( char *stemFile, const char *suffix )
306 {
307         long len = strlen( stemFile );
308         assert( len > 0 );
309
310         /* Get the extension. */
311         char *ppos = findFileExtension( stemFile );
312
313         /* If an extension was found, then shorten what we think the len is. */
314         if ( ppos != 0 )
315                 len = ppos - stemFile;
316
317         /* Make the return string from the stem and the suffix. */
318         char *retVal = new char[ len + strlen( suffix ) + 1 ];
319         strncpy( retVal, stemFile, len );
320         strcpy( retVal + len, suffix );
321
322         return retVal;
323 }
324
325 exit_object endp;
326
327 void operator<<( std::ostream &out, exit_object & )
328 {
329     out << std::endl;
330     exit(1);
331 }