More warning elimination concerning constness.
[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 HostLang hostLangC =    { HostLang::C,    hostTypesC,    8, hostTypesC+0,    true };
69 HostLang hostLangD =    { HostLang::D,    hostTypesD,    9, hostTypesD+2,    true };
70 HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
71 HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
72
73 HostLang *hostLang = &hostLangC;
74
75 HostType *findAlphType( char *s1 )
76 {
77         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
78                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
79                                 hostLang->hostTypes[i].data2 == 0 )
80                 {
81                         return hostLang->hostTypes + i;
82                 }
83         }
84
85         return 0;
86 }
87
88 HostType *findAlphType( char *s1, char *s2 )
89 {
90         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
91                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
92                                 hostLang->hostTypes[i].data2 != 0 && 
93                                 strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
94                 {
95                         return hostLang->hostTypes + i;
96                 }
97         }
98
99         return 0;
100 }
101
102 HostType *findAlphTypeInternal( char *s1 )
103 {
104         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
105                 if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
106                         return hostLang->hostTypes + i;
107         }
108
109         return 0;
110 }
111
112 /* Construct a new parameter checker with for paramSpec. */
113 ParamCheck::ParamCheck( const char *paramSpec, int argc, char **argv )
114 :
115         state(noparam),
116         argOffset(0),
117         curArg(0),
118         iCurArg(1),
119         paramSpec(paramSpec), 
120         argc(argc), 
121         argv(argv)
122 {
123 }
124
125 /* Check a single option. Returns the index of the next parameter.  Sets p to
126  * the arg character if valid, 0 otherwise.  Sets parg to the parameter arg if
127  * there is one, NULL otherwise. */
128 bool ParamCheck::check()
129 {
130         bool requiresParam;
131
132         if ( iCurArg >= argc ) {            /* Off the end of the arg list. */
133                 state = noparam;
134                 return false;
135         }
136
137         if ( argOffset != 0 && *argOffset == 0 ) {
138                 /* We are at the end of an arg string. */
139                 iCurArg += 1;
140                 if ( iCurArg >= argc ) {
141                         state = noparam;
142                         return false;
143                 }
144                 argOffset = 0;
145         }
146
147         if ( argOffset == 0 ) {
148                 /* Set the current arg. */
149                 curArg = argv[iCurArg];
150
151                 /* We are at the beginning of an arg string. */
152                 if ( argv[iCurArg] == 0 ||        /* Argv[iCurArg] is null. */
153                          argv[iCurArg][0] != '-' ||   /* Not a param. */
154                          argv[iCurArg][1] == 0 ) {    /* Only a dash. */
155                         parameter = 0;
156                         parameterArg = 0;
157
158                         iCurArg += 1;
159                         state = noparam;
160                         return true;
161                 }
162                 argOffset = argv[iCurArg] + 1;
163         }
164
165         /* Get the arg char. */
166         char argChar = *argOffset;
167         
168         /* Loop over all the parms and look for a match. */
169         const char *pSpec = paramSpec;
170         while ( *pSpec != 0 ) {
171                 char pSpecChar = *pSpec;
172
173                 /* If there is a ':' following the char then
174                  * it requires a parm.  If a parm is required
175                  * then move ahead two in the parmspec. Otherwise
176                  * move ahead one in the parm spec. */
177                 if ( pSpec[1] == ':' ) {
178                         requiresParam = true;
179                         pSpec += 2;
180                 }
181                 else {
182                         requiresParam = false;
183                         pSpec += 1;
184                 }
185
186                 /* Do we have a match. */
187                 if ( argChar == pSpecChar ) {
188                         if ( requiresParam ) {
189                                 if ( argOffset[1] == 0 ) {
190                                         /* The param must follow. */
191                                         if ( iCurArg + 1 == argc ) {
192                                                 /* We are the last arg so there
193                                                  * cannot be a parameter to it. */
194                                                 parameter = argChar;
195                                                 parameterArg = 0;
196                                                 iCurArg += 1;
197                                                 argOffset = 0;
198                                                 state = invalid;
199                                                 return true;
200                                         }
201                                         else {
202                                                 /* the parameter to the arg is the next arg. */
203                                                 parameter = pSpecChar;
204                                                 parameterArg = argv[iCurArg + 1];
205                                                 iCurArg += 2;
206                                                 argOffset = 0;
207                                                 state = match;
208                                                 return true;
209                                         }
210                                 }
211                                 else {
212                                         /* The param for the arg is built in. */
213                                         parameter = pSpecChar;
214                                         parameterArg = argOffset + 1;
215                                         iCurArg += 1;
216                                         argOffset = 0;
217                                         state = match;
218                                         return true;
219                                 }
220                         }
221                         else {
222                                 /* Good, we matched the parm and no
223                                  * arg is required. */
224                                 parameter = pSpecChar;
225                                 parameterArg = 0;
226                                 argOffset += 1;
227                                 state = match;
228                                 return true;
229                         }
230                 }
231         }
232
233         /* We did not find a match. Bad Argument. */
234         parameter = argChar;
235         parameterArg = 0;
236         argOffset += 1;
237         state = invalid;
238         return true;
239 }
240
241 /* Counts newlines before sending sync. */
242 int output_filter::sync( )
243 {
244         line += 1;
245         return std::filebuf::sync();
246 }
247
248 /* Counts newlines before sending data out to file. */
249 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
250 {
251         for ( int i = 0; i < n; i++ ) {
252                 if ( s[i] == '\n' )
253                         line += 1;
254         }
255         return std::filebuf::xsputn( s, n );
256 }
257
258 /* Scans a string looking for the file extension. If there is a file
259  * extension then pointer returned points to inside the string
260  * passed in. Otherwise returns null. */
261 char *findFileExtension( char *stemFile )
262 {
263         char *ppos = stemFile + strlen(stemFile) - 1;
264
265         /* Scan backwards from the end looking for the first dot.
266          * If we encounter a '/' before the first dot, then stop the scan. */
267         while ( 1 ) {
268                 /* If we found a dot or got to the beginning of the string then
269                  * we are done. */
270                 if ( ppos == stemFile || *ppos == '.' )
271                         break;
272
273                 /* If we hit a / then there is no extension. Done. */
274                 if ( *ppos == '/' ) {
275                         ppos = stemFile;
276                         break;
277                 }
278                 ppos--;
279         } 
280
281         /* If we got to the front of the string then bail we 
282          * did not find an extension  */
283         if ( ppos == stemFile )
284                 ppos = 0;
285
286         return ppos;
287 }
288
289 /* Make a file name from a stem. Removes the old filename suffix and
290  * replaces it with a new one. Returns a newed up string. */
291 char *fileNameFromStem( char *stemFile, const char *suffix )
292 {
293         long len = strlen( stemFile );
294         assert( len > 0 );
295
296         /* Get the extension. */
297         char *ppos = findFileExtension( stemFile );
298
299         /* If an extension was found, then shorten what we think the len is. */
300         if ( ppos != 0 )
301                 len = ppos - stemFile;
302
303         /* Make the return string from the stem and the suffix. */
304         char *retVal = new char[ len + strlen( suffix ) + 1 ];
305         strncpy( retVal, stemFile, len );
306         strcpy( retVal + len, suffix );
307
308         return retVal;
309 }
310
311 exit_object endp;
312
313 void operator<<( std::ostream &out, exit_object & )
314 {
315     out << std::endl;
316     exit(1);
317 }