private sync
[external/ragel.git] / ragel / common.cpp
1 /*
2  *  Copyright 2006-2007 Adrian Thurston <thurston@complang.org>
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 #define S8BIT_MIN  -128
41 #define S8BIT_MAX  127
42
43 #define U8BIT_MIN  0
44 #define U8BIT_MAX  255
45
46 #define S16BIT_MIN -32768
47 #define S16BIT_MAX 32767
48
49 #define U16BIT_MIN 0
50 #define U16BIT_MAX 65535
51
52 #define S32BIT_MIN –2147483648l
53 #define S32BIT_MAX 2147483647l
54
55 #define U32BIT_MIN 0
56 #define U32BIT_MAX 4294967295l
57
58 #define S64BIT_MIN –9223372036854775808ll
59 #define S64BIT_MAX 9223372036854775807ll
60
61 #define U64BIT_MIN 0
62 #define U64BIT_MAX 18446744073709551615ll
63
64 HostType hostTypesD[] =
65 {
66         { "byte",    0,  "byte",    true,   CHAR_MIN,  CHAR_MAX,    1 },
67         { "ubyte",   0,  "ubyte",   false,  0,         UCHAR_MAX,   1 },
68         { "char",    0,  "char",    false,  0,         UCHAR_MAX,   1 },
69         { "short",   0,  "short",   true,   SHRT_MIN,  SHRT_MAX,    2 },
70         { "ushort",  0,  "ushort",  false,  0,         USHRT_MAX,   2 },
71         { "wchar",   0,  "wchar",   false,  0,         USHRT_MAX,   2 },
72         { "int",     0,  "int",     true,   INT_MIN,   INT_MAX,     4 },
73         { "uint",    0,  "uint",    false,  0,         UINT_MAX,    4 },
74         { "dchar",   0,  "dchar",   false,  0,         UINT_MAX,    4 }
75 };
76
77 HostType hostTypesJava[] = 
78 {
79         { "byte",    0,  "byte",   true,   CHAR_MIN,  CHAR_MAX,    1 },
80         { "short",   0,  "short",  true,   SHRT_MIN,  SHRT_MAX,    2 },
81         { "char",    0,  "char",   false,  0,         USHRT_MAX,   2 },
82         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
83 };
84
85 /* What are the appropriate types for ruby? */
86 HostType hostTypesRuby[] = 
87 {
88         { "char",    0,  "char",   true,   CHAR_MIN,  CHAR_MAX,    1 },
89         { "int",     0,  "int",    true,   INT_MIN,   INT_MAX,     4 },
90 };
91
92 HostType hostTypesCSharp[] =
93 {
94         { "sbyte",    0, "sbyte",   true,   CHAR_MIN,  CHAR_MAX,    1 },
95         { "byte",   0,   "byte",    false,  0,         UCHAR_MAX,   1 },
96         { "short",   0,  "short",   true,   SHRT_MIN,  SHRT_MAX,    2 },
97         { "ushort",  0,  "ushort",  false,  0,         USHRT_MAX,   2 },
98         { "char",    0,  "char",    false,  0,         USHRT_MAX,   2 },
99         { "int",     0,  "int",     true,   INT_MIN,   INT_MAX,     4 },
100         { "uint",    0,  "uint",    false,  0,         UINT_MAX,    4 },
101         { "long",    0,  "long",    true,   LONG_MIN,  LONG_MAX,    8 },
102         { "ulong",   0,  "ulong",   false,  0,         ULONG_MAX,   8 }
103 };
104
105 HostLang hostLangC =    { HostLang::C,    hostTypesC,    8, hostTypesC+0,    true };
106 HostLang hostLangD =    { HostLang::D,    hostTypesD,    9, hostTypesD+2,    true };
107 HostLang hostLangJava = { HostLang::Java, hostTypesJava, 4, hostTypesJava+2, false };
108 HostLang hostLangRuby = { HostLang::Ruby, hostTypesRuby, 2, hostTypesRuby+0, false };
109 HostLang hostLangCSharp = { HostLang::CSharp, hostTypesCSharp, 9, hostTypesCSharp+4, true };
110
111 HostLang *hostLang = &hostLangC;
112
113 HostType *findAlphType( const char *s1 )
114 {
115         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
116                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
117                                 hostLang->hostTypes[i].data2 == 0 )
118                 {
119                         return hostLang->hostTypes + i;
120                 }
121         }
122
123         return 0;
124 }
125
126 HostType *findAlphType( const char *s1, const char *s2 )
127 {
128         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
129                 if ( strcmp( s1, hostLang->hostTypes[i].data1 ) == 0 && 
130                                 hostLang->hostTypes[i].data2 != 0 && 
131                                 strcmp( s2, hostLang->hostTypes[i].data2 ) == 0 )
132                 {
133                         return hostLang->hostTypes + i;
134                 }
135         }
136
137         return 0;
138 }
139
140 HostType *findAlphTypeInternal( const char *s1 )
141 {
142         for ( int i = 0; i < hostLang->numHostTypes; i++ ) {
143                 if ( strcmp( s1, hostLang->hostTypes[i].internalName ) == 0 )
144                         return hostLang->hostTypes + i;
145         }
146
147         return 0;
148 }
149
150 /* Construct a new parameter checker with for paramSpec. */
151 ParamCheck::ParamCheck( const char *paramSpec, int argc, const char **argv )
152 :
153         state(noparam),
154         argOffset(0),
155         curArg(0),
156         iCurArg(1),
157         paramSpec(paramSpec), 
158         argc(argc), 
159         argv(argv)
160 {
161 }
162
163 /* Check a single option. Returns the index of the next parameter.  Sets p to
164  * the arg character if valid, 0 otherwise.  Sets parg to the parameter arg if
165  * there is one, NULL otherwise. */
166 bool ParamCheck::check()
167 {
168         bool requiresParam;
169
170         if ( iCurArg >= argc ) {            /* Off the end of the arg list. */
171                 state = noparam;
172                 return false;
173         }
174
175         if ( argOffset != 0 && *argOffset == 0 ) {
176                 /* We are at the end of an arg string. */
177                 iCurArg += 1;
178                 if ( iCurArg >= argc ) {
179                         state = noparam;
180                         return false;
181                 }
182                 argOffset = 0;
183         }
184
185         if ( argOffset == 0 ) {
186                 /* Set the current arg. */
187                 curArg = argv[iCurArg];
188
189                 /* We are at the beginning of an arg string. */
190                 if ( argv[iCurArg] == 0 ||        /* Argv[iCurArg] is null. */
191                          argv[iCurArg][0] != '-' ||   /* Not a param. */
192                          argv[iCurArg][1] == 0 ) {    /* Only a dash. */
193                         parameter = 0;
194                         paramArg = 0;
195
196                         iCurArg += 1;
197                         state = noparam;
198                         return true;
199                 }
200                 argOffset = argv[iCurArg] + 1;
201         }
202
203         /* Get the arg char. */
204         char argChar = *argOffset;
205         
206         /* Loop over all the parms and look for a match. */
207         const char *pSpec = paramSpec;
208         while ( *pSpec != 0 ) {
209                 char pSpecChar = *pSpec;
210
211                 /* If there is a ':' following the char then
212                  * it requires a parm.  If a parm is required
213                  * then move ahead two in the parmspec. Otherwise
214                  * move ahead one in the parm spec. */
215                 if ( pSpec[1] == ':' ) {
216                         requiresParam = true;
217                         pSpec += 2;
218                 }
219                 else {
220                         requiresParam = false;
221                         pSpec += 1;
222                 }
223
224                 /* Do we have a match. */
225                 if ( argChar == pSpecChar ) {
226                         if ( requiresParam ) {
227                                 if ( argOffset[1] == 0 ) {
228                                         /* The param must follow. */
229                                         if ( iCurArg + 1 == argc ) {
230                                                 /* We are the last arg so there
231                                                  * cannot be a parameter to it. */
232                                                 parameter = argChar;
233                                                 paramArg = 0;
234                                                 iCurArg += 1;
235                                                 argOffset = 0;
236                                                 state = invalid;
237                                                 return true;
238                                         }
239                                         else {
240                                                 /* the parameter to the arg is the next arg. */
241                                                 parameter = pSpecChar;
242                                                 paramArg = argv[iCurArg + 1];
243                                                 iCurArg += 2;
244                                                 argOffset = 0;
245                                                 state = match;
246                                                 return true;
247                                         }
248                                 }
249                                 else {
250                                         /* The param for the arg is built in. */
251                                         parameter = pSpecChar;
252                                         paramArg = argOffset + 1;
253                                         iCurArg += 1;
254                                         argOffset = 0;
255                                         state = match;
256                                         return true;
257                                 }
258                         }
259                         else {
260                                 /* Good, we matched the parm and no
261                                  * arg is required. */
262                                 parameter = pSpecChar;
263                                 paramArg = 0;
264                                 argOffset += 1;
265                                 state = match;
266                                 return true;
267                         }
268                 }
269         }
270
271         /* We did not find a match. Bad Argument. */
272         parameter = argChar;
273         paramArg = 0;
274         argOffset += 1;
275         state = invalid;
276         return true;
277 }
278
279 /* Counts newlines before sending sync. */
280 int output_filter::sync( )
281 {
282         line += 1;
283         return std::filebuf::sync();
284 }
285
286 /* Counts newlines before sending data out to file. */
287 std::streamsize output_filter::xsputn( const char *s, std::streamsize n )
288 {
289         for ( int i = 0; i < n; i++ ) {
290                 if ( s[i] == '\n' )
291                         line += 1;
292         }
293         return std::filebuf::xsputn( s, n );
294 }
295
296 /* Scans a string looking for the file extension. If there is a file
297  * extension then pointer returned points to inside the string
298  * passed in. Otherwise returns null. */
299 const char *findFileExtension( const char *stemFile )
300 {
301         const char *ppos = stemFile + strlen(stemFile) - 1;
302
303         /* Scan backwards from the end looking for the first dot.
304          * If we encounter a '/' before the first dot, then stop the scan. */
305         while ( 1 ) {
306                 /* If we found a dot or got to the beginning of the string then
307                  * we are done. */
308                 if ( ppos == stemFile || *ppos == '.' )
309                         break;
310
311                 /* If we hit a / then there is no extension. Done. */
312                 if ( *ppos == '/' ) {
313                         ppos = stemFile;
314                         break;
315                 }
316                 ppos--;
317         } 
318
319         /* If we got to the front of the string then bail we 
320          * did not find an extension  */
321         if ( ppos == stemFile )
322                 ppos = 0;
323
324         return ppos;
325 }
326
327 /* Make a file name from a stem. Removes the old filename suffix and
328  * replaces it with a new one. Returns a newed up string. */
329 const char *fileNameFromStem( const char *stemFile, const char *suffix )
330 {
331         long len = strlen( stemFile );
332         assert( len > 0 );
333
334         /* Get the extension. */
335         const char *ppos = findFileExtension( stemFile );
336
337         /* If an extension was found, then shorten what we think the len is. */
338         if ( ppos != 0 )
339                 len = ppos - stemFile;
340
341         /* Make the return string from the stem and the suffix. */
342         char *retVal = new char[ len + strlen( suffix ) + 1 ];
343         strncpy( retVal, stemFile, len );
344         strcpy( retVal + len, suffix );
345
346         return retVal;
347 }
348
349 exit_object endp;
350
351 void operator<<( std::ostream &out, exit_object & )
352 {
353     out << std::endl;
354     exit(1);
355 }