xref: /trunk/main/idlc/source/idlccompile.cxx (revision cdf0e10c)
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