xref: /trunk/main/idlc/source/idlccompile.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_idlc.hxx"
30 #include <idlc/idlc.hxx>
31 #include <rtl/ustring.hxx>
32 #include <rtl/strbuf.hxx>
33 #include <osl/process.h>
34 #include <osl/diagnose.h>
35 #include <osl/thread.h>
36 #include <osl/file.hxx>
37 
38 #if defined(SAL_W32) || defined(SAL_OS2)
39 #include <io.h>
40 #endif
41 
42 #ifdef  SAL_UNX
43 #include <unistd.h>
44 #if defined(MACOSX) || defined(FREEBSD) || defined(NETBSD)
45 #include <sys/wait.h>
46 #else
47 #include <wait.h>
48 #endif
49 #endif
50 
51 #include <string.h>
52 
53 using namespace ::rtl;
54 using namespace ::osl;
55 
56 extern int yyparse();
57 extern FILE* yyin;
58 extern int yydebug;
59 
60 sal_Int32 lineNumber = 1;
61 
62 
63 static OUString TMP(RTL_CONSTASCII_USTRINGPARAM("TMP"));
64 static OUString TEMP(RTL_CONSTASCII_USTRINGPARAM("TEMP"));
65 static sal_Char tmpFilePattern[512];
66 
67 sal_Bool isFileUrl(const OString& fileName)
68 {
69     if (fileName.indexOf("file://") == 0 )
70         return sal_True;
71     return sal_False;
72 }
73 
74 OString convertToAbsoluteSystemPath(const OString& fileName)
75 {
76     OUString uSysFileName;
77     OUString uFileName(fileName.getStr(), fileName.getLength(), osl_getThreadTextEncoding());
78     if ( isFileUrl(fileName) )
79     {
80         if (FileBase::getSystemPathFromFileURL(uFileName, uSysFileName)
81             != FileBase::E_None)
82         {
83             OSL_ASSERT(false);
84         }
85     } else
86     {
87         OUString uWorkingDir, uUrlFileName, uTmp;
88         if (osl_getProcessWorkingDir(&uWorkingDir.pData) != osl_Process_E_None)
89         {
90             OSL_ASSERT(false);
91         }
92         if (FileBase::getFileURLFromSystemPath(uFileName, uTmp)
93             != FileBase::E_None)
94         {
95             OSL_ASSERT(false);
96         }
97         if (FileBase::getAbsoluteFileURL(uWorkingDir, uTmp, uUrlFileName)
98             != FileBase::E_None)
99         {
100             OSL_ASSERT(false);
101         }
102         if (FileBase::getSystemPathFromFileURL(uUrlFileName, uSysFileName)
103             != FileBase::E_None)
104         {
105             OSL_ASSERT(false);
106         }
107     }
108 
109     return OUStringToOString(uSysFileName, osl_getThreadTextEncoding());
110 }
111 
112 OString convertToFileUrl(const OString& fileName)
113 {
114     if ( !isFileUrl(fileName) )
115     {
116         OString tmp = convertToAbsoluteSystemPath(fileName);
117         OUString uFileName(tmp.getStr(), tmp.getLength(), osl_getThreadTextEncoding());
118         OUString uUrlFileName;
119         if (FileBase::getFileURLFromSystemPath(uFileName, uUrlFileName)
120             != FileBase::E_None)
121         {
122             OSL_ASSERT(false);
123         }
124         return OUStringToOString(uUrlFileName, osl_getThreadTextEncoding());
125     }
126 
127     return fileName;
128 }
129 
130 OString makeTempName(const OString& prefix)
131 {
132     OUString uTmpPath;
133     OString tmpPath;
134 
135     if ( osl_getEnvironment(TMP.pData, &uTmpPath.pData) != osl_Process_E_None )
136     {
137         if ( osl_getEnvironment(TEMP.pData, &uTmpPath.pData) != osl_Process_E_None )
138         {
139 #if defined(SAL_W32)
140             tmpPath = OString("c:\\temp");
141 #else
142             tmpPath = OString("/tmp");
143 #endif
144         }
145     }
146 
147     if ( uTmpPath.getLength() )
148         tmpPath = OUStringToOString(uTmpPath, RTL_TEXTENCODING_UTF8);
149 
150 #if defined(SAL_W32) || defined(SAL_UNX) || defined(SAL_OS2)
151 
152     OSL_ASSERT( sizeof(tmpFilePattern) > ( strlen(tmpPath)
153                                            + RTL_CONSTASCII_LENGTH(
154                                                 PATH_SEPARATOR )
155                                            + prefix.getLength()
156                                            + RTL_CONSTASCII_LENGTH(
157                                                 "XXXXXX") ) );
158 
159     tmpFilePattern[ sizeof(tmpFilePattern)-1 ] = '\0';
160     strncpy(tmpFilePattern, tmpPath, sizeof(tmpFilePattern)-1);
161     strncat(tmpFilePattern, PATH_SEPARATOR, sizeof(tmpFilePattern)-1-strlen(tmpFilePattern));
162     strncat(tmpFilePattern, prefix.getStr(), sizeof(tmpFilePattern)-1-strlen(tmpFilePattern));
163     strncat(tmpFilePattern, "XXXXXX", sizeof(tmpFilePattern)-1-strlen(tmpFilePattern));
164 
165 #ifdef SAL_UNX
166     int nDescriptor = mkstemp(tmpFilePattern);
167     if( -1 == nDescriptor )
168     {
169         fprintf( stderr,"idlc: couldn't create temporary file\n" );
170         exit( 1 );
171     }
172     // the file shall later be reopened by stdio functions
173     close( nDescriptor );
174 #else
175     (void) mktemp(tmpFilePattern);
176 #endif
177 #endif
178 
179     return OString(tmpFilePattern);
180 }
181 
182 sal_Bool copyFile(const OString* source, const OString& target)
183 {
184     sal_Bool bRet = sal_True;
185 
186     FILE* pSource = source == 0 ? stdin : fopen(source->getStr(), "rb");
187 
188     if ( !pSource )
189         return sal_False;
190 
191     FILE* pTarget = fopen(target.getStr(), "wb");
192 
193     if ( !pTarget )
194     {
195         fclose(pSource);
196         return sal_False;
197     }
198 
199     size_t totalSize = 512;
200     size_t readSize  = 0;
201     size_t writeSize = 0;
202     char   pBuffer[513];
203 
204     while ( !feof(pSource) )
205     {
206         if ( (readSize = fread(pBuffer, 1, totalSize, pSource)) > 0 && !ferror(pSource) )
207         {
208             if ( (writeSize = fwrite(pBuffer, 1, readSize, pTarget)) != readSize || ferror(pTarget) )
209             {
210                 if (source != 0) {
211                     fclose(pSource);
212                 }
213                 fclose(pTarget);
214                 return sal_False;
215             }
216         }
217     }
218 
219     if (source != 0) {
220         fclose(pSource);
221     }
222     if ( fflush(pTarget) )
223         bRet = sal_False;
224     fclose(pTarget);
225 
226     return bRet;
227 }
228 
229 sal_Int32 compileFile(const OString * pathname)
230 {
231     // preprocess input file
232     OString tmpFile = makeTempName(OString("idli_"));
233     OString preprocFile = makeTempName(OString("idlf_"));
234 
235     OString fileName;
236     if (pathname == 0) {
237         fileName = "stdin";
238     } else {
239         fileName = *pathname;
240     }
241 
242     if ( !copyFile(pathname, tmpFile) )
243     {
244         fprintf(stderr, "%s: could not copy %s%s to %s\n",
245                 idlc()->getOptions()->getProgramName().getStr(),
246                 pathname == 0 ? "" : "file ", fileName.getStr(),
247                 tmpFile.getStr());
248         exit(99);
249     }
250 
251     idlc()->setFileName(fileName);
252     idlc()->setMainFileName(fileName);
253     idlc()->setRealFileName(tmpFile);
254 
255     OStringBuffer cppArgs(512);
256     cppArgs.append("-DIDL -Xi -Xc -+ -I.");
257     Options* pOptions = idlc()->getOptions();
258 
259     OString filePath;
260     sal_Int32 index = fileName.lastIndexOf(SEPARATOR);
261 
262     if ( index > 0)
263     {
264         filePath = fileName.copy(0, index);
265 
266         if ( filePath.getLength() )
267         {
268             cppArgs.append(" -I\"");
269             cppArgs.append(filePath);
270             cppArgs.append("\"");
271         }
272     }
273 
274     if ( pOptions->isValid("-D") )
275     {
276         cppArgs.append(" ");
277         cppArgs.append(pOptions->getOption("-D"));
278     }
279     if ( pOptions->isValid("-I") )
280     {
281         cppArgs.append(" ");
282         cppArgs.append(pOptions->getOption("-I"));
283     }
284 
285     cppArgs.append(" \"");
286     cppArgs.append(tmpFile);
287     cppArgs.append("\" \"");
288     cppArgs.append(preprocFile);
289     cppArgs.append("\"");
290 
291     OString cmdFileName = makeTempName(OString("idlc_"));
292     FILE* pCmdFile = fopen(cmdFileName, "w");
293 
294     if ( !pCmdFile )
295     {
296         fprintf(stderr, "%s: couldn't open temporary file for preprocessor commands: %s\n",
297             idlc()->getOptions()->getProgramName().getStr(), cmdFileName.getStr());
298         exit(99);
299     }
300 #ifdef SAL_OS2_00
301       char* tok = strtok( (char*)cppArgs.getStr(), " \t\n\r");
302       while( tok) {
303          if (tok[strlen(tok)-1] == '\"')
304             tok[strlen(tok)-1] = '\0';
305          if (*tok == '\"')
306             memcpy( tok, tok+1, strlen(tok));
307          if (strlen(tok)>0) {
308             fputs(tok, pCmdFile);
309             fputc('\n', pCmdFile);
310          }
311          tok = strtok( NULL, " \t\n\r");
312       }
313 #else
314     fprintf(pCmdFile, "%s", cppArgs.getStr());
315 #endif
316     fclose(pCmdFile);
317 
318     OUString cmdArg(RTL_CONSTASCII_USTRINGPARAM("@"));
319     cmdArg += OStringToOUString(cmdFileName, RTL_TEXTENCODING_UTF8);
320 
321     OUString cpp;
322     OUString startDir;
323     if (osl_getExecutableFile(&cpp.pData) != osl_Process_E_None) {
324         OSL_ASSERT(false);
325     }
326 
327     sal_Int32 idx= cpp.lastIndexOf(OUString( RTL_CONSTASCII_USTRINGPARAM("idlc")) );
328     cpp = cpp.copy(0, idx);
329 
330 #if defined(SAL_W32) || defined(SAL_OS2)
331     cpp += OUString( RTL_CONSTASCII_USTRINGPARAM("idlcpp.exe"));
332 #else
333     cpp += OUString( RTL_CONSTASCII_USTRINGPARAM("idlcpp"));
334 #endif
335 
336     oslProcess      hProcess = NULL;
337     oslProcessError procError = osl_Process_E_None;
338 
339     procError = osl_executeProcess(cpp.pData, &cmdArg.pData, 1, osl_Process_WAIT,
340                                    0, startDir.pData, 0, 0, &hProcess);
341 
342     oslProcessInfo hInfo;
343     hInfo.Size = (sal_uInt32)(sizeof(oslProcessInfo));
344     if (osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &hInfo)
345         != osl_Process_E_None)
346     {
347         OSL_ASSERT(false);
348     }
349 
350     if ( procError || (hInfo.Code != 0) )
351     {
352         if ( procError != osl_Process_E_None )
353             fprintf(stderr, "%s: starting preprocessor failed\n", pOptions->getProgramName().getStr());
354         else
355             fprintf(stderr, "%s: preprocessing %s%s failed\n",
356                     pOptions->getProgramName().getStr(),
357                     pathname == 0 ? "" : "file ", fileName.getStr());
358 
359         unlink(tmpFile.getStr());
360         unlink(preprocFile.getStr());
361         unlink(cmdFileName.getStr());
362         osl_freeProcessHandle(hProcess);
363         exit(hInfo.Code ? hInfo.Code : 99);
364     }
365     osl_freeProcessHandle(hProcess);
366 
367     if (unlink(tmpFile.getStr()) != 0)
368     {
369         fprintf(stderr, "%s: Could not remove cpp input file %s\n",
370                  pOptions->getProgramName().getStr(), tmpFile.getStr());
371         exit(99);
372     }
373 
374     if (unlink(cmdFileName.getStr()) != 0)
375     {
376         fprintf(stderr, "%s: Could not remove unocpp command file %s\n",
377                 pOptions->getProgramName().getStr(), cmdFileName.getStr());
378 
379         exit(99);
380     }
381 
382     if ( pOptions->isValid("-E") )
383     {
384         if (unlink(preprocFile) != 0)
385         {
386             fprintf(stderr, "%s: Could not remove parser input file %s\n",
387                     pOptions->getProgramName().getStr(), preprocFile.getStr());
388             exit(99);
389         }
390         exit(0);
391     }
392 
393     // parse file
394     yyin = fopen(preprocFile.getStr(), "r");
395     if (yyin == NULL)
396     {
397         fprintf(stderr, "%s: Could not open cpp output file %s\n",
398                 pOptions->getProgramName().getStr(), preprocFile.getStr());
399         exit(99);
400     }
401 
402     //yydebug = 0 no trace information
403     //yydebug = 1 parser produce trace information
404     yydebug = 0;
405 
406     sal_Int32 nErrors = yyparse();
407     nErrors = idlc()->getErrorCount();
408 
409     fclose(yyin);
410     if (unlink(preprocFile.getStr()) != 0)
411     {
412         fprintf(stderr, "%s: Could not remove parser input file %s\n",
413                 pOptions->getProgramName().getStr(), preprocFile.getStr());
414         exit(99);
415     }
416 
417     return nErrors;
418 }
419