Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / TAO / TAO_IDL / driver / drv_preproc.cpp
blobb182ad6b9889e74c1bf808237c7c32ff93c3d52c
1 /*
3 COPYRIGHT
5 Copyright 1992, 1993, 1994 Sun Microsystems, Inc. Printed in the United
6 States of America. All Rights Reserved.
8 This product is protected by copyright and distributed under the following
9 license restricting its use.
11 The Interface Definition Language Compiler Front End (CFE) is made
12 available for your use provided that you include this license and copyright
13 notice on all media and documentation and the software program in which
14 this product is incorporated in whole or part. You may copy and extend
15 functionality (but may not remove functionality) of the Interface
16 Definition Language CFE without charge, but you are not authorized to
17 license or distribute it to anyone else except as part of a product or
18 program developed by you or with the express written consent of Sun
19 Microsystems, Inc. ("Sun").
21 The names of Sun Microsystems, Inc. and any of its subsidiaries or
22 affiliates may not be used in advertising or publicity pertaining to
23 distribution of Interface Definition Language CFE as permitted herein.
25 This license is effective until terminated by Sun for failure to comply
26 with this license. Upon termination, you shall destroy or return all code
27 and documentation for the Interface Definition Language CFE.
29 INTERFACE DEFINITION LANGUAGE CFE IS PROVIDED AS IS WITH NO WARRANTIES OF
30 ANY KIND INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS
31 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR ARISING FROM A COURSE OF
32 DEALING, USAGE OR TRADE PRACTICE.
34 INTERFACE DEFINITION LANGUAGE CFE IS PROVIDED WITH NO SUPPORT AND WITHOUT
35 ANY OBLIGATION ON THE PART OF Sun OR ANY OF ITS SUBSIDIARIES OR AFFILIATES
36 TO ASSIST IN ITS USE, CORRECTION, MODIFICATION OR ENHANCEMENT.
38 SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES SHALL HAVE NO LIABILITY WITH
39 RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY
40 INTERFACE DEFINITION LANGUAGE CFE OR ANY PART THEREOF.
42 IN NO EVENT WILL SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES BE LIABLE FOR
43 ANY LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL
44 DAMAGES, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46 Use, duplication, or disclosure by the government is subject to
47 restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
48 Technical Data and Computer Software clause at DFARS 252.227-7013 and FAR
49 52.227-19.
51 Sun, Sun Microsystems and the Sun logo are trademarks or registered
52 trademarks of Sun Microsystems, Inc.
54 SunSoft, Inc.
55 2550 Garcia Avenue
56 Mountain View, California 94043
58 NOTE:
60 SunOS, SunSoft, Sun, Solaris, Sun Microsystems or the Sun logo are
61 trademarks or registered trademarks of Sun Microsystems, Inc.
65 // Pass an IDL file through the C preprocessor
68 #include "idl_defines.h"
69 #include "global_extern.h"
70 #include "fe_extern.h"
71 #include "drv_extern.h"
72 #include "utl_string.h"
73 #include "utl_err.h"
75 #include "ace/Version.h"
76 #include "ace/Process_Manager.h"
77 #include "ace/SString.h"
78 #include "ace/Env_Value_T.h"
79 #include "ace/ARGV.h"
80 #include "ace/UUID.h"
81 #include "ace/Dirent.h"
82 #include "ace/OS_NS_sys_stat.h"
83 #include "ace/Truncate.h"
85 // FUZZ: disable check_for_streams_include
86 #include "ace/streams.h"
88 #include "ace/OS_NS_stdio.h"
89 #include "ace/OS_NS_unistd.h"
90 #include "ace/OS_NS_fcntl.h"
91 #include "ace/OS_NS_sys_stat.h"
93 // Storage for preprocessor args.
94 unsigned long const DRV_MAX_ARGCOUNT = 1024;
95 unsigned long DRV_argcount = 0;
96 ACE_TCHAR const * DRV_arglist[DRV_MAX_ARGCOUNT] = { 0 };
98 static char const * output_arg_format = 0;
99 static long output_arg_index = 0;
101 ACE_TCHAR const TCHAR_DIR_DOT[] = ACE_TEXT(".");
103 #if defined (ACE_HAS_TCHAR_DIRENT)
104 // ACE_TCHAR const DIR_DOT[] = ACE_TEXT(".");
105 ACE_TCHAR const DIR_DOT_DOT[] = ACE_TEXT("..");
106 #else
107 // char const DIR_DOT[] = ".";
108 char const DIR_DOT_DOT[] = "..";
109 #endif /* ACE_HAS_TCHAR_DIRENT */
111 // File names.
112 static char tmp_file [MAXPATHLEN + 1] = { 0 };
113 static char tmp_ifile[MAXPATHLEN + 1] = { 0 };
115 // Lines can be 1024 chars long intially -
116 // it will expand as required.
117 #define LINEBUF_SIZE 1024
118 char* drv_line = 0;
119 static size_t drv_line_size = LINEBUF_SIZE + 1;
121 // Push the new CPP location if we got a -Yp argument.
122 void
123 DRV_cpp_new_location (char const * new_loc)
125 ACE::strdelete (const_cast<ACE_TCHAR *> (DRV_arglist[0]));
126 DRV_arglist[0] =
127 ACE::strnew (ACE_TEXT_CHAR_TO_TCHAR (new_loc));
130 // Push an argument into the DRV_arglist.
131 void
132 DRV_cpp_putarg (const char *str)
134 if (DRV_argcount >= DRV_MAX_ARGCOUNT)
136 ACE_ERROR ((LM_ERROR,
137 "%C: More than %d arguments to preprocessor\n",
138 idl_global->prog_name (),
139 DRV_MAX_ARGCOUNT ));
141 throw Bailout ();
144 char *replace = 0;
145 if (str)
147 bool allocate_error = false;
149 #ifdef ACE_WIN32
150 const char *const first_quote = ACE_OS::strchr (str, '"');
151 if (first_quote)
153 // Escape Doublequotes on Windows
155 size_t quote_count = 0;
156 for (const char *quote = first_quote; quote; quote = ACE_OS::strchr (quote, '"'))
158 ++quote_count;
159 ++quote;
162 ACE_NEW_NORETURN (replace, char[ACE_OS::strlen (str) + quote_count + 1]);
163 allocate_error = !replace;
164 if (replace)
166 char *to = replace;
167 for (const char *from = str; *from; ++from)
169 if (*from == '"')
171 *to = '\\';
172 ++to;
174 *to = *from;
175 ++to;
177 *to = '\0';
180 #endif
181 if (ACE_OS::strchr (str, ' '))
183 ACE_NEW_NORETURN (replace, char[ACE_OS::strlen (str) + 3]);
184 allocate_error = !replace;
185 if (replace)
187 replace[0] = '"';
188 ACE_OS::strcpy (replace + 1, str);
189 ACE_OS::strcat (replace, "\"");
193 if (allocate_error)
195 idl_global->err()->misc_error ("DRV_cpp_putarg failed to allocate memory for argument!");
196 throw Bailout ();
200 DRV_arglist[DRV_argcount++] = ACE::strnew (ACE_TEXT_CHAR_TO_TCHAR (replace ? replace : str));
202 if (replace)
204 delete [] replace;
205 replace = 0;
209 // Expand the output argument with the given filename.
210 void
211 DRV_cpp_expand_output_arg (const char *filename)
213 if (output_arg_format != 0)
215 ACE::strdelete (const_cast<ACE_TCHAR *> (
216 DRV_arglist[output_arg_index]));
217 DRV_arglist[output_arg_index] = 0;
219 ACE_NEW (DRV_arglist[output_arg_index],
220 ACE_TCHAR [ACE_OS::strlen (output_arg_format)
221 + ACE_OS::strlen (filename)
222 + 1]);
224 ACE_OS::sprintf (const_cast<ACE_TCHAR *> (
225 DRV_arglist[output_arg_index]),
226 ACE_TEXT_CHAR_TO_TCHAR (output_arg_format),
227 ACE_TEXT_CHAR_TO_TCHAR (filename));
231 // calculate the total size of all commandline arguments
232 unsigned int
233 DRV_cpp_calc_total_argsize(void)
235 unsigned long size = 0;
236 unsigned long ix = 0;
237 while (DRV_arglist[ix] != 0)
239 size += ACE_Utils::truncate_cast<unsigned long> (ACE_OS::strlen (DRV_arglist[ix]) + 1);
240 ++ix;
242 return size;
245 // Get a line from stdin.
246 static bool
247 DRV_get_line (FILE *file)
249 char *line = ACE_OS::fgets (drv_line,
250 ACE_Utils::truncate_cast<int> (drv_line_size),
251 file);
252 if (!line || (!*line && feof (file)))
254 // End of file, nothing else read in.
255 return false;
260 // Check for line continuation escape...
261 size_t len = ACE_OS::strlen (drv_line);
262 if (2 <= len &&
263 '\n' == drv_line [len-1] &&
264 '\\' == drv_line [len-2] )
266 // This is a "false" end-of-line, remove token
267 len-= 2;
268 drv_line [len]= '\0';
271 // Check for end-of-line
272 if (len && '\n' == drv_line [len-1])
274 // Replace the end-of-line with a null
275 drv_line [len-1] = '\0';
276 return true;
279 // Need to continue to read more of this line in,
280 // is there enough space left in the buffer?
281 if (drv_line_size - len < 10)
283 // Create a bigger buffer
284 size_t temp_size = drv_line_size * 2;
285 char *temp = 0;
286 ACE_NEW_RETURN (temp, char [temp_size], false);
287 ACE_OS::strcpy (temp, drv_line);
288 delete [] drv_line;
289 drv_line = temp;
290 drv_line_size = temp_size;
293 line = ACE_OS::fgets (drv_line + len,
294 ACE_Utils::truncate_cast<int> (drv_line_size - len),
295 file);
296 } while (line && *line);
298 return true;
301 // Initialize the cpp argument list.
302 void
303 DRV_cpp_init (void)
305 // Create the line buffer.
306 // (JP) Deleting this at the end or DRV_pre_proc() causes
307 // Purify to output a Freeing Mismatched Memory warning.
308 // When it is not deleted (currently the case) there is no
309 // memory leak reported by Purify. I don't know why.
310 ACE_NEW (drv_line,
311 char [drv_line_size]);
313 char const * const cpp_loc = FE_get_cpp_loc_from_env ();
314 DRV_cpp_putarg (cpp_loc);
316 // Add an option to the IDL compiler to make the TAO version
317 // available to the user. A XX.YY.ZZ release gets
318 // version 0xXXYYZZ, for example, 5.1.14 gets 0x050114.
319 char version_option[128];
320 ACE_OS::sprintf (version_option,
321 "-D__TAO_IDL=0x%2.2d%2.2d%2.2d",
322 ACE_MAJOR_VERSION,
323 ACE_MINOR_VERSION,
324 ACE_MICRO_VERSION);
326 DRV_cpp_putarg (version_option);
327 DRV_cpp_putarg ("-I.");
329 const char *platform_cpp_args =
330 FE_get_cpp_args_from_env ();
332 if (platform_cpp_args == 0)
334 // If no cpp flag was defined by the user, we define some
335 // platform specific flags here.
337 #if defined (TAO_IDL_PREPROCESSOR_ARGS)
338 platform_cpp_args = TAO_IDL_PREPROCESSOR_ARGS;
339 #elif defined (ACE_CC_PREPROCESSOR_ARGS)
340 platform_cpp_args = ACE_CC_PREPROCESSOR_ARGS;
341 #else
342 platform_cpp_args = "-E";
343 #endif /* TAO_IDL_PREPROCESSOR_ARGS */
345 // So we can find OMG IDL files, such as `orb.idl'.
346 ACE_CString include_path1, include_path2;
348 char* TAO_ROOT = ACE_OS::getenv ("TAO_ROOT");
350 if (TAO_ROOT != 0)
352 DRV_add_include_path (include_path1,
353 TAO_ROOT,
355 true);
357 DRV_add_include_path (include_path2,
358 TAO_ROOT,
359 "/tao",
360 true);
362 else
364 char* ACE_ROOT = ACE_OS::getenv ("ACE_ROOT");
366 if (ACE_ROOT != 0)
368 DRV_add_include_path (include_path1,
369 ACE_ROOT,
370 "/TAO",
371 true);
373 DRV_add_include_path (include_path2,
374 ACE_ROOT,
375 "/TAO/tao",
376 true);
378 else
380 #if defined (TAO_IDL_INCLUDE_DIR)
381 // TAO_IDL_INCLUDE_DIR may be in quotes,
382 // e.g. "/usr/local/include/tao"
383 // We deal with a case like this below ...
384 DRV_add_include_path (include_path1,
385 TAO_IDL_INCLUDE_DIR,
387 true);
388 DRV_add_include_path (include_path2,
389 TAO_IDL_INCLUDE_DIR,
390 "/tao",
391 true);
392 #else
393 DRV_add_include_path (include_path1,
394 ".",
396 true);
397 #endif /* TAO_IDL_INCLUDE_DIR */
401 idl_global->tao_root (include_path1.c_str ());
404 // Add any flags in platform_cpp_args to cpp's DRV_arglist.
405 ACE_ARGV platform_arglist (
406 ACE_TEXT_CHAR_TO_TCHAR (platform_cpp_args));
408 for (int i = 0; i < platform_arglist.argc (); ++i)
410 // Check for an argument that specifies
411 // the preprocessor's output file.
412 if (ACE_OS::strstr (platform_arglist[i], ACE_TEXT ("%s")) != 0
413 && output_arg_format == 0)
415 output_arg_format =
416 ACE::strnew (ACE_TEXT_ALWAYS_CHAR (platform_arglist[i]));
417 output_arg_index = DRV_argcount;
418 DRV_cpp_putarg (0);
420 else
422 DRV_cpp_putarg (ACE_TEXT_ALWAYS_CHAR (platform_arglist[i]));
428 DRV_sweep_dirs (const char *rel_path,
429 const char *base_path)
431 // Zero rel_path means we're not using this option, and
432 // so we become a no-op.
433 if (rel_path == 0)
435 return 0;
438 if (ACE_OS::chdir (rel_path) == -1)
440 ACE_ERROR_RETURN ((LM_ERROR,
441 "DRV_sweep_dirs: chdir %C failed\n",
442 rel_path),
443 -1);
446 ACE_Dirent dir (TCHAR_DIR_DOT);
447 ACE_CString bname (base_path);
448 bname += (bname.length () > 0 ? "/" : "");
449 bname += rel_path;
450 bool include_added = false;
451 char abspath[MAXPATHLEN] = "";
452 char *full_path = 0;
454 for (ACE_DIRENT *dir_entry; (dir_entry = dir.read ()) != 0;)
456 // Skip the ".." and "." files in each directory.
457 if (ACE::isdotdir (dir_entry->d_name) == true)
459 continue;
462 #if defined (ACE_HAS_TCHAR_DIRENT)
463 ACE_CString lname (ACE_TEXT_ALWAYS_CHAR (dir_entry->d_name));
464 #else
465 ACE_CString lname (dir_entry->d_name);
466 #endif
467 ACE_stat stat_buf;
469 if (ACE_OS::lstat (lname.c_str (), &stat_buf) == -1)
471 ACE_ERROR_RETURN ((LM_ERROR,
472 "DRV_sweep_dirs: ACE_OS::lstat"
473 " (%C) failed\n",
474 lname.c_str ()),
475 -1);
478 size_t len = 0;
480 switch (stat_buf.st_mode & S_IFMT)
482 case S_IFREG: // Either a regular file or an executable.
483 len = lname.length ();
485 if (len > 4 && lname.substr (len - 4) == ".idl")
487 if (!include_added)
489 ACE_CString incl_arg ("-I");
490 incl_arg += bname;
491 DRV_cpp_putarg (incl_arg.c_str ());
492 idl_global->add_rel_include_path (bname.c_str ());
493 full_path = ACE_OS::realpath ("", abspath);
495 if (full_path != 0)
497 idl_global->add_include_path (full_path,
498 false);
501 include_added = true;
504 ACE_CString fname (bname);
505 fname += "/";
506 fname += lname;
507 DRV_push_file (fname.c_str ());
510 break;
511 case S_IFDIR: // Subdirectory.
512 DRV_sweep_dirs (lname.c_str (), bname.c_str ());
513 break;
514 case S_IFLNK: // Either a file link or directory link.
515 default: // Some other type of file (PIPE/FIFO/device).
516 break;
520 // Move back up a level.
521 if (ACE_OS::chdir (DIR_DOT_DOT) == -1)
523 ACE_ERROR_RETURN ((LM_ERROR,
524 "DRV_sweep_dirs: chdir "
525 ".. (from %C) failed\n",
526 rel_path),
527 -1);
530 return 0;
533 ACE_CString&
534 DRV_add_include_path (ACE_CString& include_path,
535 const char *path,
536 const char *suffix,
537 bool is_system)
539 if (path == 0)
541 return include_path;
544 const bool needToQuote =
545 (('"' == *path) || ACE_OS::strchr (path, ' '));
546 const size_t pathLength = ACE_OS::strlen (path);
547 const char
548 #if defined (ACE_WIN32)
549 nativeDir = '\\',
550 foreignDir = '/';
551 #else
552 nativeDir = '/',
553 foreignDir = '\\';
554 #endif
556 // Eliminate possible enclosing quotes
557 // from the path, and since some compilers
558 // choke on double directory separators in
559 // paths, ensure that the path does not
560 // end with a directory slash.
561 include_path =
562 ACE_CString (path + ('"' == *path), // Skip leading Quote
563 pathLength
564 - ('"' == *path) // Don't count leading Quote
565 - ( (1uL < pathLength) && // Don't count trailing Quote XOR directory
566 ('"' == path [pathLength - 1uL] ||
567 nativeDir == path [pathLength - 1uL] ||
568 foreignDir == path [pathLength - 1uL]
570 - ( (2uL < pathLength) && // Don't count trailing Quote AND directory
571 '"' == path [pathLength - 1uL] &&
572 (nativeDir == path [pathLength - 2uL] ||
573 foreignDir == path [pathLength - 2uL]
577 if (suffix != 0)
579 if (!include_path.length ()
580 && ((nativeDir == *suffix) || (foreignDir == *suffix)))
582 // Path is empty, don't add the
583 // suffix's leading directory separator.
584 ++suffix;
587 if (include_path.length ()
588 && (*suffix != '\0')
589 && (nativeDir != *suffix)
590 && (foreignDir != *suffix))
592 // Force a directory separator.
593 include_path += nativeDir;
596 // Add the suffix string to the path,
597 // ensuring that foreign directory slashes
598 // are added as the native type.
599 for ( ; *suffix != '\0'; ++suffix)
601 include_path += (foreignDir == *suffix)
602 ? nativeDir
603 : *suffix;
607 // Build up the include string from the new path+suffix
608 ACE_CString include_option ("-I\"", 2 + needToQuote);
609 include_option+= include_path;
611 if (needToQuote)
613 include_option+= '"';
616 DRV_cpp_putarg (include_option.c_str ());
618 idl_global->add_include_path (include_path.c_str (),
619 is_system);
621 return include_path;
624 // Adds additional include paths, but after parse_args() has
625 // added user-defined include paths.
626 void
627 DRV_cpp_post_init (void)
629 char idl_version_arg[128];
630 ACE_OS::sprintf (idl_version_arg, "-D__TAO_IDL_IDL_VERSION=%s",
631 idl_global->idl_version_.to_macro ());
632 DRV_cpp_putarg (idl_version_arg);
634 DRV_cpp_putarg ("-D__TAO_IDL_FEATURES="
635 #ifdef TAO_IDL_FEATURES
636 TAO_IDL_FEATURES
637 #else
638 "\"tao/idl_features.h\""
639 #endif
642 // Add include path for TAO_ROOT/orbsvcs.
643 char* TAO_ROOT = ACE_OS::getenv ("TAO_ROOT");
645 ACE_CString include_path3, include_path4, include_path5;
647 // When adding new dirs here don't forget to update
648 // FE_Utils::validate_orb_include accordingly.
649 if (TAO_ROOT != 0)
651 DRV_add_include_path (include_path3,
652 TAO_ROOT,
653 "/orbsvcs",
654 true);
656 else
658 // If TAO_ROOT isn't defined, assume it's under ACE_ROOT.
659 char* ACE_ROOT = ACE_OS::getenv ("ACE_ROOT");
661 if (ACE_ROOT != 0)
663 DRV_add_include_path (include_path3,
664 ACE_ROOT,
665 "/TAO/orbsvcs",
666 true);
668 else
670 #if defined (TAO_IDL_INCLUDE_DIR)
671 DRV_add_include_path (include_path3,
672 TAO_IDL_INCLUDE_DIR,
673 "/orbsvcs",
674 true);
675 #else
676 // If ACE_ROOT isn't defined either, there will already
677 // be a warning from DRV_preproc().
678 DRV_add_include_path (include_path3,
679 ".",
681 true);
682 #endif /* TAO_IDL_INCLUDE_DIR */
686 // Add include paths for CIAO_ROOT and CIAO_ROOT/ciao.
687 char* CIAO_ROOT = ACE_OS::getenv ("CIAO_ROOT");
689 // When adding new dirs here don't forget to update
690 // FE_Utils::validate_orb_include accordingly.
691 if (CIAO_ROOT != 0)
693 DRV_add_include_path (include_path4,
694 CIAO_ROOT,
696 true);
698 DRV_add_include_path (include_path5,
699 CIAO_ROOT,
700 "/ciao",
701 true);
703 DRV_add_include_path (include_path5,
704 CIAO_ROOT,
705 "/ccm",
706 true);
709 // Save path of current directory, in case
710 // the call to DRV_sweep_dirs()
711 // below is not a no-op - then the current
712 // working directory will
713 // have to be restored.
714 char cwd_path[MAXPATHLEN];
716 if (ACE_OS::getcwd (cwd_path, sizeof (cwd_path)) == 0)
718 ACE_ERROR ((LM_ERROR,
719 "DRV_cpp_post_init: ACE_OS::getcwd failed\n"));
721 throw Bailout ();
724 // If first arg is non-zero, adds an include path and filename
725 // for every IDL file found in all subdirectories. This is a
726 // no-op for most backends.
727 if (DRV_sweep_dirs (idl_global->recursion_start (), "") == -1)
729 ACE_ERROR ((LM_ERROR,
730 "DRV_cpp_post_init: DRV_sweep_dirs (%C) failed\n",
731 idl_global->recursion_start ()));
733 throw Bailout ();
736 // This is redundant for most backends, but not if the call to
737 // DRV_sweep_dirs() above is more than a no-op.
738 if (ACE_OS::chdir (cwd_path) == -1)
740 ACE_ERROR ((LM_ERROR,
741 "DRV_cpp_post_init: ACE_OS::chdir (%C) failed\n",
742 cwd_path));
744 throw Bailout ();
748 // Local/internal helper function.
749 namespace
751 // Advances the input char buffer to the first non-white
752 // space character, handles /**/ comments as well.
753 char
754 DRV_skip_over_white_spaces (const char *&input)
756 while (*input != 0)
758 // Skip the spaces, tabs, vertical-tabs and form feeds.
759 while (' ' == *input ||
760 '\t' == *input ||
761 '\v' == *input ||
762 '\f' == *input)
764 ++input;
767 // Skip any "/*...*/" inline comments
768 // (Note we can't cope with fully multi-line comments since we
769 // are scanning only single lines at a time here.)
770 if ('/' != *input)
772 // This is the first non-white space character (could be
773 // end of line).
774 return *input;
777 if ('*' != *++input)
779 // Wasn't the start of a comment so / was the first non-white space character.
780 return *--input;
783 // Skip over the contents of the comment (if we reach the end of the input
784 // line we have no option but to concider the comment closed, bummer).
787 // Looking for the closing "*/" characters
788 while ('*' != *++input && *input)
791 while ('*' == *input)
793 ++input;
795 } while ('/' != *input && *input);
797 if ('/' == *input)
799 ++input;
803 return '\0'; // Reached end of line.
806 // Checks for and skips over #include, positions buffer
807 // at the leading quote character of the filename if
808 // #include is found.
809 bool
810 DRV_find_include_filename (const char *&input)
812 // Must have initial # character
813 if ('#' != DRV_skip_over_white_spaces (input))
815 return false;
818 // Only want #include to match
819 const char *include_str = "include";
821 if (*include_str != DRV_skip_over_white_spaces (++input))
823 return false;
826 while (*++include_str == *++input && *input)
829 if (*include_str || !*input)
831 // Not #include (or it ends before filename given).
832 return false;
835 // Next thing is finding the file that has been `#include'd. Skip
836 // over to the starting " or < character.
837 const char start_char = DRV_skip_over_white_spaces (input);
838 return ('"' == start_char || '<' == start_char);
841 // We really need to know whether
842 // this line is a "#include ...". If
843 // so, we would like to separate the
844 // "file name" and keep that in the
845 // idl_global. We need them to produce
846 // "#include's in the stubs and
847 // skeletons.
848 void
849 DRV_check_for_include (const char *buf)
851 if (!DRV_find_include_filename (buf))
853 return;
856 // Skip over this leading " or < and
857 // copy the filename upto the
858 // closing " or > character.
859 const char
860 start_char = *buf++,
861 end_char = ('<' == start_char) ? '>' : start_char;
863 char
864 incl_file[MAXPATHLEN + 1],
865 *fi = incl_file;
867 while (*buf != '\0' && *buf != end_char)
869 // Put Microsoft-style pathnames into a canonical form.
870 if ('\\' == buf[0] && '\\' == buf [1])
872 ++buf;
875 *fi++ = *buf++;
877 if (fi == incl_file + sizeof (incl_file) - 1)
879 // Safety valve, filename given was too long!
880 break;
884 *fi= '\0';
885 const size_t len = fi - incl_file;
887 if (len == 0)
889 return; // Null filename not allowed.
892 ACE_CString const name_str (incl_file);
893 ACE_CString const simple ("orb.idl");
894 ACE_CString const nix_path ("tao/orb.idl");
895 ACE_CString const win_path ("tao\\orb.idl");
897 // Some backends pass this file through, others don't.
898 if (name_str == simple
899 || name_str == nix_path
900 || name_str == win_path)
902 if (idl_global->pass_orb_idl ())
904 idl_global->add_to_included_idl_files (incl_file);
906 else
908 DRV_get_orb_idl_includes ();
911 // We have special lookup for orb.idl (TAO_ROOT/tao) that
912 // also kicks in for .pidl files. If one of the latter is
913 // included as a local name only, we add the 'tao/' prefix
914 // so the generated C++ include files will be correct.
915 else if ((5 <= len && !ACE_OS::strcmp (incl_file + len - 5, ".pidl"))
916 && !ACE_OS::strchr (incl_file, '/')
917 && !ACE_OS::strchr (incl_file, '\\'))
919 ACE_CString fixed_name ("tao/");
920 fixed_name += incl_file;
922 idl_global->add_to_included_idl_files (fixed_name.c_str ());
924 else
926 idl_global->add_to_included_idl_files (incl_file);
930 // This method turns a line like '#include "a.idl"' into the
931 // line '#include <a.idl>'
932 void
933 DRV_convert_includes (char *buf)
935 const char *input = buf;
937 if (!DRV_find_include_filename (input) || '"' != *input)
939 return; // Only interested in #include "" type
942 buf = const_cast<char *> (input);
944 // Find the closing '"' character.
945 char *open_quote= buf;
947 while ('"' != *++buf && *buf != '\0')
949 if ('>' == *buf)
951 // Can't change to #include <> as it
952 // has a > character in the filename!
953 return;
956 if ('"' == *buf)
958 // Replace the quotes with angle brackets.
959 *open_quote = '<';
960 *buf = '>';
963 } // End of local/internal namespace
965 void
966 DRV_get_orb_idl_includes (void)
968 static char const orb_idl[] = "tao/orb.idl";
970 // Search for orb.idl in supplied include file search paths.
971 char const * directory = 0;
972 FILE * fp = FE_Utils::open_included_file (orb_idl, directory);
974 if (fp == 0)
976 // Fall back on $TAO_ROOT/tao/orb.idl if orb.idl is not in the
977 // include path.
978 ACE_CString orb_idl_path (ACE_CString (idl_global->tao_root ())
979 + ACE_CString ('/')
980 + ACE_CString (orb_idl));
982 fp = ACE_OS::fopen (orb_idl_path.c_str (), "r");
984 if (fp == 0)
986 ACE_ERROR ((LM_ERROR,
987 "TAO_IDL: cannot open or find file: %C\n",
988 orb_idl_path.c_str ()));
990 throw Bailout ();
993 else
995 // Make sure the include directory containing orb.idl is passed
996 // to the preprocessor.
997 // This should go after user supplied include paths.
998 ACE_CString include_path_arg;
999 DRV_add_include_path (include_path_arg, directory, "/tao", true);
1002 while (DRV_get_line (fp))
1004 // Find the included .pidl files in orb.idl and add them to the
1005 // included IDL file list.
1006 DRV_check_for_include (drv_line);
1009 ACE_OS::fclose (fp);
1012 // Copy to a file.
1013 static void
1014 DRV_copy_input (FILE *fin,
1015 FILE *f,
1016 const char *fn,
1017 const char *orig_filename)
1019 if (f == 0)
1021 ACE_ERROR ((LM_ERROR,
1022 "%C: cannot open temp file \"%C\" for copying from \"%C\": %m\n",
1023 idl_global->prog_name (),
1025 orig_filename));
1027 throw Bailout ();
1030 if (fin == 0)
1032 ACE_ERROR ((LM_ERROR,
1033 "%C: cannot open input file\n",
1034 idl_global->prog_name ()));
1036 throw Bailout ();
1039 #if !defined (ACE_WIN32)
1040 ACE_OS::fprintf (f,
1041 "#line 1 \"%s\"\n",
1042 orig_filename);
1043 #else
1044 // Convert single \ into double \ otherwise MSVC++ pre-processor
1045 // gets awfully confused.
1046 char buf[2*MAXPATHLEN];
1047 char *d = buf;
1049 for (const char *s = orig_filename; *s != 0; ++s)
1051 if (*s == '\\')
1053 *d = '\\';
1054 ++d;
1057 *d = *s;
1058 ++d;
1061 *d = 0;
1062 ACE_OS::fprintf (f,
1063 "#line 1 \"%s\"\n",
1064 buf);
1065 #endif /* ! ACE_WIN32 */
1067 while (DRV_get_line (fin))
1069 DRV_convert_includes (drv_line);
1071 // Print the line to the temporary file.
1072 ACE_OS::fprintf (f,
1073 "%s\n",
1074 drv_line);
1076 // We really need to know whether this line is a "#include
1077 // ...". If so, we would like to separate the "file name" and
1078 // keep that in the idl_global. We need them to produce
1079 // "#include's in the stubs and skeletons.
1080 DRV_check_for_include (drv_line);
1083 // Close the temporary file.
1084 ACE_OS::fclose (f);
1087 // Strip down a name to the last component,
1088 // i.e. everything after the last '/' or '\' character.
1089 static char *
1090 DRV_stripped_name (char *fn)
1092 char *n = fn;
1093 size_t l;
1095 if (n == 0)
1097 return 0;
1100 l = ACE_OS::strlen (n);
1101 int slash_found = 0;
1103 for (n += l - 1; n >= fn && !slash_found; n--)
1105 slash_found = (*n == '/' || *n == '\\');
1108 n += 1;
1110 if (slash_found)
1112 n += 1;
1115 return n;
1118 // Pass input through preprocessor.
1119 void
1120 DRV_pre_proc (const char *myfile)
1122 // Check to see that the file is a normal file. If we don't and the file is a
1123 // directory, then the copy would be blank and any error message later might
1124 // not be helpful.
1125 ACE_stat file_stat;
1126 if (ACE_OS::stat (myfile, &file_stat) == -1)
1128 ACE_ERROR ((LM_ERROR,
1129 "%C: ERROR: Unable to open file (stat) \"%C\": %m\n",
1130 idl_global->prog_name (),
1131 myfile));
1132 throw Bailout ();
1134 else if ((file_stat.st_mode & S_IFREG) != S_IFREG)
1136 ACE_ERROR ((LM_ERROR,
1137 "%C: ERROR: This is not a regular file: \"%C\"\n",
1138 idl_global->prog_name (),
1139 myfile));
1140 throw Bailout ();
1143 const char* tmpdir = idl_global->temp_dir ();
1144 static const char temp_file_extension[] = ".cpp";
1146 static char const tao_idlf_template[] = "tao-idlf_XXXXXX";
1147 static char const tao_idli_template[] = "tao-idli_XXXXXX";
1149 size_t const tlen =
1150 ACE_OS::strlen (tmpdir) + sizeof (temp_file_extension);
1152 // Prevent a buffer overrun.
1153 if (tlen + sizeof (tao_idlf_template) > sizeof (tmp_file)
1154 || tlen + sizeof (tao_idli_template) > sizeof (tmp_ifile))
1156 ACE_ERROR ((LM_ERROR,
1157 "%C: temporary path/filename length is greater than "
1158 "length allowed by platform\n",
1159 idl_global->prog_name ()));
1161 throw Bailout ();
1164 ACE_OS::strcpy (tmp_file, tmpdir);
1165 ACE_OS::strcpy (tmp_ifile, tmpdir);
1167 // Append temporary filename template to temporary directory.
1168 ACE_OS::strcat (tmp_file, tao_idlf_template);
1169 ACE_OS::strcat (tmp_ifile, tao_idli_template);
1171 ACE_HANDLE const ti_fd = ACE_OS::mkstemp (tmp_ifile);
1173 if (ti_fd == ACE_INVALID_HANDLE)
1175 ACE_ERROR ((LM_ERROR,
1176 "%C: Unable to create temporary file \"%C\": %m\n",
1177 idl_global->prog_name (),
1178 tmp_ifile));
1180 throw Bailout ();
1183 ACE_HANDLE const tf_fd = ACE_OS::mkstemp (tmp_file);
1185 if (tf_fd == ACE_INVALID_HANDLE)
1187 ACE_ERROR ((LM_ERROR,
1188 "%C: Unable to create temporary file \"%C\": %m\n",
1189 idl_global->prog_name (),
1190 tmp_file));
1192 (void) ACE_OS::unlink (tmp_ifile);
1193 throw Bailout ();
1196 char tmp_cpp_file [MAXPATHLEN + 1] = { 0 };
1197 char tmp_cpp_ifile[MAXPATHLEN + 1] = { 0 };
1199 // Append C++ source file extension. Temporary files will be renamed
1200 // to these filenames.
1201 ACE_OS::strcpy (tmp_cpp_file, tmp_file);
1202 ACE_OS::strcpy (tmp_cpp_ifile, tmp_ifile);
1203 ACE_OS::strcat (tmp_cpp_file, temp_file_extension);
1204 ACE_OS::strcat (tmp_cpp_ifile, temp_file_extension);
1206 char * const t_file = tmp_cpp_file;
1207 char * const t_ifile = tmp_cpp_ifile;
1209 ACE_OS::close (tf_fd);
1211 // Rename temporary files so that they have extensions accepted
1212 // by the preprocessor.
1213 FILE * const file = ACE_OS::fopen (myfile, "r");
1214 if (file == 0)
1216 ACE_ERROR ((LM_ERROR,
1217 "%C: ERROR: Unable to open file (fopen) \"%C\": %m\n",
1218 idl_global->prog_name (),
1219 myfile));
1220 (void) ACE_OS::unlink (tmp_ifile);
1221 (void) ACE_OS::unlink (tmp_file);
1222 throw Bailout ();
1225 DRV_copy_input (file,
1226 ACE_OS::fdopen (ti_fd, ACE_TEXT("w")),
1227 tmp_ifile,
1228 myfile);
1229 ACE_OS::fclose (file);
1231 UTL_String *utl_string = 0;
1233 #if defined (ACE_OPENVMS)
1235 char main_abspath[MAXPATHLEN] = "";
1236 char trans_path[MAXPATHLEN] = "";
1237 char *main_fullpath =
1238 ACE_OS::realpath (IDL_GlobalData::translateName (myfile, trans_path),
1239 main_abspath);
1241 if (main_fullpath == 0)
1243 ACE_ERROR ((LM_ERROR,
1244 ACE_TEXT ("Unable to construct full file pathname\n")));
1246 (void) ACE_OS::unlink (tmp_ifile);
1247 (void) ACE_OS::unlink (tmp_file);
1248 throw Bailout ();
1251 ACE_NEW (utl_string,
1252 UTL_String (main_fullpath, true));
1254 idl_global->set_main_filename (utl_string);
1256 #else
1257 ACE_NEW (utl_string,
1258 UTL_String (myfile, true));
1260 idl_global->set_main_filename (utl_string);
1261 #endif
1263 ACE_Auto_String_Free safety (ACE_OS::strdup (myfile));
1265 UTL_String *stripped_tmp = 0;
1266 ACE_NEW (stripped_tmp,
1267 UTL_String (DRV_stripped_name (safety.get ()), true));
1269 idl_global->set_stripped_filename (stripped_tmp);
1271 UTL_String *real_tmp = 0;
1272 ACE_NEW (real_tmp,
1273 UTL_String (t_ifile, true));
1275 idl_global->set_real_filename (real_tmp);
1277 // We use ACE instead of the (low level) fork facilities, this also
1278 // works on NT.
1279 ACE_Process process;
1281 DRV_cpp_expand_output_arg (t_file);
1282 DRV_cpp_putarg (t_ifile);
1283 DRV_cpp_putarg (0); // Null terminate the DRV_arglist.
1285 // For complex builds, the default
1286 // command line buffer size of 1024
1287 // is often not enough. We determine
1288 // the required space and arg nr
1289 // dynamically here.
1290 ACE_Process_Options cpp_options (1, // Inherit environment.
1291 DRV_cpp_calc_total_argsize (),
1292 16 * 1024,
1293 512,
1294 DRV_argcount);
1296 if (cpp_options.command_line (DRV_arglist) != 0)
1298 ACE_ERROR ((LM_ERROR,
1299 ACE_TEXT ("%C: command line processing \"%s\" failed\n"),
1300 idl_global->prog_name (),
1301 DRV_arglist[0]));
1303 (void) ACE_OS::unlink (tmp_ifile);
1304 (void) ACE_OS::unlink (tmp_file);
1305 throw Bailout ();
1308 // Rename temporary files so that they have extensions accepted
1309 // by the preprocessor. Renaming is (supposed to be) an atomic
1310 // operation so we shouldn't be susceptible to attack.
1311 if (ACE_OS::rename (tmp_file, t_file) != 0)
1313 ACE_ERROR ((LM_ERROR,
1314 "%C: Unable to rename temporary "
1315 "file \"%C\" to \"%C\": %m\n",
1316 idl_global->prog_name (),
1317 tmp_file,
1318 t_file));
1321 (void) ACE_OS::unlink (tmp_ifile);
1322 (void) ACE_OS::unlink (tmp_file);
1323 throw Bailout ();
1326 if (ACE_OS::rename (tmp_ifile, t_ifile) != 0)
1328 ACE_ERROR ((LM_ERROR,
1329 "%C: Unable to rename temporary "
1330 "file \"%C\" to \"%C\": %m\n",
1331 idl_global->prog_name (),
1332 tmp_ifile,
1333 t_ifile));
1335 (void) ACE_OS::unlink (tmp_ifile);
1336 (void) ACE_OS::unlink (t_file);
1337 throw Bailout ();
1340 // Remove any existing output file.
1341 (void) ACE_OS::unlink (t_file);
1343 ACE_HANDLE fd = ACE_INVALID_HANDLE;
1345 if (output_arg_format == 0)
1347 // If the following open() fails, then we're either being hit with a
1348 // symbolic link attack, or another process opened the file before
1349 // us.
1350 #if defined (ACE_OPENVMS)
1351 //FUZZ: disable check_for_lack_ACE_OS
1352 fd = ::open (t_file, O_WRONLY | O_CREAT | O_EXCL,
1353 ACE_DEFAULT_FILE_PERMS,
1354 "shr=get,put,upd", "ctx=rec", "fop=dfw");
1355 //FUZZ: enable check_for_lack_ACE_OS
1356 #else
1357 fd = ACE_OS::open (t_file,
1358 O_WRONLY | O_CREAT | O_EXCL,
1359 ACE_DEFAULT_FILE_PERMS);
1360 #endif
1362 if (fd == ACE_INVALID_HANDLE)
1364 ACE_ERROR ((LM_ERROR,
1365 "%C: cannot open temp file"
1366 " \"%C\" for writing: %m\n",
1367 idl_global->prog_name (),
1368 t_file));
1370 (void) ACE_OS::unlink (t_file);
1371 (void) ACE_OS::unlink (t_ifile);
1372 throw Bailout ();
1375 if (cpp_options.set_handles (ACE_INVALID_HANDLE, fd) == -1)
1377 ACE_ERROR ((LM_ERROR, "%C: cannot set stdout for child process: %m\n",
1378 idl_global->prog_name ()));
1380 throw Bailout ();
1384 if (idl_global->compile_flags () & IDL_CF_INFORMATIVE)
1386 ACE_DEBUG ((LM_DEBUG, "%C: spawning: %s\n",
1387 idl_global->prog_name (),
1388 cpp_options.command_line_buf ()));
1391 if (process.spawn (cpp_options) == ACE_INVALID_PID)
1393 ACE_ERROR ((LM_ERROR,
1394 "%C: spawn of \"%s\" failed\n",
1395 idl_global->prog_name (),
1396 DRV_arglist[0]));
1399 (void) ACE_OS::unlink (t_file);
1400 (void) ACE_OS::unlink (t_ifile);
1401 throw Bailout ();
1404 if (fd != ACE_INVALID_HANDLE)
1406 // Close the output file on the parent process.
1407 if (ACE_OS::close (fd) == -1)
1409 ACE_ERROR ((LM_ERROR,
1410 "%C: cannot close temp file \"%C\" on parent: %m\n",
1411 idl_global->prog_name (),
1412 t_file));
1414 (void) ACE_OS::unlink (t_file);
1415 (void) ACE_OS::unlink (t_ifile);
1416 throw Bailout ();
1420 // Remove the null termination and the
1421 // input file from the DRV_arglist,
1422 // the next file will the previous args.
1423 DRV_argcount -= 2;
1424 ACE::strdelete (
1425 const_cast<ACE_TCHAR *> (DRV_arglist[DRV_argcount]));
1426 DRV_arglist[DRV_argcount] = 0;
1427 ACE_exitcode status = 0;
1429 if (process.wait (&status) == ACE_INVALID_PID)
1431 ACE_ERROR ((LM_ERROR,
1432 "%C: wait for child process failed\n",
1433 idl_global->prog_name ()));
1435 (void) ACE_OS::unlink (t_file);
1436 (void) ACE_OS::unlink (t_ifile);
1437 throw Bailout ();
1440 if (WIFEXITED ((status)))
1442 // Child terminated normally?
1443 if (WEXITSTATUS ((status)) != 0)
1445 errno = WEXITSTATUS ((status));
1447 ACE_ERROR ((LM_ERROR,
1448 "%C: preprocessor \"%s\" "
1449 "returned with an error\n",
1450 idl_global->prog_name (),
1451 DRV_arglist[0]));
1453 (void) ACE_OS::unlink (t_file);
1454 (void) ACE_OS::unlink (t_ifile);
1455 throw Bailout ();
1458 else
1460 // Child didn't call exit(); perhaps it received a signal?
1461 errno = EINTR;
1463 ACE_ERROR ((LM_ERROR,
1464 "%C: preprocessor \"%s\" appears "
1465 "to have been interrupted\n",
1466 idl_global->prog_name (),
1467 DRV_arglist[0]));
1469 (void) ACE_OS::unlink (t_file);
1470 (void) ACE_OS::unlink (t_ifile);
1471 throw Bailout ();
1473 // TODO: Manage problems in the
1474 // pre-processor, in the previous
1475 // version the current process
1476 // would exit if the pre-processor
1477 // returned with error.
1479 #if defined (ACE_OPENVMS)
1480 cpp_options.release_handles();
1481 #endif
1483 FILE * const yyin = ACE_OS::fopen (t_file, "r");
1485 if (yyin == 0)
1487 ACE_ERROR ((LM_ERROR,
1488 "%C: Could not open cpp "
1489 "output file \"%C\": %m\n",
1490 idl_global->prog_name (),
1491 t_file));
1493 (void) ACE_OS::unlink (t_file);
1494 (void) ACE_OS::unlink (t_ifile);
1495 throw Bailout ();
1498 FE_set_yyin (yyin);
1500 if (idl_global->compile_flags () & IDL_CF_ONLY_PREPROC)
1502 FILE *preproc = ACE_OS::fopen (t_file, "r");
1503 char buffer[ACE_MAXLOGMSGLEN];
1504 size_t bytes;
1506 if (preproc == 0)
1508 ACE_ERROR ((LM_ERROR,
1509 "%C: Could not open cpp "
1510 "output file \"%C\": %m\n",
1511 idl_global->prog_name (),
1512 t_file));
1514 (void) ACE_OS::unlink (t_file);
1515 (void) ACE_OS::unlink (t_ifile);
1516 throw Bailout ();
1519 // ACE_DEBUG sends to stderr - we want stdout for this dump
1520 // of the preprocessor output. So we modify the singleton that
1521 // was created in this process. Since IDL_CF_ONLY_PREPROC causes
1522 // an (almost) immediate exit below, we don't have to restore
1523 // the singleton's default parameters.
1524 ACE_Log_Msg *out = ACE_Log_Msg::instance ();
1525 out->msg_ostream (&cout);
1526 out->clr_flags (ACE_Log_Msg::STDERR);
1527 out->set_flags (ACE_Log_Msg::OSTREAM);
1529 while ((bytes = ACE_OS::fread (buffer,
1530 sizeof (char),
1531 ACE_MAXLOGMSGLEN - 1,
1532 preproc))
1533 != 0)
1535 buffer[bytes] = 0;
1536 ACE_DEBUG ((LM_DEBUG, buffer));
1539 ACE_OS::fclose (preproc);
1542 if (ACE_OS::unlink (t_ifile) == -1)
1544 ACE_ERROR ((LM_ERROR,
1545 "%C: Could not remove cpp "
1546 "input file \"%C\": %m\n",
1547 idl_global->prog_name (),
1548 t_ifile));
1550 throw Bailout ();
1553 if (ACE_OS::unlink (t_file) == -1)
1555 ACE_ERROR ((LM_ERROR,
1556 "%C: Could not remove cpp "
1557 "output file \"%C\": %m\n",
1558 idl_global->prog_name (),
1559 t_file));
1561 throw Bailout ();