Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / TAO / TAO_IDL / driver / drv_preproc.cpp
bloba26c09cce3a496aaa518932ed7e7dd5e0bc0fdf0
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.h"
77 #include "ace/SString.h"
78 #include "ace/Env_Value_T.h"
79 #include "ace/ARGV.h"
80 #include "ace/Dirent.h"
81 #include "ace/OS_NS_sys_stat.h"
82 #include "ace/Truncate.h"
84 // FUZZ: disable check_for_streams_include
85 #include "ace/streams.h"
87 #include "ace/OS_NS_stdio.h"
88 #include "ace/OS_NS_unistd.h"
89 #include "ace/OS_NS_fcntl.h"
90 #include "ace/OS_NS_sys_stat.h"
92 // Storage for preprocessor args.
93 unsigned long const DRV_MAX_ARGCOUNT = 1024;
94 unsigned long DRV_argcount = 0;
95 ACE_TCHAR const * DRV_arglist[DRV_MAX_ARGCOUNT] = { nullptr };
97 static char const * output_arg_format = nullptr;
98 static long output_arg_index = 0;
100 ACE_TCHAR const TCHAR_DIR_DOT[] = ACE_TEXT(".");
102 #if defined (ACE_HAS_TCHAR_DIRENT)
103 // ACE_TCHAR const DIR_DOT[] = ACE_TEXT(".");
104 ACE_TCHAR const DIR_DOT_DOT[] = ACE_TEXT("..");
105 #else
106 // char const DIR_DOT[] = ".";
107 char const DIR_DOT_DOT[] = "..";
108 #endif /* ACE_HAS_TCHAR_DIRENT */
110 // File names.
111 static char tmp_file [MAXPATHLEN + 1] = { 0 };
112 static char tmp_ifile[MAXPATHLEN + 1] = { 0 };
114 // Lines can be 1024 chars long intially -
115 // it will expand as required.
116 #define LINEBUF_SIZE 1024
117 char* drv_line = nullptr;
118 static size_t drv_line_size = LINEBUF_SIZE + 1;
120 // Push the new CPP location if we got a -Yp argument.
121 void
122 DRV_cpp_new_location (char const * new_loc)
124 ACE::strdelete (const_cast<ACE_TCHAR *> (DRV_arglist[0]));
125 DRV_arglist[0] =
126 ACE::strnew (ACE_TEXT_CHAR_TO_TCHAR (new_loc));
129 // Push an argument into the DRV_arglist.
130 void
131 DRV_cpp_putarg (const char *str)
133 if (DRV_argcount >= DRV_MAX_ARGCOUNT)
135 ACE_ERROR ((LM_ERROR,
136 "%C: More than %d arguments to preprocessor\n",
137 idl_global->prog_name (),
138 DRV_MAX_ARGCOUNT ));
140 throw Bailout ();
143 char *replace = nullptr;
144 if (str)
146 bool allocate_error = false;
148 #ifdef ACE_WIN32
149 const char *const first_quote = ACE_OS::strchr (str, '"');
150 if (first_quote)
152 // Escape Doublequotes on Windows
154 size_t quote_count = 0;
155 for (const char *quote = first_quote; quote; quote = ACE_OS::strchr (quote, '"'))
157 ++quote_count;
158 ++quote;
161 ACE_NEW_NORETURN (replace, char[ACE_OS::strlen (str) + quote_count + 1]);
162 allocate_error = !replace;
163 if (replace)
165 char *to = replace;
166 for (const char *from = str; *from; ++from)
168 if (*from == '"')
170 *to = '\\';
171 ++to;
173 *to = *from;
174 ++to;
176 *to = '\0';
179 #endif
180 if (ACE_OS::strchr (str, ' '))
182 ACE_NEW_NORETURN (replace, char[ACE_OS::strlen (str) + 3]);
183 allocate_error = !replace;
184 if (replace)
186 replace[0] = '"';
187 ACE_OS::strcpy (replace + 1, str);
188 ACE_OS::strcat (replace, "\"");
192 if (allocate_error)
194 idl_global->err()->misc_error ("DRV_cpp_putarg failed to allocate memory for argument!");
195 throw Bailout ();
199 DRV_arglist[DRV_argcount++] = ACE::strnew (ACE_TEXT_CHAR_TO_TCHAR (replace ? replace : str));
201 if (replace)
203 delete [] replace;
204 replace = nullptr;
208 // Expand the output argument with the given filename.
209 void
210 DRV_cpp_expand_output_arg (const char *filename)
212 if (output_arg_format != nullptr)
214 ACE::strdelete (const_cast<ACE_TCHAR *> (
215 DRV_arglist[output_arg_index]));
216 DRV_arglist[output_arg_index] = nullptr;
218 ACE_NEW (DRV_arglist[output_arg_index],
219 ACE_TCHAR [ACE_OS::strlen (output_arg_format)
220 + ACE_OS::strlen (filename)
221 + 1]);
223 ACE_OS::sprintf (const_cast<ACE_TCHAR *> (
224 DRV_arglist[output_arg_index]),
225 ACE_TEXT_CHAR_TO_TCHAR (output_arg_format),
226 ACE_TEXT_CHAR_TO_TCHAR (filename));
230 // calculate the total size of all commandline arguments
231 unsigned int
232 DRV_cpp_calc_total_argsize()
234 unsigned long size = 0;
235 unsigned long ix = 0;
236 while (DRV_arglist[ix] != nullptr)
238 size += ACE_Utils::truncate_cast<unsigned long> (ACE_OS::strlen (DRV_arglist[ix]) + 1);
239 ++ix;
241 return size;
244 // Get a line from stdin.
245 static bool
246 DRV_get_line (FILE *file)
248 char *line = ACE_OS::fgets (drv_line,
249 ACE_Utils::truncate_cast<int> (drv_line_size),
250 file);
251 if (!line || (!*line && feof (file)))
253 // End of file, nothing else read in.
254 return false;
259 // Check for line continuation escape...
260 size_t len = ACE_OS::strlen (drv_line);
261 if (2 <= len &&
262 '\n' == drv_line [len-1] &&
263 '\\' == drv_line [len-2] )
265 // This is a "false" end-of-line, remove token
266 len-= 2;
267 drv_line [len]= '\0';
270 // Check for end-of-line
271 if (len && '\n' == drv_line [len-1])
273 // Replace the end-of-line with a null
274 drv_line [len-1] = '\0';
275 return true;
278 // Need to continue to read more of this line in,
279 // is there enough space left in the buffer?
280 if (drv_line_size - len < 10)
282 // Create a bigger buffer
283 size_t temp_size = drv_line_size * 2;
284 char *temp = nullptr;
285 ACE_NEW_RETURN (temp, char [temp_size], false);
286 ACE_OS::strcpy (temp, drv_line);
287 delete [] drv_line;
288 drv_line = temp;
289 drv_line_size = temp_size;
292 line = ACE_OS::fgets (drv_line + len,
293 ACE_Utils::truncate_cast<int> (drv_line_size - len),
294 file);
295 } while (line && *line);
297 return true;
300 // Initialize the cpp argument list.
301 void
302 DRV_cpp_init ()
304 // Create the line buffer.
305 // (JP) Deleting this at the end or DRV_pre_proc() causes
306 // Purify to output a Freeing Mismatched Memory warning.
307 // When it is not deleted (currently the case) there is no
308 // memory leak reported by Purify. I don't know why.
309 ACE_NEW (drv_line,
310 char [drv_line_size]);
312 char const * const cpp_loc = FE_get_cpp_loc_from_env ();
313 DRV_cpp_putarg (cpp_loc);
315 // Add an option to the IDL compiler to make the TAO version
316 // available to the user. A XX.YY.ZZ release gets
317 // version 0xXXYYZZ, for example, 5.1.14 gets 0x050114.
318 char version_option[128];
319 ACE_OS::sprintf (version_option,
320 "-D__TAO_IDL=0x%2.2d%2.2d%2.2d",
321 ACE_MAJOR_VERSION,
322 ACE_MINOR_VERSION,
323 ACE_MICRO_VERSION);
325 DRV_cpp_putarg (version_option);
326 DRV_cpp_putarg ("-I.");
328 const char *platform_cpp_args =
329 FE_get_cpp_args_from_env ();
331 if (platform_cpp_args == nullptr)
333 // If no cpp flag was defined by the user, we define some
334 // platform specific flags here.
336 #if defined (TAO_IDL_PREPROCESSOR_ARGS)
337 platform_cpp_args = TAO_IDL_PREPROCESSOR_ARGS;
338 #elif defined (ACE_CC_PREPROCESSOR_ARGS)
339 platform_cpp_args = ACE_CC_PREPROCESSOR_ARGS;
340 #else
341 platform_cpp_args = "-E";
342 #endif /* TAO_IDL_PREPROCESSOR_ARGS */
344 // So we can find OMG IDL files, such as `orb.idl'.
345 ACE_CString include_path1, include_path2;
347 char* TAO_ROOT = ACE_OS::getenv ("TAO_ROOT");
349 if (TAO_ROOT != nullptr)
351 DRV_add_include_path (include_path1,
352 TAO_ROOT,
353 nullptr,
354 true);
356 DRV_add_include_path (include_path2,
357 TAO_ROOT,
358 "/tao",
359 true);
361 else
363 char* ACE_ROOT = ACE_OS::getenv ("ACE_ROOT");
365 if (ACE_ROOT != nullptr)
367 DRV_add_include_path (include_path1,
368 ACE_ROOT,
369 "/TAO",
370 true);
372 DRV_add_include_path (include_path2,
373 ACE_ROOT,
374 "/TAO/tao",
375 true);
377 else
379 #if defined (TAO_IDL_INCLUDE_DIR)
380 // TAO_IDL_INCLUDE_DIR may be in quotes,
381 // e.g. "/usr/local/include/tao"
382 // We deal with a case like this below ...
383 DRV_add_include_path (include_path1,
384 TAO_IDL_INCLUDE_DIR,
386 true);
387 DRV_add_include_path (include_path2,
388 TAO_IDL_INCLUDE_DIR,
389 "/tao",
390 true);
391 #else
392 DRV_add_include_path (include_path1,
393 ".",
394 nullptr,
395 true);
396 #endif /* TAO_IDL_INCLUDE_DIR */
400 idl_global->tao_root (include_path1.c_str ());
403 // Add any flags in platform_cpp_args to cpp's DRV_arglist.
404 ACE_ARGV platform_arglist (
405 ACE_TEXT_CHAR_TO_TCHAR (platform_cpp_args));
407 for (int i = 0; i < platform_arglist.argc (); ++i)
409 // Check for an argument that specifies
410 // the preprocessor's output file.
411 if (ACE_OS::strstr (platform_arglist[i], ACE_TEXT ("%s")) != nullptr
412 && output_arg_format == nullptr)
414 output_arg_format =
415 ACE::strnew (ACE_TEXT_ALWAYS_CHAR (platform_arglist[i]));
416 output_arg_index = DRV_argcount;
417 DRV_cpp_putarg (nullptr);
419 else
421 DRV_cpp_putarg (ACE_TEXT_ALWAYS_CHAR (platform_arglist[i]));
427 DRV_sweep_dirs (const char *rel_path,
428 const char *base_path)
430 // Zero rel_path means we're not using this option, and
431 // so we become a no-op.
432 if (rel_path == nullptr)
434 return 0;
437 if (ACE_OS::chdir (rel_path) == -1)
439 ACE_ERROR_RETURN ((LM_ERROR,
440 "DRV_sweep_dirs: chdir %C failed\n",
441 rel_path),
442 -1);
445 ACE_Dirent dir (TCHAR_DIR_DOT);
446 ACE_CString bname (base_path);
447 bname += (bname.length () > 0 ? "/" : "");
448 bname += rel_path;
449 bool include_added = false;
450 char abspath[MAXPATHLEN] = "";
451 char *full_path = nullptr;
453 for (ACE_DIRENT *dir_entry; (dir_entry = dir.read ()) != nullptr;)
455 // Skip the ".." and "." files in each directory.
456 if (ACE::isdotdir (dir_entry->d_name) == true)
458 continue;
461 #if defined (ACE_HAS_TCHAR_DIRENT)
462 ACE_CString lname (ACE_TEXT_ALWAYS_CHAR (dir_entry->d_name));
463 #else
464 ACE_CString lname (dir_entry->d_name);
465 #endif
466 ACE_stat stat_buf;
468 if (ACE_OS::lstat (lname.c_str (), &stat_buf) == -1)
470 ACE_ERROR_RETURN ((LM_ERROR,
471 "DRV_sweep_dirs: ACE_OS::lstat"
472 " (%C) failed\n",
473 lname.c_str ()),
474 -1);
477 size_t len = 0;
479 switch (stat_buf.st_mode & S_IFMT)
481 case S_IFREG: // Either a regular file or an executable.
482 len = lname.length ();
484 if (len > 4 && lname.substr (len - 4) == ".idl")
486 if (!include_added)
488 ACE_CString incl_arg ("-I");
489 incl_arg += bname;
490 DRV_cpp_putarg (incl_arg.c_str ());
491 idl_global->add_rel_include_path (bname.c_str ());
492 full_path = ACE_OS::realpath ("", abspath);
494 if (full_path != nullptr)
496 idl_global->add_include_path (full_path,
497 false);
500 include_added = true;
503 ACE_CString fname (bname);
504 fname += "/";
505 fname += lname;
506 DRV_push_file (fname.c_str ());
509 break;
510 case S_IFDIR: // Subdirectory.
511 DRV_sweep_dirs (lname.c_str (), bname.c_str ());
512 break;
513 case S_IFLNK: // Either a file link or directory link.
514 default: // Some other type of file (PIPE/FIFO/device).
515 break;
519 // Move back up a level.
520 if (ACE_OS::chdir (DIR_DOT_DOT) == -1)
522 ACE_ERROR_RETURN ((LM_ERROR,
523 "DRV_sweep_dirs: chdir "
524 ".. (from %C) failed\n",
525 rel_path),
526 -1);
529 return 0;
532 ACE_CString&
533 DRV_add_include_path (ACE_CString& include_path,
534 const char *path,
535 const char *suffix,
536 bool is_system)
538 if (path == nullptr)
540 return include_path;
543 const bool needToQuote =
544 (('"' == *path) || ACE_OS::strchr (path, ' '));
545 const size_t pathLength = ACE_OS::strlen (path);
546 const char
547 #if defined (ACE_WIN32)
548 nativeDir = '\\',
549 foreignDir = '/';
550 #else
551 nativeDir = '/',
552 foreignDir = '\\';
553 #endif
555 // Eliminate possible enclosing quotes
556 // from the path, and since some compilers
557 // choke on double directory separators in
558 // paths, ensure that the path does not
559 // end with a directory slash.
560 include_path =
561 ACE_CString (path + ('"' == *path), // Skip leading Quote
562 pathLength
563 - ('"' == *path) // Don't count leading Quote
564 - ( (1uL < pathLength) && // Don't count trailing Quote XOR directory
565 ('"' == path [pathLength - 1uL] ||
566 nativeDir == path [pathLength - 1uL] ||
567 foreignDir == path [pathLength - 1uL]
569 - ( (2uL < pathLength) && // Don't count trailing Quote AND directory
570 '"' == path [pathLength - 1uL] &&
571 (nativeDir == path [pathLength - 2uL] ||
572 foreignDir == path [pathLength - 2uL]
576 if (suffix != nullptr)
578 if (!include_path.length ()
579 && ((nativeDir == *suffix) || (foreignDir == *suffix)))
581 // Path is empty, don't add the
582 // suffix's leading directory separator.
583 ++suffix;
586 if (include_path.length ()
587 && (*suffix != '\0')
588 && (nativeDir != *suffix)
589 && (foreignDir != *suffix))
591 // Force a directory separator.
592 include_path += nativeDir;
595 // Add the suffix string to the path,
596 // ensuring that foreign directory slashes
597 // are added as the native type.
598 for ( ; *suffix != '\0'; ++suffix)
600 include_path += (foreignDir == *suffix)
601 ? nativeDir
602 : *suffix;
606 // Build up the include string from the new path+suffix
607 ACE_CString include_option ("-I\"", 2 + needToQuote);
608 include_option+= include_path;
610 if (needToQuote)
612 include_option+= '"';
615 DRV_cpp_putarg (include_option.c_str ());
617 idl_global->add_include_path (include_path.c_str (),
618 is_system);
620 return include_path;
623 // Adds additional include paths, but after parse_args() has
624 // added user-defined include paths.
625 void
626 DRV_cpp_post_init ()
628 char idl_version_arg[128];
629 ACE_OS::sprintf (idl_version_arg, "-D__TAO_IDL_IDL_VERSION=%s",
630 idl_global->idl_version_.to_macro ());
631 DRV_cpp_putarg (idl_version_arg);
633 DRV_cpp_putarg ("-D__TAO_IDL_FEATURES="
634 #ifdef TAO_IDL_FEATURES
635 TAO_IDL_FEATURES
636 #else
637 "\"tao/idl_features.h\""
638 #endif
641 // Add include path for TAO_ROOT/orbsvcs.
642 char* TAO_ROOT = ACE_OS::getenv ("TAO_ROOT");
644 ACE_CString include_path3, include_path4, include_path5;
646 // When adding new dirs here don't forget to update
647 // FE_Utils::validate_orb_include accordingly.
648 if (TAO_ROOT != nullptr)
650 DRV_add_include_path (include_path3,
651 TAO_ROOT,
652 "/orbsvcs",
653 true);
655 else
657 // If TAO_ROOT isn't defined, assume it's under ACE_ROOT.
658 char* ACE_ROOT = ACE_OS::getenv ("ACE_ROOT");
660 if (ACE_ROOT != nullptr)
662 DRV_add_include_path (include_path3,
663 ACE_ROOT,
664 "/TAO/orbsvcs",
665 true);
667 else
669 #if defined (TAO_IDL_INCLUDE_DIR)
670 DRV_add_include_path (include_path3,
671 TAO_IDL_INCLUDE_DIR,
672 "/orbsvcs",
673 true);
674 #else
675 // If ACE_ROOT isn't defined either, there will already
676 // be a warning from DRV_preproc().
677 DRV_add_include_path (include_path3,
678 ".",
679 nullptr,
680 true);
681 #endif /* TAO_IDL_INCLUDE_DIR */
685 // Add include paths for CIAO_ROOT and CIAO_ROOT/ciao.
686 char* CIAO_ROOT = ACE_OS::getenv ("CIAO_ROOT");
688 // When adding new dirs here don't forget to update
689 // FE_Utils::validate_orb_include accordingly.
690 if (CIAO_ROOT != nullptr)
692 DRV_add_include_path (include_path4,
693 CIAO_ROOT,
694 nullptr,
695 true);
697 DRV_add_include_path (include_path5,
698 CIAO_ROOT,
699 "/ciao",
700 true);
702 DRV_add_include_path (include_path5,
703 CIAO_ROOT,
704 "/ccm",
705 true);
708 // Save path of current directory, in case
709 // the call to DRV_sweep_dirs()
710 // below is not a no-op - then the current
711 // working directory will
712 // have to be restored.
713 char cwd_path[MAXPATHLEN];
715 if (ACE_OS::getcwd (cwd_path, sizeof (cwd_path)) == nullptr)
717 ACE_ERROR ((LM_ERROR,
718 "DRV_cpp_post_init: ACE_OS::getcwd failed\n"));
720 throw Bailout ();
723 // If first arg is non-zero, adds an include path and filename
724 // for every IDL file found in all subdirectories. This is a
725 // no-op for most backends.
726 if (DRV_sweep_dirs (idl_global->recursion_start (), "") == -1)
728 ACE_ERROR ((LM_ERROR,
729 "DRV_cpp_post_init: DRV_sweep_dirs (%C) failed\n",
730 idl_global->recursion_start ()));
732 throw Bailout ();
735 // This is redundant for most backends, but not if the call to
736 // DRV_sweep_dirs() above is more than a no-op.
737 if (ACE_OS::chdir (cwd_path) == -1)
739 ACE_ERROR ((LM_ERROR,
740 "DRV_cpp_post_init: ACE_OS::chdir (%C) failed\n",
741 cwd_path));
743 throw Bailout ();
747 // Local/internal helper function.
748 namespace
750 // Advances the input char buffer to the first non-white
751 // space character, handles /**/ comments as well.
752 char
753 DRV_skip_over_white_spaces (const char *&input)
755 while (*input != 0)
757 // Skip the spaces, tabs, vertical-tabs and form feeds.
758 while (' ' == *input ||
759 '\t' == *input ||
760 '\v' == *input ||
761 '\f' == *input)
763 ++input;
766 // Skip any "/*...*/" inline comments
767 // (Note we can't cope with fully multi-line comments since we
768 // are scanning only single lines at a time here.)
769 if ('/' != *input)
771 // This is the first non-white space character (could be
772 // end of line).
773 return *input;
776 if ('*' != *++input)
778 // Wasn't the start of a comment so / was the first non-white space character.
779 return *--input;
782 // Skip over the contents of the comment (if we reach the end of the input
783 // line we have no option but to concider the comment closed, bummer).
786 // Looking for the closing "*/" characters
787 while ('*' != *++input && *input)
790 while ('*' == *input)
792 ++input;
794 } while ('/' != *input && *input);
796 if ('/' == *input)
798 ++input;
802 return '\0'; // Reached end of line.
805 // Checks for and skips over #include, positions buffer
806 // at the leading quote character of the filename if
807 // #include is found.
808 bool
809 DRV_find_include_filename (const char *&input)
811 // Must have initial # character
812 if ('#' != DRV_skip_over_white_spaces (input))
814 return false;
817 // Only want #include to match
818 const char *include_str = "include";
820 if (*include_str != DRV_skip_over_white_spaces (++input))
822 return false;
825 while (*++include_str == *++input && *input)
828 if (*include_str || !*input)
830 // Not #include (or it ends before filename given).
831 return false;
834 // Next thing is finding the file that has been `#include'd. Skip
835 // over to the starting " or < character.
836 const char start_char = DRV_skip_over_white_spaces (input);
837 return ('"' == start_char || '<' == start_char);
840 // We really need to know whether
841 // this line is a "#include ...". If
842 // so, we would like to separate the
843 // "file name" and keep that in the
844 // idl_global. We need them to produce
845 // "#include's in the stubs and
846 // skeletons.
847 void
848 DRV_check_for_include (const char *buf)
850 if (!DRV_find_include_filename (buf))
852 return;
855 // Skip over this leading " or < and
856 // copy the filename upto the
857 // closing " or > character.
858 const char
859 start_char = *buf++,
860 end_char = ('<' == start_char) ? '>' : start_char;
862 char
863 incl_file[MAXPATHLEN + 1],
864 *fi = incl_file;
866 while (*buf != '\0' && *buf != end_char)
868 // Put Microsoft-style pathnames into a canonical form.
869 if ('\\' == buf[0] && '\\' == buf [1])
871 ++buf;
874 *fi++ = *buf++;
876 if (fi == incl_file + sizeof (incl_file) - 1)
878 // Safety valve, filename given was too long!
879 break;
883 *fi= '\0';
884 const size_t len = fi - incl_file;
886 if (len == 0)
888 return; // Null filename not allowed.
891 ACE_CString const name_str (incl_file);
892 ACE_CString const simple ("orb.idl");
893 ACE_CString const nix_path ("tao/orb.idl");
894 ACE_CString const win_path ("tao\\orb.idl");
896 // Some backends pass this file through, others don't.
897 if (name_str == simple
898 || name_str == nix_path
899 || name_str == win_path)
901 if (idl_global->pass_orb_idl ())
903 idl_global->add_to_included_idl_files (incl_file);
905 else
907 DRV_get_orb_idl_includes ();
910 // We have special lookup for orb.idl (TAO_ROOT/tao) that
911 // also kicks in for .pidl files. If one of the latter is
912 // included as a local name only, we add the 'tao/' prefix
913 // so the generated C++ include files will be correct.
914 else if ((5 <= len && !ACE_OS::strcmp (incl_file + len - 5, ".pidl"))
915 && !ACE_OS::strchr (incl_file, '/')
916 && !ACE_OS::strchr (incl_file, '\\'))
918 ACE_CString fixed_name ("tao/");
919 fixed_name += incl_file;
921 idl_global->add_to_included_idl_files (fixed_name.c_str ());
923 else
925 idl_global->add_to_included_idl_files (incl_file);
929 // This method turns a line like '#include "a.idl"' into the
930 // line '#include <a.idl>'
931 void
932 DRV_convert_includes (char *buf)
934 const char *input = buf;
936 if (!DRV_find_include_filename (input) || '"' != *input)
938 return; // Only interested in #include "" type
941 buf = const_cast<char *> (input);
943 // Find the closing '"' character.
944 char *open_quote= buf;
946 while ('"' != *++buf && *buf != '\0')
948 if ('>' == *buf)
950 // Can't change to #include <> as it
951 // has a > character in the filename!
952 return;
955 if ('"' == *buf)
957 // Replace the quotes with angle brackets.
958 *open_quote = '<';
959 *buf = '>';
962 } // End of local/internal namespace
964 void
965 DRV_get_orb_idl_includes ()
967 static char const orb_idl[] = "tao/orb.idl";
969 // Search for orb.idl in supplied include file search paths.
970 char const * directory = nullptr;
971 FILE * fp = FE_Utils::open_included_file (orb_idl, directory);
973 if (fp == nullptr)
975 // Fall back on $TAO_ROOT/tao/orb.idl if orb.idl is not in the
976 // include path.
977 ACE_CString orb_idl_path (ACE_CString (idl_global->tao_root ())
978 + ACE_CString ('/')
979 + ACE_CString (orb_idl));
981 fp = ACE_OS::fopen (orb_idl_path.c_str (), "r");
983 if (fp == nullptr)
985 ACE_ERROR ((LM_ERROR,
986 "TAO_IDL: cannot open or find file: %C\n",
987 orb_idl_path.c_str ()));
989 throw Bailout ();
992 else
994 // Make sure the include directory containing orb.idl is passed
995 // to the preprocessor.
996 // This should go after user supplied include paths.
997 ACE_CString include_path_arg;
998 DRV_add_include_path (include_path_arg, directory, "/tao", true);
1001 while (DRV_get_line (fp))
1003 // Find the included .pidl files in orb.idl and add them to the
1004 // included IDL file list.
1005 DRV_check_for_include (drv_line);
1008 ACE_OS::fclose (fp);
1011 // Copy to a file.
1012 static void
1013 DRV_copy_input (FILE *fin,
1014 FILE *f,
1015 const char *fn,
1016 const char *orig_filename)
1018 if (f == nullptr)
1020 ACE_ERROR ((LM_ERROR,
1021 "%C: cannot open temp file \"%C\" for copying from \"%C\": %m\n",
1022 idl_global->prog_name (),
1024 orig_filename));
1026 throw Bailout ();
1029 if (fin == nullptr)
1031 ACE_ERROR ((LM_ERROR,
1032 "%C: cannot open input file\n",
1033 idl_global->prog_name ()));
1035 throw Bailout ();
1038 #if !defined (ACE_WIN32)
1039 ACE_OS::fprintf (f,
1040 "#line 1 \"%s\"\n",
1041 orig_filename);
1042 #else
1043 // Convert single \ into double \ otherwise MSVC++ pre-processor
1044 // gets awfully confused.
1045 char buf[2*MAXPATHLEN];
1046 char *d = buf;
1048 for (const char *s = orig_filename; *s != 0; ++s)
1050 if (*s == '\\')
1052 *d = '\\';
1053 ++d;
1056 *d = *s;
1057 ++d;
1060 *d = 0;
1061 ACE_OS::fprintf (f,
1062 "#line 1 \"%s\"\n",
1063 buf);
1064 #endif /* ! ACE_WIN32 */
1066 while (DRV_get_line (fin))
1068 DRV_convert_includes (drv_line);
1070 // Print the line to the temporary file.
1071 ACE_OS::fprintf (f,
1072 "%s\n",
1073 drv_line);
1075 // We really need to know whether this line is a "#include
1076 // ...". If so, we would like to separate the "file name" and
1077 // keep that in the idl_global. We need them to produce
1078 // "#include's in the stubs and skeletons.
1079 DRV_check_for_include (drv_line);
1082 // Close the temporary file.
1083 ACE_OS::fclose (f);
1086 // Strip down a name to the last component,
1087 // i.e. everything after the last '/' or '\' character.
1088 static char *
1089 DRV_stripped_name (char *fn)
1091 char *n = fn;
1092 size_t l;
1094 if (n == nullptr)
1096 return nullptr;
1099 l = ACE_OS::strlen (n);
1100 int slash_found = 0;
1102 for (n += l - 1; n >= fn && !slash_found; n--)
1104 slash_found = (*n == '/' || *n == '\\');
1107 n += 1;
1109 if (slash_found)
1111 n += 1;
1114 return n;
1117 // Pass input through preprocessor.
1118 void
1119 DRV_pre_proc (const char *myfile)
1121 // Check to see that the file is a normal file. If we don't and the file is a
1122 // directory, then the copy would be blank and any error message later might
1123 // not be helpful.
1124 ACE_stat file_stat;
1125 if (ACE_OS::stat (myfile, &file_stat) == -1)
1127 ACE_ERROR ((LM_ERROR,
1128 "%C: ERROR: Unable to open file (stat) \"%C\": %m\n",
1129 idl_global->prog_name (),
1130 myfile));
1131 throw Bailout ();
1133 else if ((file_stat.st_mode & S_IFREG) != S_IFREG)
1135 ACE_ERROR ((LM_ERROR,
1136 "%C: ERROR: This is not a regular file: \"%C\"\n",
1137 idl_global->prog_name (),
1138 myfile));
1139 throw Bailout ();
1142 const char* tmpdir = idl_global->temp_dir ();
1143 static const char temp_file_extension[] = ".cpp";
1145 static char const tao_idlf_template[] = "tao-idlf_XXXXXX";
1146 static char const tao_idli_template[] = "tao-idli_XXXXXX";
1148 size_t const tlen =
1149 ACE_OS::strlen (tmpdir) + sizeof (temp_file_extension);
1151 // Prevent a buffer overrun.
1152 if (tlen + sizeof (tao_idlf_template) > sizeof (tmp_file)
1153 || tlen + sizeof (tao_idli_template) > sizeof (tmp_ifile))
1155 ACE_ERROR ((LM_ERROR,
1156 "%C: temporary path/filename length is greater than "
1157 "length allowed by platform\n",
1158 idl_global->prog_name ()));
1160 throw Bailout ();
1163 ACE_OS::strcpy (tmp_file, tmpdir);
1164 ACE_OS::strcpy (tmp_ifile, tmpdir);
1166 // Append temporary filename template to temporary directory.
1167 ACE_OS::strcat (tmp_file, tao_idlf_template);
1168 ACE_OS::strcat (tmp_ifile, tao_idli_template);
1170 ACE_HANDLE const ti_fd = ACE_OS::mkstemp (tmp_ifile);
1172 if (ti_fd == ACE_INVALID_HANDLE)
1174 ACE_ERROR ((LM_ERROR,
1175 "%C: Unable to create temporary file \"%C\": %m\n",
1176 idl_global->prog_name (),
1177 tmp_ifile));
1179 throw Bailout ();
1182 ACE_HANDLE const tf_fd = ACE_OS::mkstemp (tmp_file);
1184 if (tf_fd == ACE_INVALID_HANDLE)
1186 ACE_ERROR ((LM_ERROR,
1187 "%C: Unable to create temporary file \"%C\": %m\n",
1188 idl_global->prog_name (),
1189 tmp_file));
1191 (void) ACE_OS::unlink (tmp_ifile);
1192 throw Bailout ();
1195 char tmp_cpp_file [MAXPATHLEN + 1] = { 0 };
1196 char tmp_cpp_ifile[MAXPATHLEN + 1] = { 0 };
1198 // Append C++ source file extension. Temporary files will be renamed
1199 // to these filenames.
1200 ACE_OS::strcpy (tmp_cpp_file, tmp_file);
1201 ACE_OS::strcpy (tmp_cpp_ifile, tmp_ifile);
1202 ACE_OS::strcat (tmp_cpp_file, temp_file_extension);
1203 ACE_OS::strcat (tmp_cpp_ifile, temp_file_extension);
1205 char * const t_file = tmp_cpp_file;
1206 char * const t_ifile = tmp_cpp_ifile;
1208 ACE_OS::close (tf_fd);
1210 // Rename temporary files so that they have extensions accepted
1211 // by the preprocessor.
1212 FILE * const file = ACE_OS::fopen (myfile, "r");
1213 if (file == nullptr)
1215 ACE_ERROR ((LM_ERROR,
1216 "%C: ERROR: Unable to open file (fopen) \"%C\": %m\n",
1217 idl_global->prog_name (),
1218 myfile));
1219 (void) ACE_OS::unlink (tmp_ifile);
1220 (void) ACE_OS::unlink (tmp_file);
1221 throw Bailout ();
1224 DRV_copy_input (file,
1225 ACE_OS::fdopen (ti_fd, ACE_TEXT("w")),
1226 tmp_ifile,
1227 myfile);
1228 ACE_OS::fclose (file);
1230 UTL_String *utl_string = nullptr;
1232 ACE_NEW (utl_string,
1233 UTL_String (myfile, true));
1235 idl_global->set_main_filename (utl_string);
1237 ACE_Auto_String_Free safety (ACE_OS::strdup (myfile));
1239 UTL_String *stripped_tmp = nullptr;
1240 ACE_NEW (stripped_tmp,
1241 UTL_String (DRV_stripped_name (safety.get ()), true));
1243 idl_global->set_stripped_filename (stripped_tmp);
1245 UTL_String *real_tmp = nullptr;
1246 ACE_NEW (real_tmp,
1247 UTL_String (t_ifile, true));
1249 idl_global->set_real_filename (real_tmp);
1251 // We use ACE instead of the (low level) fork facilities, this also
1252 // works on NT.
1253 ACE_Process process;
1255 DRV_cpp_expand_output_arg (t_file);
1256 DRV_cpp_putarg (t_ifile);
1257 DRV_cpp_putarg (nullptr); // Null terminate the DRV_arglist.
1259 // For complex builds, the default
1260 // command line buffer size of 1024
1261 // is often not enough. We determine
1262 // the required space and arg nr
1263 // dynamically here.
1264 ACE_Process_Options cpp_options (true, // Inherit environment.
1265 DRV_cpp_calc_total_argsize (),
1266 16 * 1024,
1267 512,
1268 DRV_argcount);
1270 if (cpp_options.command_line (DRV_arglist) != 0)
1272 ACE_ERROR ((LM_ERROR,
1273 ACE_TEXT ("%C: command line processing \"%s\" failed\n"),
1274 idl_global->prog_name (),
1275 DRV_arglist[0]));
1277 (void) ACE_OS::unlink (tmp_ifile);
1278 (void) ACE_OS::unlink (tmp_file);
1279 throw Bailout ();
1282 // Rename temporary files so that they have extensions accepted
1283 // by the preprocessor. Renaming is (supposed to be) an atomic
1284 // operation so we shouldn't be susceptible to attack.
1285 if (ACE_OS::rename (tmp_file, t_file) != 0)
1287 ACE_ERROR ((LM_ERROR,
1288 "%C: Unable to rename temporary "
1289 "file \"%C\" to \"%C\": %m\n",
1290 idl_global->prog_name (),
1291 tmp_file,
1292 t_file));
1295 (void) ACE_OS::unlink (tmp_ifile);
1296 (void) ACE_OS::unlink (tmp_file);
1297 throw Bailout ();
1300 if (ACE_OS::rename (tmp_ifile, t_ifile) != 0)
1302 ACE_ERROR ((LM_ERROR,
1303 "%C: Unable to rename temporary "
1304 "file \"%C\" to \"%C\": %m\n",
1305 idl_global->prog_name (),
1306 tmp_ifile,
1307 t_ifile));
1309 (void) ACE_OS::unlink (tmp_ifile);
1310 (void) ACE_OS::unlink (t_file);
1311 throw Bailout ();
1314 // Remove any existing output file.
1315 (void) ACE_OS::unlink (t_file);
1317 ACE_HANDLE fd = ACE_INVALID_HANDLE;
1319 if (output_arg_format == nullptr)
1321 // If the following open() fails, then we're either being hit with a
1322 // symbolic link attack, or another process opened the file before
1323 // us.
1324 fd = ACE_OS::open (t_file,
1325 O_WRONLY | O_CREAT | O_EXCL,
1326 ACE_DEFAULT_FILE_PERMS);
1328 if (fd == ACE_INVALID_HANDLE)
1330 ACE_ERROR ((LM_ERROR,
1331 "%C: cannot open temp file"
1332 " \"%C\" for writing: %m\n",
1333 idl_global->prog_name (),
1334 t_file));
1336 (void) ACE_OS::unlink (t_file);
1337 (void) ACE_OS::unlink (t_ifile);
1338 throw Bailout ();
1341 if (cpp_options.set_handles (ACE_INVALID_HANDLE, fd) == -1)
1343 ACE_ERROR ((LM_ERROR, "%C: cannot set stdout for child process: %m\n",
1344 idl_global->prog_name ()));
1346 throw Bailout ();
1350 if (idl_global->compile_flags () & IDL_CF_INFORMATIVE)
1352 ACE_DEBUG ((LM_DEBUG, "%C: spawning: %s\n",
1353 idl_global->prog_name (),
1354 cpp_options.command_line_buf ()));
1357 if (process.spawn (cpp_options) == ACE_INVALID_PID)
1359 ACE_ERROR ((LM_ERROR,
1360 "%C: spawn of \"%s\" failed\n",
1361 idl_global->prog_name (),
1362 DRV_arglist[0]));
1365 (void) ACE_OS::unlink (t_file);
1366 (void) ACE_OS::unlink (t_ifile);
1367 throw Bailout ();
1370 if (fd != ACE_INVALID_HANDLE)
1372 // Close the output file on the parent process.
1373 if (ACE_OS::close (fd) == -1)
1375 ACE_ERROR ((LM_ERROR,
1376 "%C: cannot close temp file \"%C\" on parent: %m\n",
1377 idl_global->prog_name (),
1378 t_file));
1380 (void) ACE_OS::unlink (t_file);
1381 (void) ACE_OS::unlink (t_ifile);
1382 throw Bailout ();
1386 // Remove the null termination and the
1387 // input file from the DRV_arglist,
1388 // the next file will the previous args.
1389 DRV_argcount -= 2;
1390 ACE::strdelete (
1391 const_cast<ACE_TCHAR *> (DRV_arglist[DRV_argcount]));
1392 DRV_arglist[DRV_argcount] = nullptr;
1393 ACE_exitcode status = 0;
1395 if (process.wait (&status) == ACE_INVALID_PID)
1397 ACE_ERROR ((LM_ERROR,
1398 "%C: wait for child process failed\n",
1399 idl_global->prog_name ()));
1401 (void) ACE_OS::unlink (t_file);
1402 (void) ACE_OS::unlink (t_ifile);
1403 throw Bailout ();
1406 if (WIFEXITED ((status)))
1408 // Child terminated normally?
1409 if (WEXITSTATUS ((status)) != 0)
1411 errno = WEXITSTATUS ((status));
1413 ACE_ERROR ((LM_ERROR,
1414 "%C: preprocessor \"%s\" "
1415 "returned with an error\n",
1416 idl_global->prog_name (),
1417 DRV_arglist[0]));
1419 (void) ACE_OS::unlink (t_file);
1420 (void) ACE_OS::unlink (t_ifile);
1421 throw Bailout ();
1424 else
1426 // Child didn't call exit(); perhaps it received a signal?
1427 errno = EINTR;
1429 ACE_ERROR ((LM_ERROR,
1430 "%C: preprocessor \"%s\" appears "
1431 "to have been interrupted\n",
1432 idl_global->prog_name (),
1433 DRV_arglist[0]));
1435 (void) ACE_OS::unlink (t_file);
1436 (void) ACE_OS::unlink (t_ifile);
1437 throw Bailout ();
1439 // TODO: Manage problems in the
1440 // pre-processor, in the previous
1441 // version the current process
1442 // would exit if the pre-processor
1443 // returned with error.
1444 FILE * const yyin = ACE_OS::fopen (t_file, "r");
1446 if (yyin == nullptr)
1448 ACE_ERROR ((LM_ERROR,
1449 "%C: Could not open cpp "
1450 "output file \"%C\": %m\n",
1451 idl_global->prog_name (),
1452 t_file));
1454 (void) ACE_OS::unlink (t_file);
1455 (void) ACE_OS::unlink (t_ifile);
1456 throw Bailout ();
1459 FE_set_yyin (yyin);
1461 if (idl_global->compile_flags () & IDL_CF_ONLY_PREPROC)
1463 FILE *preproc = ACE_OS::fopen (t_file, "r");
1464 char buffer[ACE_MAXLOGMSGLEN];
1465 size_t bytes;
1467 if (preproc == nullptr)
1469 ACE_ERROR ((LM_ERROR,
1470 "%C: Could not open cpp "
1471 "output file \"%C\": %m\n",
1472 idl_global->prog_name (),
1473 t_file));
1475 (void) ACE_OS::unlink (t_file);
1476 (void) ACE_OS::unlink (t_ifile);
1477 throw Bailout ();
1480 // ACE_DEBUG sends to stderr - we want stdout for this dump
1481 // of the preprocessor output. So we modify the singleton that
1482 // was created in this process. Since IDL_CF_ONLY_PREPROC causes
1483 // an (almost) immediate exit below, we don't have to restore
1484 // the singleton's default parameters.
1485 ACE_Log_Msg *out = ACE_Log_Msg::instance ();
1486 out->msg_ostream (&cout);
1487 out->clr_flags (ACE_Log_Msg::STDERR);
1488 out->set_flags (ACE_Log_Msg::OSTREAM);
1490 while ((bytes = ACE_OS::fread (buffer,
1491 sizeof (char),
1492 ACE_MAXLOGMSGLEN - 1,
1493 preproc))
1494 != 0)
1496 buffer[bytes] = 0;
1497 ACE_DEBUG ((LM_DEBUG, buffer));
1500 ACE_OS::fclose (preproc);
1503 if (ACE_OS::unlink (t_ifile) == -1)
1505 ACE_ERROR ((LM_ERROR,
1506 "%C: Could not remove cpp "
1507 "input file \"%C\": %m\n",
1508 idl_global->prog_name (),
1509 t_ifile));
1511 throw Bailout ();
1514 if (ACE_OS::unlink (t_file) == -1)
1516 ACE_ERROR ((LM_ERROR,
1517 "%C: Could not remove cpp "
1518 "output file \"%C\": %m\n",
1519 idl_global->prog_name (),
1520 t_file));
1522 throw Bailout ();