1 #include "Shapes_Kernel_decls.h"
3 #include "simplepdfi.h"
4 #include "simplepdfo.h"
7 #include "shapesexceptions.h"
10 #include "continuations.h"
11 #include "charconverters.h"
12 #include "pagecontentstates.h"
13 #include "autoonoff.h"
14 #include "shapesscanner.h"
15 #include "texlabelmanager.h"
31 extern int shapesdebug
;
34 using namespace Shapes
;
35 using namespace SimplePDF
;
37 void argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
);
38 bool strprefixcmp( char * str
, const char * prefix
, char ** endp
);
39 bool strtobool( const char * str
, const char * containingString
, const char * trueLabel
= 0, const char * falseLabel
= 0 );
41 std::string
absoluteFilename( const char * filename
);
42 std::string
absoluteDirectory( const char * filename
);
43 void ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
);
44 RefCountPtr
< std::ifstream
> performIterativeStartup( const std::string
& texJobName
);
45 void abortProcedure( int exitCode
);
47 enum XpdfAction
{ XPDF_DEFAULT
, XPDF_RAISE
, XPDF_RELOAD
, XPDF_QUIT
, XPDF_NOSERVER
};
48 void xpdfHelper( const std::string
& filename
, const std::string
& server
, const XpdfAction
& action
);
49 void openHelper( const std::string
& filename
, const char * application
);
50 void addDefaultNeedPath( );
51 void addDefaultFontMetricsPath( );
52 void destroyGlobals( );
53 void escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
);
59 void systemDebugMessage( const std::string
& msg
);
64 main( int argc
, char ** argv
)
70 bool iterativeMode
= true;
71 bool useResources
= true;
74 char * cwd
= getcwd( 0, 0 );
75 callDir
= cwd
+ std::string( "/" );
81 bool allowCreateTmpDir
= false;
83 std::string inputName
;
84 std::string outputName
;
85 std::string texJobName
;
86 std::string labelDBName
;
87 std::string fontmetricsOutputName
;
89 enum FilenameRequests
{ FILENAME_RESOURCE
, FILENAME_IN
, FILENAME_OUT
, FILENAME_TMP
, FILENAME_TEXJOB
, FILENAME_LABELDB
, FILENAME_AFM
, FILENAME_TEXINPUTS
, FILENAME_HTMLDOC
};
91 std::list
< int > filenameRequestList
;
92 std::list
< const char * > resourceRequestList
;
94 bool evalTrace
= false;
95 bool evalBackTrace
= false;
96 bool cleanupMemory
= true;
97 bool memoryStats
= false;
98 bool launch_xpdf
= false;
99 SimplePDF::PDF_Version::Version pdfVersion
= SimplePDF::PDF_Version::VERSION_UNDEFINED
;
100 SimplePDF::PDF_Version::Action pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
101 XpdfAction xpdfAction
= XPDF_DEFAULT
;
102 std::string xpdfServer
;
103 bool do_open
= false;
104 const char * do_open_application
= 0;
105 std::ostringstream prependStreamOut
;
107 enum SplitMode
{ SPLIT_NO
, SPLIT_FLAT
, SPLIT_DIR
};
108 SplitMode splitMode
= SPLIT_NO
;
115 if( strcmp( *argv
, "--yydebug" ) == 0 )
121 else if( strcmp( *argv
, "--shapes-debug" ) == 0 )
127 else if( strcmp( *argv
, "--system-debug" ) == 0 )
129 Interaction::debugSystem
= true;
133 else if( strcmp( *argv
, "--afm-debug" ) == 0 )
135 Interaction::fontMetricDebug
= true;
139 else if( strcmp( *argv
, "--afm-messages" ) == 0 )
141 Interaction::fontMetricMessages
= true;
145 else if( strcmp( *argv
, "--tex-debug" ) == 0 )
147 Interaction::pdfLaTeXInteractionTo_stderr
= true;
151 else if( strcmp( *argv
, "--log-globals" ) == 0 )
153 Interaction::logGlobals
= true;
157 else if( strprefixcmp( *argv
, "--bytecolumn=", & optionSuffix
) )
159 Interaction::characterColumnInBytes
= strtobool( optionSuffix
, *argv
);
163 else if( strprefixcmp( *argv
, "--debugstep=", & optionSuffix
) )
166 int tmp
= strtol( optionSuffix
, & endp
, 10 );
169 std::cerr
<< "The --debugstep value must be nonnegative: " << optionSuffix
<< std::endl
;
170 exit( Interaction::EXIT_INVOCATION_ERROR
);
172 Interaction::debugStep
= static_cast< size_t >( tmp
);
176 else if( strcmp( *argv
, "--debuglog" ) == 0 )
178 argcAssertion( *argv
, argc
, 2 );
181 Kernel::theDebugLog
.setFilename( *( argv
+ 1 ) );
183 catch( const char * ball
)
185 std::cerr
<< ball
<< std::endl
;
186 exit( Interaction::EXIT_INVOCATION_ERROR
);
191 else if( strcmp( *argv
, "--debuglog-stderr" ) == 0 )
195 Kernel::theDebugLog
.setStream( & std::cerr
);
197 catch( const char * ball
)
199 std::cerr
<< ball
<< std::endl
;
200 exit( Interaction::EXIT_INVOCATION_ERROR
);
205 else if( strcmp( *argv
, "--debuglog-stdout" ) == 0 )
209 Kernel::theDebugLog
.setStream( & std::cout
);
211 catch( const char * ball
)
213 std::cerr
<< ball
<< std::endl
;
214 exit( Interaction::EXIT_INVOCATION_ERROR
);
219 else if( strprefixcmp( *argv
, "--dtminerror=", & optionSuffix
) )
221 Computation::dtMinIsError
= strtobool( optionSuffix
, *argv
);
225 else if( strprefixcmp( *argv
, "--fmguesserror=", & optionSuffix
) )
227 Computation::fontMetricGuessIsError
= strtobool( optionSuffix
, *argv
);
231 else if( strcmp( *argv
, "--evaltrace" ) == 0 )
237 else if( strcmp( *argv
, "--evalbacktrace" ) == 0 )
240 evalBackTrace
= true;
244 else if( strprefixcmp( *argv
, "--backtrace=", & optionSuffix
) )
246 Interaction::debugBacktrace
= strtobool( optionSuffix
, *argv
);
250 else if( strprefixcmp( *argv
, "--iteration=", & optionSuffix
) )
252 iterativeMode
= strtobool( optionSuffix
, *argv
);
256 else if( strprefixcmp( *argv
, "--resources=", & optionSuffix
) )
258 useResources
= strtobool( optionSuffix
, *argv
);
262 else if( strprefixcmp( *argv
, "--stats=", & optionSuffix
) )
264 memoryStats
= strtobool( optionSuffix
, *argv
);
268 else if( strprefixcmp( *argv
, "--memclean=", & optionSuffix
) )
270 cleanupMemory
= strtobool( optionSuffix
, *argv
);
274 else if( strprefixcmp( *argv
, "--showfiles=", & optionSuffix
) )
276 Ast::theShapesScanner
.setShowFiles( strtobool( optionSuffix
, *argv
) );
280 else if( strprefixcmp( *argv
, "--pdf-version=", & optionSuffix
) || /* Note that we use that || shortcuts! */
281 strprefixcmp( *argv
, "-v", & optionSuffix
) )
283 if( pdfVersion
!= SimplePDF::PDF_Version::VERSION_UNDEFINED
)
285 std::cerr
<< "Multiply defined pdf version." << std::endl
;
286 exit( Interaction::EXIT_INVOCATION_ERROR
);
289 switch( *optionSuffix
)
292 pdfVersionAction
= SimplePDF::PDF_Version::ERROR
;
295 pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
298 pdfVersionAction
= SimplePDF::PDF_Version::SILENT
;
301 std::cerr
<< "The only allowed action-characters in the pdf version specification are: \"e\" (error), \"w\" (warn), and \"s\" (silent). You said \"" << *optionSuffix
<< "\", being the first character in \"" << optionSuffix
<< "\"." << std::endl
;
302 exit( Interaction::EXIT_INVOCATION_ERROR
);
305 if( strncmp( optionSuffix
, "1.", 2 ) == 0 &&
306 '1' <= optionSuffix
[2] && optionSuffix
[2] <= '6' )
308 SimplePDF::PDF_Version::Version versions
[] = { SimplePDF::PDF_Version::PDF_1_1
, SimplePDF::PDF_Version::PDF_1_2
, SimplePDF::PDF_Version::PDF_1_3
, SimplePDF::PDF_Version::PDF_1_4
, SimplePDF::PDF_Version::PDF_1_5
, SimplePDF::PDF_Version::PDF_1_6
};
309 pdfVersion
= versions
[ optionSuffix
[2] - '1' ];
311 else if( strcmp( optionSuffix
, "X" ) == 0 )
313 std::cerr
<< "Restriction to PDF-X is not implemented, please try using a low version number, such as 1.1 instead." << std::endl
;
317 std::cerr
<< "Unsupported pdf version specification: " << optionSuffix
<< std::endl
;
318 exit( Interaction::EXIT_INVOCATION_ERROR
);
323 else if( strprefixcmp( *argv
, "--tp=", & optionSuffix
) )
325 Kernel::allowTransparency
= strtobool( optionSuffix
, *argv
);
329 else if( strprefixcmp( *argv
, "--spot-pair=", & optionSuffix
) )
331 Kernel::allowSingletonPaths
= ! strtobool( optionSuffix
, *argv
);
335 else if( strprefixcmp( *argv
, "--unit=", & optionSuffix
) )
337 Interaction::displayUnitName
= optionSuffix
;
342 else if( strprefixcmp( *argv
, "--splicingtol=", & optionSuffix
) )
345 Computation::theTrixelizeSplicingTol
= strtod( optionSuffix
, &endp
);
348 std::cerr
<< "Argument to --splicingtol= was not a float: " << optionSuffix
<< std::endl
;
349 exit( Interaction::EXIT_INVOCATION_ERROR
);
351 if( Computation::theTrixelizeSplicingTol
<= 0 )
353 std::cerr
<< "Argument to --splicingtol not positive: " << Computation::theTrixelizeSplicingTol
.offtype
< 1, 0 >( ) << std::endl
;
354 exit( Interaction::EXIT_INVOCATION_ERROR
);
360 else if( strprefixcmp( *argv
, "--overlaptol=", & optionSuffix
) )
363 Computation::theTrixelizeOverlapTol
= strtod( optionSuffix
, &endp
);
366 std::cerr
<< "Argument to --overlaptol was not a float: " << optionSuffix
<< std::endl
;
367 exit( Interaction::EXIT_INVOCATION_ERROR
);
369 if( Computation::theTrixelizeOverlapTol
<= 0 )
371 std::cerr
<< "Argument to --overlaptol not positive: " << Computation::theTrixelizeOverlapTol
.offtype
< 1, 0 >( ) << std::endl
;
372 exit( Interaction::EXIT_INVOCATION_ERROR
);
378 else if( strcmp( *argv
, "--needpath" ) == 0 ||
379 strncmp( *argv
, "-N", 2 ) == 0 )
381 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
383 const char * pth
= 0;
386 argcAssertion( *argv
, argc
, 2 );
394 if( strchr( pth
, ':' ) != 0 )
396 const char * flag
= 0;
397 const char * shortFlag
= "-N";
407 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
410 std::cerr
<< " (or " << shortFlag
<< ")" ;
412 std::cerr
<<"." << std::endl
;
413 exit( Interaction::EXIT_INVOCATION_ERROR
);
416 Ast::theShapesScanner
.push_backNeedPath( absoluteDirectory( pth
) );
429 else if( strcmp( *argv
, "--fontmetricspath" ) == 0 ||
430 strncmp( *argv
, "-M", 2 ) == 0 )
432 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
434 const char * pth
= 0;
437 argcAssertion( *argv
, argc
, 2 );
445 if( strchr( pth
, ':' ) != 0 )
447 const char * flag
= 0;
448 const char * shortFlag
= "-M";
458 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
461 std::cerr
<< " (or " << shortFlag
<< ")" ;
463 std::cerr
<<"." << std::endl
;
464 exit( Interaction::EXIT_INVOCATION_ERROR
);
467 Lang::Font::push_backFontMetricsPath( absoluteDirectory( pth
) );
480 else if( strprefixcmp( *argv
, "--seed=", & optionSuffix
) )
483 long s
= strtol( optionSuffix
, &endp
, 10 );
486 std::cerr
<< "Argument to --seed= was not an integer: " << optionSuffix
<< std::endl
;
487 exit( Interaction::EXIT_INVOCATION_ERROR
);
495 else if( strprefixcmp( *argv
, "--arcdelta=", & optionSuffix
) )
498 Computation::the_arcdelta
= strtod( optionSuffix
, &endp
);
501 std::cerr
<< "Argument to --arcdelta= was not a float: " << optionSuffix
<< std::endl
;
502 exit( Interaction::EXIT_INVOCATION_ERROR
);
504 if( Computation::the_arcdelta
<= 0 )
506 std::cerr
<< "Argument to --arcdelta= not positive: " << Computation::the_arcdelta
.offtype
< 1, 0 >( ) << std::endl
;
507 exit( Interaction::EXIT_INVOCATION_ERROR
);
513 else if( strprefixcmp( *argv
, "--dtmin=", & optionSuffix
) )
516 Computation::the_dtMin
= strtod( optionSuffix
, &endp
);
519 std::cerr
<< "Argument to --dtmin= was not a float: " << optionSuffix
<< std::endl
;
520 exit( Interaction::EXIT_INVOCATION_ERROR
);
522 if( Computation::the_dtMin
<= 0 )
524 std::cerr
<< "Argument to --dtmin= not positive: " << Computation::the_dtMin
<< std::endl
;
525 exit( Interaction::EXIT_INVOCATION_ERROR
);
531 else if( strcmp( *argv
, "--prepend" ) == 0 )
533 argcAssertion( *argv
, argc
, 2 );
534 prependStreamOut
<< *( argv
+ 1 ) << std::endl
;
538 else if( strcmp( *argv
, "--base" ) == 0 )
540 argcAssertion( *argv
, argc
, 2 );
543 std::cerr
<< "The name base is multiply specified." << std::endl
;
544 exit( Interaction::EXIT_INVOCATION_ERROR
);
546 baseName
= *( argv
+ 1 );
550 else if( strcmp( *argv
, "--which" ) == 0 )
552 argcAssertion( *argv
, argc
, 2 );
553 filenameRequestList
.push_back( FILENAME_RESOURCE
);
554 resourceRequestList
.push_back( *( argv
+ 1 ) );
558 else if( strcmp( *argv
, "--in" ) == 0 )
560 argcAssertion( *argv
, argc
, 2 );
561 if( inputName
!= "" )
563 std::cerr
<< "The input file is multiply specified." << std::endl
;
564 exit( Interaction::EXIT_INVOCATION_ERROR
);
566 inputName
= absoluteFilename( *( argv
+ 1 ) );
570 else if( strcmp( *argv
, "--which-in" ) == 0 )
572 filenameRequestList
.push_back( FILENAME_IN
);
576 else if( strcmp( *argv
, "--out" ) == 0 )
578 argcAssertion( *argv
, argc
, 2 );
579 if( outputName
!= "" )
581 std::cerr
<< "The output file is multiply specified." << std::endl
;
582 exit( Interaction::EXIT_INVOCATION_ERROR
);
584 outputName
= absoluteFilename( *( argv
+ 1 ) );
588 else if( strcmp( *argv
, "--which-out" ) == 0 )
590 filenameRequestList
.push_back( FILENAME_OUT
);
594 else if( strcmp( *argv
, "--texjob" ) == 0 )
596 argcAssertion( *argv
, argc
, 2 );
597 if( texJobName
!= "" )
599 std::cerr
<< "The tex job name is multiply specified." << std::endl
;
600 exit( Interaction::EXIT_INVOCATION_ERROR
);
602 texJobName
= *( argv
+ 1 );
603 if( texJobName
.find( '/' ) != std::string::npos
)
605 std::cerr
<< "The tex job name may not include directory specification. Please use --tmpdir to set the directory where the tex job is carried out." << std::endl
;
606 exit( Interaction::EXIT_INVOCATION_ERROR
);
611 else if( strcmp( *argv
, "--which-texjob" ) == 0 )
613 filenameRequestList
.push_back( FILENAME_TEXJOB
);
617 else if( strcmp( *argv
, "--labeldb" ) == 0 )
619 argcAssertion( *argv
, argc
, 2 );
620 if( labelDBName
!= "" )
622 std::cerr
<< "The label database file is multiply specified." << std::endl
;
623 exit( Interaction::EXIT_INVOCATION_ERROR
);
625 labelDBName
= absoluteFilename( *( argv
+ 1 ) );
629 else if( strcmp( *argv
, "--which-labeldb" ) == 0 )
631 filenameRequestList
.push_back( FILENAME_LABELDB
);
635 else if( strcmp( *argv
, "--afmout" ) == 0 )
637 argcAssertion( *argv
, argc
, 2 );
638 if( fontmetricsOutputName
!= "" )
640 std::cerr
<< "The font metrics output name is multiply specified." << std::endl
;
641 exit( Interaction::EXIT_INVOCATION_ERROR
);
643 fontmetricsOutputName
= absoluteFilename( *( argv
+ 1 ) );
647 else if( strcmp( *argv
, "--which-afmout" ) == 0 )
649 filenameRequestList
.push_back( FILENAME_AFM
);
653 else if( strcmp( *argv
, "--which-TEXINPUTS" ) == 0 )
655 filenameRequestList
.push_back( FILENAME_TEXINPUTS
);
659 else if( strcmp( *argv
, "--which-doc" ) == 0 )
661 filenameRequestList
.push_back( FILENAME_HTMLDOC
);
665 else if( strcmp( *argv
, "--outdir" ) == 0 )
667 argcAssertion( *argv
, argc
, 2 );
670 std::cerr
<< "The output directory is multiply specified." << std::endl
;
671 exit( Interaction::EXIT_INVOCATION_ERROR
);
673 outDir
= absoluteDirectory( *( argv
+ 1 ) );
677 else if( strprefixcmp( *argv
, "--tmp*=", & optionSuffix
) )
679 allowCreateTmpDir
= strtobool( optionSuffix
, *argv
);
683 else if( strcmp( *argv
, "--tmpdir" ) == 0 )
685 argcAssertion( *argv
, argc
, 2 );
688 std::cerr
<< "The temporaries directory is multiply specified." << std::endl
;
689 exit( Interaction::EXIT_INVOCATION_ERROR
);
691 tmpDir
= absoluteDirectory( *( argv
+ 1 ) );
695 else if( strcmp( *argv
, "--which-tmp" ) == 0 )
697 filenameRequestList
.push_back( FILENAME_TMP
);
701 else if( strprefixcmp( *argv
, "--split=", & optionSuffix
) )
703 if( strcmp( optionSuffix
, "no" ) == 0 )
705 splitMode
= SPLIT_NO
;
707 else if( strcmp( optionSuffix
, "flat" ) == 0 )
709 splitMode
= SPLIT_FLAT
;
711 else if( strcmp( optionSuffix
, "dir" ) == 0 )
713 splitMode
= SPLIT_DIR
;
717 std::cerr
<< "The string \"" << optionSuffix
<< "\" in the command line argument \"" << *argv
<< "\" was not any of { 'no', 'flat', 'dir' }." << std::endl
;
722 else if( strcmp( *argv
, "--xpdf" ) == 0 )
728 else if( strcmp( *argv
, "--xpdf-remote" ) == 0 )
730 argcAssertion( *argv
, argc
, 2 );
731 if( xpdfServer
!= "" )
733 std::cerr
<< "The xpdf server is multiply specified." << std::endl
;
734 exit( Interaction::EXIT_INVOCATION_ERROR
);
736 xpdfServer
= *( argv
+ 1 );
740 else if( strcmp( *argv
, "--xpdf-no-server" ) == 0 )
742 if( xpdfAction
!= XPDF_DEFAULT
)
744 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
745 exit( Interaction::EXIT_INVOCATION_ERROR
);
747 xpdfAction
= XPDF_NOSERVER
;
751 else if( strcmp( *argv
, "--xpdf-reload" ) == 0 )
753 if( xpdfAction
!= XPDF_DEFAULT
)
755 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
756 exit( Interaction::EXIT_INVOCATION_ERROR
);
758 xpdfAction
= XPDF_RELOAD
;
762 else if( strcmp( *argv
, "--xpdf-quit" ) == 0 )
764 if( xpdfAction
!= XPDF_DEFAULT
)
766 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
767 exit( Interaction::EXIT_INVOCATION_ERROR
);
769 xpdfAction
= XPDF_QUIT
;
773 else if( strcmp( *argv
, "--open" ) == 0 )
779 else if( strcmp( *argv
, "--open-a" ) == 0 )
781 argcAssertion( *argv
, argc
, 2 );
783 do_open_application
= *( argv
+ 1 );
787 else if( strcmp( *argv
, "--version" ) == 0 )
790 exit( Interaction::EXIT_OK
);
796 std::cerr
<< "The name base is multiply specified." << std::endl
;
797 exit( Interaction::EXIT_INVOCATION_ERROR
);
800 if( stat( *argv
, & theStat
) == 0 &&
801 ( theStat
.st_mode
& S_IFDIR
) == 0 ) /* We are not interested in directories here. */
804 char * ext
= *argv
+ strlen( *argv
) - 6;
807 std::cerr
<< "The file name \"" << *argv
<< "\" is unexpectedly short (it should include the \".shape\" suffix)." << std::endl
;
808 exit( Interaction::EXIT_INVOCATION_ERROR
);
810 if( strcmp( ext
, ".shape" ) != 0 )
812 std::cerr
<< "Expected \".shape\" suffix in the file name \"" << *argv
<< "\"." << std::endl
;
813 exit( Interaction::EXIT_INVOCATION_ERROR
);
818 if( (*argv
)[ strlen( *argv
) - 1 ] == '.' )
820 inputName
= std::string( *argv
) + "shape";
824 inputName
= std::string( *argv
) + ".shape";
826 if( ! stat( inputName
.c_str( ), & theStat
) == 0 )
828 /* It is not entirely clear what is the best error message here,
829 * as the source file may be specified in several different ways.
830 * This should cause the least confusion.
832 std::cerr
<< "Failed to locate input file: " << *argv
<< std::endl
;
833 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
837 const char * slash
= strrchr( inputName
.c_str( ), '/' );
840 slash
= inputName
.c_str( );
846 size_t skipCount
= slash
- inputName
.c_str( );
847 baseName
= inputName
.substr( skipCount
, inputName
.length( ) - skipCount
- 6 );
854 std::cerr
<< "Illegal command line option: " << *argv
<< std::endl
;
855 exit( Interaction::EXIT_INVOCATION_ERROR
);
861 outDir
= absoluteDirectory( "" );
865 char * start
= getenv( "SHAPESTMPDIR" );
868 tmpDir
= absoluteDirectory( start
);
872 tmpDir
= absoluteDirectory( "" );
875 ensureTmpDirectoryExists( tmpDir
, allowCreateTmpDir
);
879 if( texJobName
== "" )
881 texJobName
= "#shapes.labels";
886 if( inputName
== "" )
888 inputName
= absoluteFilename( ( baseName
+ ".shape" ).c_str( ) );
890 if( outputName
== "" )
892 if( splitMode
== SPLIT_NO
)
894 outputName
= outDir
+ baseName
+ ".pdf";
898 outputName
= outDir
+ baseName
;
901 if( texJobName
== "" )
903 texJobName
= baseName
+ ".labels";
905 if( labelDBName
== "" )
907 labelDBName
= outDir
+ baseName
+ ".labels.pdf";
909 if( fontmetricsOutputName
== "" )
911 fontmetricsOutputName
= outDir
+ baseName
+ ".afm";
915 if( outputName
== "" )
917 if( ! filenameRequestList
.empty( ) )
919 /* The output name will never really be used, so it's rather harmless to assign a dummy value.
921 outputName
= "?.pdf" ;
925 std::cerr
<< "The output file is undetermined. Consider specifying it using \"--out <filename>\"." << std::endl
;
926 exit( Interaction::EXIT_INVOCATION_ERROR
);
930 if( labelDBName
== "" )
932 iterativeMode
= false;
935 if( ! Kernel::theDebugLog
.initialized( ) )
937 std::string::size_type suffixSep
= outputName
.rfind( '.' );
938 if( suffixSep
!= std::string::npos
&& outputName
.find( '/', suffixSep
) == std::string::npos
)
940 /* If there would have been a slash after the '.', the dot would have been part of a directory name.
941 * Otherwise, we conclude that we have found the extension of a filename, and replace that extension
944 Kernel::theDebugLog
.setFilename( outputName
.substr( 0, suffixSep
) + ".log" );
946 else if( baseName
!= "" )
948 Kernel::theDebugLog
.setFilename( outDir
+ baseName
+ ".log" );
952 Kernel::theDebugLog
.setFilename( outDir
+ "#shapes.log" );
958 std::string inPath
= inputName
;
959 std::string::size_type slash
= inPath
.rfind( '/' );
960 if( slash
== std::string::npos
)
962 inDir
= absoluteDirectory( "" );
966 inDir
= absoluteDirectory( inPath
.substr( 0, slash
).c_str( ) );
968 Ast::theShapesScanner
.setSourceDir( inDir
);
969 Kernel::theTeXLabelManager
.setup( inDir
, tmpDir
, texJobName
);
972 if( Computation::theTrixelizeSplicingTol
>= Computation::theTrixelizeOverlapTol
)
974 std::cerr
<< "The splicing tolerance (" << Concrete::Length::offtype( Computation::theTrixelizeSplicingTol
) << "bp) must be less than the overlap tolerance (" << Concrete::Length::offtype( Computation::theTrixelizeOverlapTol
) << "bp)." << std::endl
;
975 exit( Interaction::EXIT_INVOCATION_ERROR
);
978 if( xpdfServer
== "" )
980 xpdfServer
= outputName
;
983 if( xpdfAction
== XPDF_DEFAULT
)
985 xpdfAction
= XPDF_RAISE
;
988 addDefaultNeedPath( );
989 addDefaultFontMetricsPath( );
994 Ast::theShapesScanner
.push_backNeedPath( std::string( RESOURCES_DIR
) + "/extensions/" );
995 Lang::Font::push_backFontMetricsPath( std::string( RESOURCES_DIR
) + "/fontmetrics/" );
999 if( ! filenameRequestList
.empty( ) )
1001 std::list
< const char * >::const_iterator resource
= resourceRequestList
.begin( );
1002 for( std::list
< int >::const_iterator i
= filenameRequestList
.begin( );
1003 i
!= filenameRequestList
.end( );
1009 if( inputName
== "" )
1011 std::cout
<< "<stdin>" ;
1015 std::cout
<< inputName
;
1019 std::cout
<< outputName
;
1022 std::cout
<< tmpDir
;
1024 case FILENAME_TEXJOB
:
1025 std::cout
<< tmpDir
<< texJobName
;
1027 case FILENAME_LABELDB
:
1028 std::cout
<< labelDBName
;
1031 std::cout
<< fontmetricsOutputName
;
1033 case FILENAME_TEXINPUTS
:
1035 std::cout
<< getenv( "TEXINPUTS" ) ;
1038 case FILENAME_HTMLDOC
:
1040 std::cout
<< HTMLDIR
<< "/index.html" ;
1043 case FILENAME_RESOURCE
:
1047 std::cout
<< Ast::theShapesScanner
.searchFile( *resource
) ;
1049 catch( const Exceptions::Exception
& ball
)
1052 ball
.display( std::cerr
);
1053 exit( Interaction::EXIT_INVOCATION_ERROR
);
1059 std::cerr
<< "Internal error: filename request switch in main out of range." << std::endl
;
1060 exit( Interaction::EXIT_INTERNAL_ERROR
);
1062 std::cout
<< std::endl
;
1064 exit( Interaction::EXIT_OK
);
1067 if( pdfVersion
== SimplePDF::PDF_Version::VERSION_UNDEFINED
)
1069 pdfVersion
= SimplePDF::PDF_Version::PDF_1_4
;
1072 Kernel::the_PDF_version
.setVersion( pdfVersion
);
1073 Kernel::the_PDF_version
.setAction( pdfVersionAction
);
1076 std::ostringstream oss
;
1079 struct tm
* now( gmtime( &tmp
) );
1081 << std::setfill( '0' )
1082 << std::setw(4) << 1900 + now
->tm_year
1083 << std::setw(2) << 1 + now
->tm_mon
1084 << std::setw(2) << now
->tm_mday
1085 << std::setw(2) << now
->tm_hour
1086 << std::setw(2) << now
->tm_min
1087 << std::setw(2) << now
->tm_sec
1089 Kernel::theDocInfo
.addInfo( "CreationDate", SimplePDF::newString( oss
.str( ).c_str( ) ) );
1092 std::ifstream iFile
;
1093 if( inputName
== "" )
1095 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( "<stdin>" ) );
1096 Ast::theShapesScanner
.switch_streams( & std::cin
, & std::cerr
);
1097 Ast::theShapesScanner
.setNameOf_yyin( "stdin" );
1101 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( inputName
.c_str( ) ) );
1102 iFile
.open( inputName
.c_str( ) );
1103 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1105 std::cerr
<< "Failed to open " << inputName
<< " for input." << std::endl
;
1106 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1108 Ast::theShapesScanner
.switch_streams( & iFile
, & std::cerr
);
1109 Ast::theShapesScanner
.setNameOf_yyin( inputName
.c_str( ) );
1112 std::istringstream prependStreamIn
;
1113 if( ! prependStreamOut
.str( ).empty( ) )
1115 prependStreamIn
.str( prependStreamOut
.str( ) );
1116 Ast::theShapesScanner
.prependStream( & prependStreamIn
);
1119 RefCountPtr
< std::ifstream
> labelDBFile
= RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1120 Kernel::WarmCatalog::ShipoutList documents
;
1125 Kernel::theGlobalEnvironment
= new Kernel::Environment( Kernel::theEnvironmentList
);
1126 Kernel::registerGlobals( Kernel::theGlobalEnvironment
);
1127 Kernel::registerDynamic( Kernel::theGlobalEnvironment
);
1128 Kernel::registerHot( Kernel::theGlobalEnvironment
);
1129 Kernel::registerClasses( Kernel::theGlobalEnvironment
);
1130 Kernel::registerCore_elem( Kernel::theGlobalEnvironment
);
1131 Kernel::registerCore_point( Kernel::theGlobalEnvironment
);
1132 Kernel::registerCore_path( Kernel::theGlobalEnvironment
);
1133 Kernel::registerCore_draw( Kernel::theGlobalEnvironment
);
1134 Kernel::registerCore_construct( Kernel::theGlobalEnvironment
);
1135 Kernel::registerCore_font( Kernel::theGlobalEnvironment
);
1136 Kernel::registerCore_misc( Kernel::theGlobalEnvironment
);
1137 Kernel::registerCore_state( Kernel::theGlobalEnvironment
);
1138 Kernel::registerCore_annotation( Kernel::theGlobalEnvironment
);
1139 Ast::theGlobalAnalysisEnvironment
= Kernel::theGlobalEnvironment
->newAnalysisEnvironment( );
1140 Ast::theProgram
->analyze( 0, Ast::theGlobalAnalysisEnvironment
);
1141 if( ! Ast::theAnalysisErrorsList
.empty( ) )
1144 typedef typeof Ast::theAnalysisErrorsList ListType
;
1145 for( ListType::const_iterator i
= Ast::theAnalysisErrorsList
.begin( ); i
!= Ast::theAnalysisErrorsList
.end( ); ++i
)
1148 typedef const Exceptions::StaticInconsistency ErrorType
;
1149 ErrorType
* err
= dynamic_cast< ErrorType
* >( *i
);
1152 std::cerr
<< err
->loc( ) << ": " ;
1153 err
->display( std::cerr
);
1157 std::cerr
<< "(Bad exception type)" << ": " ;
1158 (*i
)->display( std::cerr
);
1160 abortProcedure( Interaction::EXIT_USER_ERROR
);
1163 // The display unit is looked up after the input is scanned, so the user may use her own units
1164 Interaction::displayUnitFactor
= Ast::theShapesScanner
.lookupUnitFactor( Interaction::displayUnitName
);
1165 if( Interaction::displayUnitFactor
<= 0 )
1167 std::cerr
<< "Invalid display unit: " << Interaction::displayUnitName
<< std::endl
;
1168 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
1170 labelDBFile
= performIterativeStartup( labelDBName
);
1171 RefCountPtr
< const Kernel::GraphicsState
> graphicsState( new Kernel::GraphicsState( true ) );
1172 Kernel::PassedDyn
baseDyn( new Kernel::DynamicEnvironment( graphicsState
) );
1175 Kernel::EvalState
evalState( Ast::theProgram
,
1176 Kernel::theGlobalEnvironment
,
1178 Kernel::ContRef( new Kernel::ExitVoidContinuation( & done
, Ast::theProgram
->loc( ) ) ) );
1187 evalState
.cont_
->backTrace( std::cerr
);
1188 std::cerr
<< "--- Bottom of trace ---" << std::endl
;
1192 std::cerr
<< "Eval trace: Cont: " << evalState
.cont_
->traceLoc( ) << " Expr: " << evalState
.expr_
->loc( ) << std::endl
;
1195 Ast::Expression
* expr
= evalState
.expr_
;
1196 expr
->eval( & evalState
);
1199 catch( const Exceptions::StaticInconsistency
& ball
)
1202 std::cerr
<< ball
.loc( ) << ": " ;
1203 ball
.display( std::cerr
);
1204 abortProcedure( ball
.exitCode( ) );
1206 catch( Exceptions::Exception
& ball
)
1209 if( Interaction::debugBacktrace
)
1211 evalState
.cont_
->backTrace( std::cerr
);
1214 std::cerr
<< evalState
.cont_
->traceLoc( ) << Exceptions::Exception::locsep
;
1215 ball
.display( std::cerr
);
1216 abortProcedure( ball
.exitCode( ) );
1219 Kernel::WarmCatalog
* catalog
= dynamic_cast< Kernel::WarmCatalog
* >( Kernel::theGlobalEnvironment
->getStateHandle( Ast::theGlobalAnalysisEnvironment
->findLocalStatePosition( Ast::THE_UNKNOWN_LOCATION
, Lang::CATALOG_ID
) ) );
1220 RefCountPtr
< const Lang::Group2D
> finalPicture
= dynamic_cast< Kernel::WarmGroup2D
* >( Kernel::theGlobalEnvironment
->getStateHandle( Ast::theGlobalAnalysisEnvironment
->findLocalStatePosition( Ast::THE_UNKNOWN_LOCATION
, Lang::CANVAS_ID
) ) )->getPile( );
1221 if( catalog
->isEmpty( ) && finalPicture
->isNull( ) )
1223 throw Exceptions::EmptyFinalPicture( );
1225 if( catalog
->isEmpty( ) )
1227 catalog
->tackOnPage( baseDyn
, finalPicture
, Ast::THE_UNKNOWN_LOCATION
);
1230 catalog
->shipout( splitMode
!= SPLIT_NO
, & documents
);
1234 Kernel::theGlobalEnvironment
->clear( );
1237 delete Kernel::theGlobalEnvironment
;
1238 delete Ast::theProgram
;
1240 catch( const Exceptions::StaticInconsistency
& ball
)
1243 std::cerr
<< ball
.loc( ) << ": " ;
1244 ball
.display( std::cerr
);
1245 abortProcedure( ball
.exitCode( ) );
1247 catch( const Exceptions::Exception
& ball
)
1250 ball
.display( std::cerr
);
1251 abortProcedure( ball
.exitCode( ) );
1253 catch( const NonLocalExit::DynamicBindingNotFound
& ball
)
1255 std::cerr
<< "Caught DynamicBindingNotFound at top level." << std::endl
1256 << "This should really not be possible; it is an internal error." << std::endl
;
1257 exit( Interaction::EXIT_INTERNAL_ERROR
);
1259 catch( const NonLocalExit::NotThisType
& ball
)
1261 std::cerr
<< "Caught NotThisType at top level." << std::endl
1262 << "This should really not be possible; it is an internal error." << std::endl
;
1263 exit( Interaction::EXIT_INTERNAL_ERROR
);
1265 catch( const NonLocalExit::NonLocalExitBase
& ball
)
1267 std::cerr
<< "Caught an unknown descendant to NonLocalExitBase at top level." << std::endl
1268 << "This should really not be possible; it is an internal error." << std::endl
;
1269 exit( Interaction::EXIT_INTERNAL_ERROR
);
1271 catch( const char * ball
)
1273 std::cerr
<< "Caught (char*) ball at top level:" << std::endl
1274 << " " << ball
<< std::endl
;
1275 exit( Interaction::EXIT_GENERIC_ERROR
);
1277 catch( const std::string
& ball
)
1279 std::cerr
<< "Caught (string) ball at top level:" << std::endl
1280 << " " << ball
<< std::endl
;
1281 exit( Interaction::EXIT_GENERIC_ERROR
);
1285 std::cerr
<< "Caught (...) ball at top level." << std::endl
;
1286 exit( Interaction::EXIT_GENERIC_ERROR
);
1289 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1291 abortProcedure( Interaction::EXIT_USER_ERROR
);
1296 std::cerr
<< "Summary:" << std::endl
;
1297 std::cerr
<< "Environments: alive: " << Kernel::Environment::liveCount
<< " of total: " << Kernel::Environment::createdCount
1298 << " (" << 100 * static_cast< double >( Kernel::Environment::liveCount
) / static_cast< double >( Kernel::Environment::createdCount
) << "%)" << std::endl
;
1305 if( documents
.size( ) != 1 )
1307 std::cerr
<< "Internal error: Failed to produce exactly one document of output although --split=no." << std::endl
;
1309 std::ofstream oFile
;
1310 oFile
.open( outputName
.c_str( ) );
1311 if( ! oFile
.good( ) )
1313 /* If this is because the output directory does not exist, we shall inform the user about this. */
1314 std::string::size_type slash
= outputName
.rfind( '/' );
1315 if( slash
!= std::string::npos
)
1317 std::string outputDir
= outputName
.substr( 0, slash
);
1318 struct stat theStat
;
1319 if( stat( outputDir
.c_str( ), & theStat
) == 0 )
1321 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1323 std::cerr
<< "The prefix " << outputDir
<< " of the output name must be a directory." << std::endl
;
1324 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1326 /* In case we reach here, the directory exists, so we fall back on the generic error message below. */
1330 std::cerr
<< "The file " << outputName
<< " cannot be opened for output since the directory " << outputDir
<< " does not exist." << std::endl
;
1331 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1334 std::cerr
<< "Failed to open " << outputName
<< " for output." << std::endl
;
1335 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1337 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
1342 std::ostringstream rmCommand
;
1343 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1344 escapeExtGlobChars( outputName
, rmCommand
);
1345 rmCommand
<< "-+([0-9]).pdf'" ;
1346 Interaction::systemDebugMessage( rmCommand
.str( ) );
1347 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1349 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1351 size_t physicalPageNo
= 1;
1352 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1354 std::ostringstream tmpFilename
;
1355 tmpFilename
<< outputName
<< "-" << physicalPageNo
<< ".pdf" ;
1356 std::ofstream oFile
;
1357 oFile
.open( tmpFilename
.str( ).c_str( ) );
1358 if( ! oFile
.good( ) )
1360 std::cerr
<< "Failed to open " << tmpFilename
.str( ) << " for output." << std::endl
;
1361 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1363 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1369 struct stat theStat
;
1370 if( stat( outputName
.c_str( ), & theStat
) == 0 )
1372 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1374 std::cerr
<< "The path " << outputName
<< " was expected to reference a directory." << std::endl
;
1375 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1380 if( mkdir( outputName
.c_str( ), S_IRWXU
| S_IRWXG
| S_IRWXO
) != 0 )
1382 std::cerr
<< "Failed to create directory for split document files (errno=" << errno
<< "): " << outputName
<< std::endl
;
1383 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1386 std::ostringstream rmCommand
;
1387 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1388 escapeExtGlobChars( outputName
, rmCommand
);
1389 rmCommand
<< "/+([0-9]).pdf'" ;
1390 Interaction::systemDebugMessage( rmCommand
.str( ) );
1391 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1393 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1395 size_t physicalPageNo
= 1;
1396 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1398 std::ostringstream tmpFilename
;
1399 tmpFilename
<< outputName
<< "/" << physicalPageNo
<< ".pdf" ;
1400 std::ofstream oFile
;
1401 oFile
.open( tmpFilename
.str( ).c_str( ) );
1402 if( ! oFile
.good( ) )
1404 std::cerr
<< "Failed to open " << tmpFilename
.str( ) << " for output." << std::endl
;
1405 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1407 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1413 /* This must be done after the output has been written, and before iterativeFinish writes to the labels database file.
1415 Kernel::thePDFImporter
.free( );
1417 if( labelDBFile
!= NullPtr
< std::ifstream
>( ) )
1419 if( labelDBFile
->is_open( ) )
1421 labelDBFile
->close( );
1423 labelDBFile
= NullPtr
< std::ifstream
>( ); // Free the reference.
1428 Kernel::theTeXLabelManager
.iterativeFinish( labelDBName
);
1433 if( splitMode
!= SPLIT_NO
)
1435 std::cerr
<< "Warning: not launching viewer since the documet was split" << std::endl
;
1439 xpdfHelper( outputName
, xpdfServer
, xpdfAction
);
1445 if( splitMode
!= SPLIT_NO
)
1447 std::cerr
<< "Warning: not launching viewer since the documet was split" << std::endl
;
1451 openHelper( outputName
, do_open_application
);
1462 argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
)
1464 if( argc
< argcMin
)
1466 std::cerr
<< "The command line option " << optionSpecifier
<< " requires " << argcMin
- 1 << " parameters." << std::endl
;
1467 exit( Interaction::EXIT_INVOCATION_ERROR
);
1472 strprefixcmp( char * str
, const char * prefix
, char ** endp
)
1474 int len
= strlen( prefix
);
1475 bool res
= ( strncmp( str
, prefix
, len
) == 0 );
1481 strtobool( const char * str
, const char * containingString
, const char * trueLabel
, const char * falseLabel
)
1483 if( trueLabel
!= 0 &&
1484 strcmp( str
, trueLabel
) == 0 )
1488 if( falseLabel
!= 0 &&
1489 strcmp( str
, falseLabel
) == 0 )
1493 if( strcmp( str
, "yes" ) == 0 ||
1494 strcmp( str
, "true" ) == 0 ||
1495 strcmp( str
, "on" ) == 0 )
1499 if( strcmp( str
, "no" ) == 0 ||
1500 strcmp( str
, "false" ) == 0 ||
1501 strcmp( str
, "off" ) == 0)
1505 std::cerr
<< "The string \"" << str
<< "\" in the command line argument \"" << containingString
<< "\" was not recognized as a boolean value." << std::endl
;
1506 exit( Interaction::EXIT_INVOCATION_ERROR
);
1510 RefCountPtr
< std::ifstream
>
1511 performIterativeStartup( const std::string
& labelDBName
)
1514 struct stat theStat
;
1515 if( stat( labelDBName
.c_str( ), & theStat
) != 0 )
1517 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1521 // ostringstream mvCommand;
1522 // mvCommand << "cp '" << oldFilename.str( ) << "' '" << labelDBName.str( ) << "'" ;
1523 // Interaction::systemDebugMessage( mvCommand.str( ) );
1524 // if( system( mvCommand.str( ).c_str( ) ) != 0 )
1526 // return RefCountPtr< std::ifstream >( NullPtr< std::ifstream >( ) );
1529 RefCountPtr
< std::ifstream
> labelsFile( new std::ifstream( labelDBName
.c_str( ) ) );
1530 if( ! labelsFile
->good( ) )
1532 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1536 Kernel::theTeXLabelManager
.iterativeStartup( labelsFile
);
1539 catch( const char * ball
)
1541 std::cerr
<< "Caught (char*) ball from iterative startup:" << std::endl
1542 << " " << ball
<< std::endl
;
1543 exit( Interaction::EXIT_GENERIC_ERROR
);
1545 catch( const std::string
& ball
)
1547 std::cerr
<< "Caught (string) ball from iterative startup:" << std::endl
1548 << " " << ball
<< std::endl
;
1549 exit( Interaction::EXIT_GENERIC_ERROR
);
1551 catch( const Exceptions::Exception
& ball
)
1553 ball
.display( std::cerr
);
1554 exit( ball
.exitCode( ) );
1558 std::cerr
<< "Caught (...) ball from iterative startup." << std::endl
;
1559 exit( Interaction::EXIT_GENERIC_ERROR
);
1565 abortProcedure( int exitCode
)
1567 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1570 while( ! Kernel::thePostCheckErrorsList
.empty( ) )
1572 Exceptions::Exception
* e
= Kernel::thePostCheckErrorsList
.front( );
1573 Kernel::thePostCheckErrorsList
.pop_front( );
1575 typedef const Exceptions::PostCondition ErrorType
;
1576 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1579 std::cerr
<< err
->loc( ) << ": " ;
1580 err
->display( std::cerr
);
1585 typedef const Exceptions::RuntimeError ErrorType
;
1586 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1589 std::cerr
<< err
->getLoc( ) << " (runtime): " ;
1590 err
->display( std::cerr
);
1594 std::cerr
<< "(Bad post-exception type)" << ": " ;
1595 e
->display( std::cerr
);
1598 std::cerr
<< "Aborting job. Output files are left unchanged." << std::endl
;
1606 void setSelfRef( RefCountPtr
< const Lang::Class
> cls
)
1608 cls
->setSelfRef( cls
);
1610 void initMutators( RefCountPtr
< const Lang::Class
> cls
)
1612 Lang::SystemFinalClass
* typedPtr
= dynamic_cast< Lang::SystemFinalClass
* >( const_cast< Lang::Class
* >( cls
.getPtr( ) ) );
1615 typedPtr
->initMutators( );
1619 std::cerr
<< "Helpers::initMutators was called with object of bad type." << std::endl
;
1620 exit( Interaction::EXIT_INTERNAL_ERROR
);
1629 Lang::ElementaryPath2D
* bbox
= new Lang::ElementaryPath2D
;
1630 bbox
->push_back( new Concrete::PathPoint2D( 0, 0 ) );
1632 Lang::THE_POINTPICTURE
= RefCountPtr
< Lang::Drawable2D
>( new Lang::BBoxed2D( Lang::THE_NULL2D
,
1633 RefCountPtr
< Lang::ElementaryPath2D
>( bbox
) ) );
1634 Helpers::setSelfRef( Lang::THE_OBJECT
);
1636 Helpers::setSelfRef( Lang::Void::TypeID
);
1637 Helpers::setSelfRef( Lang::Symbol::TypeID
);
1638 Helpers::setSelfRef( Lang::Float::TypeID
);
1639 Helpers::setSelfRef( Lang::Length::TypeID
);
1640 Helpers::setSelfRef( Lang::Boolean::TypeID
);
1641 Helpers::setSelfRef( Lang::String::TypeID
);
1642 Helpers::setSelfRef( Lang::FloatPair::TypeID
);
1643 Helpers::setSelfRef( Lang::FloatTriple::TypeID
);
1644 Helpers::setSelfRef( Lang::Coords2D::TypeID
);
1645 Helpers::setSelfRef( Lang::CornerCoords2D::TypeID
);
1646 Helpers::setSelfRef( Lang::Coords3D::TypeID
);
1648 Helpers::setSelfRef( Lang::Function::TypeID
);
1649 Helpers::setSelfRef( Lang::Transform2D::TypeID
);
1650 Helpers::setSelfRef( Lang::Transform3D::TypeID
);
1652 Helpers::setSelfRef( Lang::Class::TypeID
);
1654 Helpers::setSelfRef( Lang::TransformedInstance::TypeID
);
1656 Helpers::initMutators( Kernel::WarmGroup2D::TypeID
);
1657 Helpers::initMutators( Kernel::WarmGroup3D::TypeID
);
1658 Helpers::initMutators( Kernel::WarmCatalog::TypeID
);
1661 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric2D" ) );
1662 Lang::Geometric2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1663 Helpers::setSelfRef( Lang::Geometric2D::TypeID
);
1664 /* Note that addVirtual must not be called before the selfRef is set!
1668 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric3D" ) );
1669 Lang::Geometric3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1670 Helpers::setSelfRef( Lang::Geometric3D::TypeID
);
1671 /* Note that addVirtual must not be called before the selfRef is set!
1675 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable2D" ) );
1676 Lang::Drawable2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1677 Helpers::setSelfRef( Lang::Drawable2D::TypeID
);
1678 /* Note that addVirtual must not be called before the selfRef is set!
1680 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1683 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable3D" ) );
1684 Lang::Drawable3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1685 Helpers::setSelfRef( Lang::Drawable3D::TypeID
);
1686 /* Note that addVirtual must not be called before the selfRef is set!
1688 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1691 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Color" ) );
1692 Lang::Color::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1693 Helpers::setSelfRef( Lang::Color::TypeID
);
1694 /* Note that addVirtual must not be called before the selfRef is set!
1696 tmp
->addVirtual( "stroking" );
1697 tmp
->addVirtual( "nonstroking" );
1702 xpdfHelper( const std::string
& filename
, const std::string
& server
, const XpdfAction
& action
)
1704 pid_t xpdfProcess
= fork( );
1705 if( xpdfProcess
== -1 )
1707 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running xpdf." ) );
1710 if( xpdfProcess
== 0 ) /* This is the child */
1712 /* The exec call below never returns, so the child process never leaves this if clause.
1713 * Hence, there is no need to create a special else clasuse below.
1718 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-raise", filename
.c_str( ), static_cast< const char * >( 0 ) );
1721 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-reload", static_cast< const char * >( 0 ) );
1724 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-quit", static_cast< const char * >( 0 ) );
1727 execlp( "xpdf", "xpdf", filename
.c_str( ), static_cast< const char * >( 0 ) );
1730 std::cerr
<< "Internal error: XpdfAction switch out of range." << std::endl
;
1731 exit( Interaction::EXIT_INTERNAL_ERROR
);
1735 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to xpdf." << std::endl
;
1736 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1738 std::cerr
<< "execlp call to xpdf returned with errno == 0." << std::endl
;
1739 exit( Interaction::EXIT_INTERNAL_ERROR
);
1745 openHelper( const std::string
& filename
, const char * application
)
1747 pid_t openProcess
= fork( );
1748 if( openProcess
== -1 )
1750 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running open." ) );
1753 if( openProcess
== 0 ) /* This is the child */
1755 /* The exec call below never returns, so the child process never leaves this if clause.
1756 * Hence, there is no need to create a special else clasuse below.
1758 if( application
!= 0 )
1760 execlp( "open", "open", "-a", application
, filename
.c_str( ), static_cast< const char * >( 0 ) );
1764 execlp( "open", "open", filename
.c_str( ), static_cast< const char * >( 0 ) );
1768 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to open." << std::endl
;
1769 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1771 std::cerr
<< "execlp call to open returned with errno == 0." << std::endl
;
1772 exit( Interaction::EXIT_INTERNAL_ERROR
);
1778 Interaction::systemDebugMessage( const std::string
& msg
)
1780 if( Interaction::debugSystem
)
1782 std::cerr
<< "System command: " << msg
<< std::endl
;
1787 addDefaultNeedPath( )
1789 char * start
= getenv( "SHAPESINPUTS" );
1792 Ast::theShapesScanner
.push_backNeedPath( "./" );
1795 char * tok
= strsep( & start
, ":" );
1798 Ast::theShapesScanner
.push_backNeedPath( tok
);
1799 tok
= strsep( & start
, ":" );
1804 addDefaultFontMetricsPath( )
1806 char * start
= getenv( "SHAPESFONTMETRICS" );
1811 char * tok
= strsep( & start
, ":" );
1814 Lang::Font::push_backFontMetricsPath( tok
);
1815 tok
= strsep( & start
, ":" );
1822 Helpers::requireUTF8ToMacRomanConverter( true ); // true means "cleanup"
1823 Helpers::requireMacRomanToUTF8Converter( true ); // true means "cleanup"
1824 Helpers::requireUTF8ToWinANSIConverter( true ); // true means "cleanup"
1825 Helpers::requireUTF8ToASCIIConverter( true ); // true means "cleanup"
1826 Helpers::requireUTF8ToUCS4Converter( true ); // true means "cleanup"
1827 Helpers::requireUTF16BEToUCS4Converter( true ); // true means "cleanup"
1828 Helpers::requireGlyphList( true ); // true means "cleanup"
1829 Helpers::requireMacRomanEncoding( true ); // true means "cleanup"
1833 absoluteFilename( const char * filename
)
1835 if( *filename
== '/' )
1839 return callDir
+ filename
;
1843 absoluteDirectory( const char * filename
)
1845 if( *filename
== '\0' )
1849 if( filename
[ strlen( filename
) - 1 ] != '/' )
1851 if( *filename
== '/' )
1853 return filename
+ std::string( "/" );
1855 return callDir
+ filename
+ "/";
1857 if( *filename
== '/' )
1861 return callDir
+ filename
;
1867 ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
)
1869 struct stat theStat
;
1870 if( stat( dirname
.c_str( ), & theStat
) == 0 )
1872 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1874 std::cerr
<< "The path " << dirname
<< " was expected to reference a directory." << std::endl
;
1875 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1877 // if( ( theStat.st_mode & S_IWOTH ) == 0 )
1879 // std::cerr << "The directory " << dirname << " was expected have write permission for others." << std::endl ;
1880 // exit( Interaction::EXIT_FILE_PERMISSION_ERROR );
1887 std::cerr
<< "The directory for temporaries, " << dirname
<< ", does not exist and is not allowed to be created. Consider using --tmpdir+ instead of --tmpdir ." << std::endl
;
1888 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1891 size_t i2
= 0; /* We know there's a slash at the first position */
1892 i2
= dirname
.find( '/', i2
+ 1 );
1894 while( stat( dirname
.substr( 0, i2
).c_str( ), & theStat
) == 0 )
1897 i2
= dirname
.find( '/', i2
+ 1 );
1901 std::cerr
<< "Shapes will not create directories for temporary files at the root: " << dirname
<< std::endl
;
1902 exit( Interaction::EXIT_INVOCATION_ERROR
);
1905 mode_t oldUmask
= umask( 0 ); /* We want to be able to create directories with any permissions. */
1906 while( i2
!= std::string::npos
)
1908 if( mkdir( dirname
.substr( 0, i2
).c_str( ), theStat
.st_mode
& ( S_IRWXU
| S_IRWXG
| S_IRWXO
) ) != 0 )
1910 std::cerr
<< "Failed to create directory for temporary files (errno=" << errno
<< "): " << dirname
.substr( 0, i2
) << std::endl
;
1911 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1913 i2
= dirname
.find( '/', i2
+ 1 );
1919 escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
)
1921 const char * special
= "*?[+@!";
1922 for( std::string::const_iterator i
= str
.begin( ); i
!= str
.end( ); ++i
)
1924 if( strchr( special
, *i
) != 0 )