1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include "Shapes_Kernel_decls.h"
21 #include "simplepdfi.h"
22 #include "simplepdfo.h"
25 #include "shapesexceptions.h"
27 #include "multipage.h"
28 #include "continuations.h"
29 #include "charconverters.h"
30 #include "pagecontentstates.h"
31 #include "autoonoff.h"
32 #include "shapesscanner.h"
33 #include "texlabelmanager.h"
49 extern int shapesdebug
;
52 using namespace Shapes
;
53 using namespace SimplePDF
;
55 void argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
);
56 bool strprefixcmp( char * str
, const char * prefix
, char ** endp
);
57 bool strtobool( const char * str
, const char * containingString
, const char * trueLabel
= 0, const char * falseLabel
= 0 );
59 std::string
absoluteFilename( const char * filename
);
60 std::string
absoluteDirectory( const char * filename
);
61 void ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
);
62 RefCountPtr
< std::ifstream
> performIterativeStartup( const std::string
& texJobName
);
63 void abortProcedure( int exitCode
);
65 enum XpdfAction
{ XPDF_DEFAULT
, XPDF_RAISE
, XPDF_RELOAD
, XPDF_QUIT
, XPDF_NOSERVER
};
66 void xpdfHelper( const std::string
& filename
, const std::string
& server
, const XpdfAction
& action
);
67 void openHelper( const std::string
& filename
, const char * application
);
68 void addDefaultNeedPath( );
69 void addDefaultFontMetricsPath( );
70 void destroyGlobals( );
71 void escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
);
77 void systemDebugMessage( const std::string
& msg
);
82 main( int argc
, char ** argv
)
88 bool iterativeMode
= true;
89 bool useResources
= true;
92 char * cwd
= getcwd( 0, 0 );
93 callDir
= cwd
+ std::string( "/" );
99 bool allowCreateTmpDir
= false;
100 std::string baseName
;
101 std::string inputName
;
102 std::string outputName
;
103 std::string texJobName
;
104 std::string labelDBName
;
105 std::string fontmetricsOutputName
;
107 enum FilenameRequests
{ FILENAME_RESOURCE
, FILENAME_IN
, FILENAME_OUT
, FILENAME_TMP
, FILENAME_TEXJOB
, FILENAME_LABELDB
, FILENAME_AFM
, FILENAME_TEXINPUTS
, FILENAME_HTMLDOC
};
109 std::list
< int > filenameRequestList
;
110 std::list
< const char * > resourceRequestList
;
112 bool evalTrace
= false;
113 bool evalBackTrace
= false;
114 bool cleanupMemory
= true;
115 bool memoryStats
= false;
116 bool launch_xpdf
= false;
117 SimplePDF::PDF_Version::Version pdfVersion
= SimplePDF::PDF_Version::VERSION_UNDEFINED
;
118 SimplePDF::PDF_Version::Action pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
119 XpdfAction xpdfAction
= XPDF_DEFAULT
;
120 std::string xpdfServer
;
121 bool do_open
= false;
122 const char * do_open_application
= 0;
123 std::ostringstream prependStreamOut
;
125 enum SplitMode
{ SPLIT_NO
, SPLIT_FLAT
, SPLIT_DIR
};
126 SplitMode splitMode
= SPLIT_NO
;
133 if( strcmp( *argv
, "--yydebug" ) == 0 )
139 else if( strcmp( *argv
, "--shapes-debug" ) == 0 )
145 else if( strcmp( *argv
, "--system-debug" ) == 0 )
147 Interaction::debugSystem
= true;
151 else if( strcmp( *argv
, "--afm-debug" ) == 0 )
153 Interaction::fontMetricDebug
= true;
157 else if( strcmp( *argv
, "--afm-messages" ) == 0 )
159 Interaction::fontMetricMessages
= true;
163 else if( strcmp( *argv
, "--tex-debug" ) == 0 )
165 Interaction::pdfLaTeXInteractionTo_stderr
= true;
169 else if( strcmp( *argv
, "--log-globals" ) == 0 )
171 Interaction::logGlobals
= true;
175 else if( strprefixcmp( *argv
, "--bytecolumn=", & optionSuffix
) )
177 Interaction::characterColumnInBytes
= strtobool( optionSuffix
, *argv
);
181 else if( strprefixcmp( *argv
, "--debugstep=", & optionSuffix
) )
184 int tmp
= strtol( optionSuffix
, & endp
, 10 );
187 std::cerr
<< "The --debugstep value must be nonnegative: " << optionSuffix
<< std::endl
;
188 exit( Interaction::EXIT_INVOCATION_ERROR
);
190 Interaction::debugStep
= static_cast< size_t >( tmp
);
194 else if( strcmp( *argv
, "--debuglog" ) == 0 )
196 argcAssertion( *argv
, argc
, 2 );
199 Kernel::theDebugLog
.setFilename( *( argv
+ 1 ) );
201 catch( const char * ball
)
203 std::cerr
<< ball
<< std::endl
;
204 exit( Interaction::EXIT_INVOCATION_ERROR
);
209 else if( strcmp( *argv
, "--debuglog-stderr" ) == 0 )
213 Kernel::theDebugLog
.setStream( & std::cerr
);
215 catch( const char * ball
)
217 std::cerr
<< ball
<< std::endl
;
218 exit( Interaction::EXIT_INVOCATION_ERROR
);
223 else if( strcmp( *argv
, "--debuglog-stdout" ) == 0 )
227 Kernel::theDebugLog
.setStream( & std::cout
);
229 catch( const char * ball
)
231 std::cerr
<< ball
<< std::endl
;
232 exit( Interaction::EXIT_INVOCATION_ERROR
);
237 else if( strprefixcmp( *argv
, "--dtminerror=", & optionSuffix
) )
239 Computation::dtMinIsError
= strtobool( optionSuffix
, *argv
);
243 else if( strprefixcmp( *argv
, "--fmguesserror=", & optionSuffix
) )
245 Computation::fontMetricGuessIsError
= strtobool( optionSuffix
, *argv
);
249 else if( strcmp( *argv
, "--evaltrace" ) == 0 )
255 else if( strcmp( *argv
, "--evalbacktrace" ) == 0 )
258 evalBackTrace
= true;
262 else if( strprefixcmp( *argv
, "--backtrace=", & optionSuffix
) )
264 Interaction::debugBacktrace
= strtobool( optionSuffix
, *argv
);
268 else if( strprefixcmp( *argv
, "--iteration=", & optionSuffix
) )
270 iterativeMode
= strtobool( optionSuffix
, *argv
);
274 else if( strprefixcmp( *argv
, "--resources=", & optionSuffix
) )
276 useResources
= strtobool( optionSuffix
, *argv
);
280 else if( strprefixcmp( *argv
, "--stats=", & optionSuffix
) )
282 memoryStats
= strtobool( optionSuffix
, *argv
);
286 else if( strprefixcmp( *argv
, "--memclean=", & optionSuffix
) )
288 cleanupMemory
= strtobool( optionSuffix
, *argv
);
292 else if( strprefixcmp( *argv
, "--showfiles=", & optionSuffix
) )
294 Ast::theShapesScanner
.setShowFiles( strtobool( optionSuffix
, *argv
) );
298 else if( strprefixcmp( *argv
, "--pdf-version=", & optionSuffix
) || /* Note that we use that || shortcuts! */
299 strprefixcmp( *argv
, "-v", & optionSuffix
) )
301 if( pdfVersion
!= SimplePDF::PDF_Version::VERSION_UNDEFINED
)
303 std::cerr
<< "Multiply defined pdf version." << std::endl
;
304 exit( Interaction::EXIT_INVOCATION_ERROR
);
307 switch( *optionSuffix
)
310 pdfVersionAction
= SimplePDF::PDF_Version::ERROR
;
313 pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
316 pdfVersionAction
= SimplePDF::PDF_Version::SILENT
;
319 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
;
320 exit( Interaction::EXIT_INVOCATION_ERROR
);
323 if( strncmp( optionSuffix
, "1.", 2 ) == 0 &&
324 '1' <= optionSuffix
[2] && optionSuffix
[2] <= '6' )
326 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
};
327 pdfVersion
= versions
[ optionSuffix
[2] - '1' ];
329 else if( strcmp( optionSuffix
, "X" ) == 0 )
331 std::cerr
<< "Restriction to PDF-X is not implemented, please try using a low version number, such as 1.1 instead." << std::endl
;
335 std::cerr
<< "Unsupported pdf version specification: " << optionSuffix
<< std::endl
;
336 exit( Interaction::EXIT_INVOCATION_ERROR
);
341 else if( strprefixcmp( *argv
, "--tp=", & optionSuffix
) )
343 Kernel::allowTransparency
= strtobool( optionSuffix
, *argv
);
347 else if( strprefixcmp( *argv
, "--spot-pair=", & optionSuffix
) )
349 Kernel::allowSingletonPaths
= ! strtobool( optionSuffix
, *argv
);
353 else if( strprefixcmp( *argv
, "--unit=", & optionSuffix
) )
355 Interaction::displayUnitName
= optionSuffix
;
360 else if( strprefixcmp( *argv
, "--splicingtol=", & optionSuffix
) )
364 Computation::theTrixelizeSplicingTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
368 std::cerr
<< "Argument to --splicing= was not recognized as a length: " << optionSuffix
<< std::endl
;
369 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
371 if( Computation::theTrixelizeSplicingTol
<= 0 )
373 std::cerr
<< "Argument to --splicingtol not positive: " << Computation::theTrixelizeSplicingTol
.offtype
< 1, 0 >( ) << std::endl
;
374 exit( Interaction::EXIT_INVOCATION_ERROR
);
380 else if( strprefixcmp( *argv
, "--overlaptol=", & optionSuffix
) )
384 Computation::theTrixelizeOverlapTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
388 std::cerr
<< "Argument to --overlaptol= was not recognized as a length: " << optionSuffix
<< std::endl
;
389 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
391 if( Computation::theTrixelizeOverlapTol
<= 0 )
393 std::cerr
<< "Argument to --overlaptol not positive: " << Computation::theTrixelizeOverlapTol
.offtype
< 1, 0 >( ) << std::endl
;
394 exit( Interaction::EXIT_INVOCATION_ERROR
);
400 else if( strcmp( *argv
, "--needpath" ) == 0 ||
401 strncmp( *argv
, "-N", 2 ) == 0 )
403 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
405 const char * pth
= 0;
408 argcAssertion( *argv
, argc
, 2 );
416 if( strchr( pth
, ':' ) != 0 )
418 const char * flag
= 0;
419 const char * shortFlag
= "-N";
429 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
432 std::cerr
<< " (or " << shortFlag
<< ")" ;
434 std::cerr
<<"." << std::endl
;
435 exit( Interaction::EXIT_INVOCATION_ERROR
);
438 Ast::theShapesScanner
.push_backNeedPath( absoluteDirectory( pth
) );
451 else if( strcmp( *argv
, "--fontmetricspath" ) == 0 ||
452 strncmp( *argv
, "-M", 2 ) == 0 )
454 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
456 const char * pth
= 0;
459 argcAssertion( *argv
, argc
, 2 );
467 if( strchr( pth
, ':' ) != 0 )
469 const char * flag
= 0;
470 const char * shortFlag
= "-M";
480 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
483 std::cerr
<< " (or " << shortFlag
<< ")" ;
485 std::cerr
<<"." << std::endl
;
486 exit( Interaction::EXIT_INVOCATION_ERROR
);
489 Lang::Font::push_backFontMetricsPath( absoluteDirectory( pth
) );
502 else if( strprefixcmp( *argv
, "--seed=", & optionSuffix
) )
505 long s
= strtol( optionSuffix
, &endp
, 10 );
508 std::cerr
<< "Argument to --seed= was not an integer: " << optionSuffix
<< std::endl
;
509 exit( Interaction::EXIT_INVOCATION_ERROR
);
517 else if( strprefixcmp( *argv
, "--arcdelta=", & optionSuffix
) )
521 Computation::the_arcdelta
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
525 std::cerr
<< "Argument to --arcdelta= was not recognized as a length: " << optionSuffix
<< std::endl
;
526 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
528 if( Computation::the_arcdelta
<= 0 )
530 std::cerr
<< "Argument to --arcdelta= not positive: " << optionSuffix
<< std::endl
;
531 exit( Interaction::EXIT_INVOCATION_ERROR
);
537 else if( strprefixcmp( *argv
, "--dtmin=", & optionSuffix
) )
540 Computation::the_dtMin
= strtod( optionSuffix
, &endp
);
543 std::cerr
<< "Argument to --dtmin= was not a float: " << optionSuffix
<< std::endl
;
544 exit( Interaction::EXIT_INVOCATION_ERROR
);
546 if( Computation::the_dtMin
<= 0 )
548 std::cerr
<< "Argument to --dtmin= not positive: " << Computation::the_dtMin
<< std::endl
;
549 exit( Interaction::EXIT_INVOCATION_ERROR
);
555 else if( strcmp( *argv
, "--prepend" ) == 0 )
557 argcAssertion( *argv
, argc
, 2 );
558 prependStreamOut
<< *( argv
+ 1 ) << std::endl
;
562 else if( strcmp( *argv
, "--base" ) == 0 )
564 argcAssertion( *argv
, argc
, 2 );
567 std::cerr
<< "The name base is multiply specified." << std::endl
;
568 exit( Interaction::EXIT_INVOCATION_ERROR
);
570 baseName
= *( argv
+ 1 );
574 else if( strcmp( *argv
, "--which" ) == 0 )
576 argcAssertion( *argv
, argc
, 2 );
577 filenameRequestList
.push_back( FILENAME_RESOURCE
);
578 resourceRequestList
.push_back( *( argv
+ 1 ) );
582 else if( strcmp( *argv
, "--in" ) == 0 )
584 argcAssertion( *argv
, argc
, 2 );
585 if( inputName
!= "" )
587 std::cerr
<< "The input file is multiply specified." << std::endl
;
588 exit( Interaction::EXIT_INVOCATION_ERROR
);
590 inputName
= absoluteFilename( *( argv
+ 1 ) );
594 else if( strcmp( *argv
, "--which-in" ) == 0 )
596 filenameRequestList
.push_back( FILENAME_IN
);
600 else if( strcmp( *argv
, "--out" ) == 0 )
602 argcAssertion( *argv
, argc
, 2 );
603 if( outputName
!= "" )
605 std::cerr
<< "The output file is multiply specified." << std::endl
;
606 exit( Interaction::EXIT_INVOCATION_ERROR
);
608 outputName
= absoluteFilename( *( argv
+ 1 ) );
612 else if( strcmp( *argv
, "--which-out" ) == 0 )
614 filenameRequestList
.push_back( FILENAME_OUT
);
618 else if( strcmp( *argv
, "--texjob" ) == 0 )
620 argcAssertion( *argv
, argc
, 2 );
621 if( texJobName
!= "" )
623 std::cerr
<< "The tex job name is multiply specified." << std::endl
;
624 exit( Interaction::EXIT_INVOCATION_ERROR
);
626 texJobName
= *( argv
+ 1 );
627 if( texJobName
.find( '/' ) != std::string::npos
)
629 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
;
630 exit( Interaction::EXIT_INVOCATION_ERROR
);
635 else if( strcmp( *argv
, "--which-texjob" ) == 0 )
637 filenameRequestList
.push_back( FILENAME_TEXJOB
);
641 else if( strcmp( *argv
, "--labeldb" ) == 0 )
643 argcAssertion( *argv
, argc
, 2 );
644 if( labelDBName
!= "" )
646 std::cerr
<< "The label database file is multiply specified." << std::endl
;
647 exit( Interaction::EXIT_INVOCATION_ERROR
);
649 labelDBName
= absoluteFilename( *( argv
+ 1 ) );
653 else if( strcmp( *argv
, "--which-labeldb" ) == 0 )
655 filenameRequestList
.push_back( FILENAME_LABELDB
);
659 else if( strcmp( *argv
, "--afmout" ) == 0 )
661 argcAssertion( *argv
, argc
, 2 );
662 if( fontmetricsOutputName
!= "" )
664 std::cerr
<< "The font metrics output name is multiply specified." << std::endl
;
665 exit( Interaction::EXIT_INVOCATION_ERROR
);
667 fontmetricsOutputName
= absoluteFilename( *( argv
+ 1 ) );
671 else if( strcmp( *argv
, "--which-afmout" ) == 0 )
673 filenameRequestList
.push_back( FILENAME_AFM
);
677 else if( strcmp( *argv
, "--which-TEXINPUTS" ) == 0 )
679 filenameRequestList
.push_back( FILENAME_TEXINPUTS
);
683 else if( strcmp( *argv
, "--which-doc" ) == 0 )
685 filenameRequestList
.push_back( FILENAME_HTMLDOC
);
689 else if( strcmp( *argv
, "--outdir" ) == 0 )
691 argcAssertion( *argv
, argc
, 2 );
694 std::cerr
<< "The output directory is multiply specified." << std::endl
;
695 exit( Interaction::EXIT_INVOCATION_ERROR
);
697 outDir
= absoluteDirectory( *( argv
+ 1 ) );
701 else if( strprefixcmp( *argv
, "--tmp*=", & optionSuffix
) )
703 allowCreateTmpDir
= strtobool( optionSuffix
, *argv
);
707 else if( strcmp( *argv
, "--tmpdir" ) == 0 )
709 argcAssertion( *argv
, argc
, 2 );
712 std::cerr
<< "The temporaries directory is multiply specified." << std::endl
;
713 exit( Interaction::EXIT_INVOCATION_ERROR
);
715 tmpDir
= absoluteDirectory( *( argv
+ 1 ) );
719 else if( strcmp( *argv
, "--which-tmp" ) == 0 )
721 filenameRequestList
.push_back( FILENAME_TMP
);
725 else if( strprefixcmp( *argv
, "--split=", & optionSuffix
) )
727 if( strcmp( optionSuffix
, "no" ) == 0 )
729 splitMode
= SPLIT_NO
;
731 else if( strcmp( optionSuffix
, "flat" ) == 0 )
733 splitMode
= SPLIT_FLAT
;
735 else if( strcmp( optionSuffix
, "dir" ) == 0 )
737 splitMode
= SPLIT_DIR
;
741 std::cerr
<< "The string \"" << optionSuffix
<< "\" in the command line argument \"" << *argv
<< "\" was not any of { 'no', 'flat', 'dir' }." << std::endl
;
746 else if( strcmp( *argv
, "--xpdf" ) == 0 )
752 else if( strcmp( *argv
, "--xpdf-remote" ) == 0 )
754 argcAssertion( *argv
, argc
, 2 );
755 if( xpdfServer
!= "" )
757 std::cerr
<< "The xpdf server is multiply specified." << std::endl
;
758 exit( Interaction::EXIT_INVOCATION_ERROR
);
760 xpdfServer
= *( argv
+ 1 );
764 else if( strcmp( *argv
, "--xpdf-no-server" ) == 0 )
766 if( xpdfAction
!= XPDF_DEFAULT
)
768 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
769 exit( Interaction::EXIT_INVOCATION_ERROR
);
771 xpdfAction
= XPDF_NOSERVER
;
775 else if( strcmp( *argv
, "--xpdf-reload" ) == 0 )
777 if( xpdfAction
!= XPDF_DEFAULT
)
779 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
780 exit( Interaction::EXIT_INVOCATION_ERROR
);
782 xpdfAction
= XPDF_RELOAD
;
786 else if( strcmp( *argv
, "--xpdf-quit" ) == 0 )
788 if( xpdfAction
!= XPDF_DEFAULT
)
790 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
791 exit( Interaction::EXIT_INVOCATION_ERROR
);
793 xpdfAction
= XPDF_QUIT
;
797 else if( strcmp( *argv
, "--open" ) == 0 )
803 else if( strcmp( *argv
, "--open-a" ) == 0 )
805 argcAssertion( *argv
, argc
, 2 );
807 do_open_application
= *( argv
+ 1 );
811 else if( strcmp( *argv
, "--version" ) == 0 )
814 exit( Interaction::EXIT_OK
);
820 std::cerr
<< "The name base is multiply specified." << std::endl
;
821 exit( Interaction::EXIT_INVOCATION_ERROR
);
824 if( stat( *argv
, & theStat
) == 0 &&
825 ( theStat
.st_mode
& S_IFDIR
) == 0 ) /* We are not interested in directories here. */
828 char * ext
= *argv
+ strlen( *argv
) - 6;
831 std::cerr
<< "The file name \"" << *argv
<< "\" is unexpectedly short (it should include the \".shape\" suffix)." << std::endl
;
832 exit( Interaction::EXIT_INVOCATION_ERROR
);
834 if( strcmp( ext
, ".shape" ) != 0 )
836 std::cerr
<< "Expected \".shape\" suffix in the file name \"" << *argv
<< "\"." << std::endl
;
837 exit( Interaction::EXIT_INVOCATION_ERROR
);
842 if( (*argv
)[ strlen( *argv
) - 1 ] == '.' )
844 inputName
= std::string( *argv
) + "shape";
848 inputName
= std::string( *argv
) + ".shape";
850 if( ! stat( inputName
.c_str( ), & theStat
) == 0 )
852 /* It is not entirely clear what is the best error message here,
853 * as the source file may be specified in several different ways.
854 * This should cause the least confusion.
856 std::cerr
<< "Failed to locate input file: " << *argv
<< std::endl
;
857 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
861 const char * slash
= strrchr( inputName
.c_str( ), '/' );
864 slash
= inputName
.c_str( );
870 size_t skipCount
= slash
- inputName
.c_str( );
871 baseName
= inputName
.substr( skipCount
, inputName
.length( ) - skipCount
- 6 );
878 std::cerr
<< "Illegal command line option: " << *argv
<< std::endl
;
879 exit( Interaction::EXIT_INVOCATION_ERROR
);
885 outDir
= absoluteDirectory( "" );
889 char * start
= getenv( "SHAPESTMPDIR" );
892 tmpDir
= absoluteDirectory( start
);
896 tmpDir
= absoluteDirectory( "" );
899 ensureTmpDirectoryExists( tmpDir
, allowCreateTmpDir
);
903 if( texJobName
== "" )
905 texJobName
= "#shapes.labels";
910 if( inputName
== "" )
912 inputName
= absoluteFilename( ( baseName
+ ".shape" ).c_str( ) );
914 if( outputName
== "" )
916 if( splitMode
== SPLIT_NO
)
918 outputName
= outDir
+ baseName
+ ".pdf";
922 outputName
= outDir
+ baseName
;
925 if( texJobName
== "" )
927 texJobName
= baseName
+ ".labels";
929 if( labelDBName
== "" )
931 labelDBName
= outDir
+ baseName
+ ".labels.pdf";
933 if( fontmetricsOutputName
== "" )
935 fontmetricsOutputName
= outDir
+ baseName
+ ".afm";
939 if( outputName
== "" )
941 if( ! filenameRequestList
.empty( ) )
943 /* The output name will never really be used, so it's rather harmless to assign a dummy value.
945 outputName
= "?.pdf" ;
949 std::cerr
<< "The output file is undetermined. Consider specifying it using \"--out <filename>\"." << std::endl
;
950 exit( Interaction::EXIT_INVOCATION_ERROR
);
954 if( labelDBName
== "" )
956 iterativeMode
= false;
959 if( ! Kernel::theDebugLog
.initialized( ) )
961 std::string::size_type suffixSep
= outputName
.rfind( '.' );
962 if( suffixSep
!= std::string::npos
&& outputName
.find( '/', suffixSep
) == std::string::npos
)
964 /* If there would have been a slash after the '.', the dot would have been part of a directory name.
965 * Otherwise, we conclude that we have found the extension of a filename, and replace that extension
968 Kernel::theDebugLog
.setFilename( outputName
.substr( 0, suffixSep
) + ".log" );
970 else if( baseName
!= "" )
972 Kernel::theDebugLog
.setFilename( outDir
+ baseName
+ ".log" );
976 Kernel::theDebugLog
.setFilename( outDir
+ "#shapes.log" );
982 std::string inPath
= inputName
;
983 std::string::size_type slash
= inPath
.rfind( '/' );
984 if( slash
== std::string::npos
)
986 inDir
= absoluteDirectory( "" );
990 inDir
= absoluteDirectory( inPath
.substr( 0, slash
).c_str( ) );
992 Ast::theShapesScanner
.setSourceDir( inDir
);
993 Kernel::theTeXLabelManager
.setup( inDir
, tmpDir
, texJobName
);
996 if( Computation::theTrixelizeSplicingTol
>= Computation::theTrixelizeOverlapTol
)
998 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
;
999 exit( Interaction::EXIT_INVOCATION_ERROR
);
1002 if( xpdfServer
== "" )
1004 xpdfServer
= outputName
;
1007 if( xpdfAction
== XPDF_DEFAULT
)
1009 xpdfAction
= XPDF_RAISE
;
1012 addDefaultNeedPath( );
1013 addDefaultFontMetricsPath( );
1015 #ifdef RESOURCES_DIR
1018 Ast::theShapesScanner
.push_backNeedPath( std::string( RESOURCES_DIR
) + "/extensions/" );
1019 Lang::Font::push_backFontMetricsPath( std::string( RESOURCES_DIR
) + "/fontmetrics/" );
1023 if( ! filenameRequestList
.empty( ) )
1025 std::list
< const char * >::const_iterator resource
= resourceRequestList
.begin( );
1026 for( std::list
< int >::const_iterator i
= filenameRequestList
.begin( );
1027 i
!= filenameRequestList
.end( );
1033 if( inputName
== "" )
1035 std::cout
<< "<stdin>" ;
1039 std::cout
<< inputName
;
1043 std::cout
<< outputName
;
1046 std::cout
<< tmpDir
;
1048 case FILENAME_TEXJOB
:
1049 std::cout
<< tmpDir
<< texJobName
;
1051 case FILENAME_LABELDB
:
1052 std::cout
<< labelDBName
;
1055 std::cout
<< fontmetricsOutputName
;
1057 case FILENAME_TEXINPUTS
:
1059 std::cout
<< getenv( "TEXINPUTS" ) ;
1062 case FILENAME_HTMLDOC
:
1064 std::cout
<< HTMLDIR
<< "/index.html" ;
1067 case FILENAME_RESOURCE
:
1071 std::cout
<< Ast::theShapesScanner
.searchFile( *resource
) ;
1073 catch( const Exceptions::Exception
& ball
)
1076 ball
.display( std::cerr
);
1077 exit( Interaction::EXIT_INVOCATION_ERROR
);
1083 std::cerr
<< "Internal error: filename request switch in main out of range." << std::endl
;
1084 exit( Interaction::EXIT_INTERNAL_ERROR
);
1086 std::cout
<< std::endl
;
1088 exit( Interaction::EXIT_OK
);
1091 if( pdfVersion
== SimplePDF::PDF_Version::VERSION_UNDEFINED
)
1093 pdfVersion
= SimplePDF::PDF_Version::PDF_1_4
;
1096 Kernel::the_PDF_version
.setVersion( pdfVersion
);
1097 Kernel::the_PDF_version
.setAction( pdfVersionAction
);
1100 std::ostringstream oss
;
1103 struct tm
* now( gmtime( &tmp
) );
1105 << std::setfill( '0' )
1106 << std::setw(4) << 1900 + now
->tm_year
1107 << std::setw(2) << 1 + now
->tm_mon
1108 << std::setw(2) << now
->tm_mday
1109 << std::setw(2) << now
->tm_hour
1110 << std::setw(2) << now
->tm_min
1111 << std::setw(2) << now
->tm_sec
1113 Kernel::theDocInfo
.addInfo( "CreationDate", SimplePDF::newString( oss
.str( ).c_str( ) ) );
1116 std::ifstream iFile
;
1117 if( inputName
== "" )
1119 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( "<stdin>" ) );
1120 Ast::theShapesScanner
.switch_streams( & std::cin
, & std::cerr
);
1121 Ast::theShapesScanner
.setNameOf_yyin( "stdin" );
1125 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( inputName
.c_str( ) ) );
1126 iFile
.open( inputName
.c_str( ) );
1127 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1129 std::cerr
<< "Failed to open " << inputName
<< " for input." << std::endl
;
1130 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1132 Ast::theShapesScanner
.switch_streams( & iFile
, & std::cerr
);
1133 Ast::theShapesScanner
.setNameOf_yyin( inputName
.c_str( ) );
1136 std::istringstream prependStreamIn
;
1137 if( ! prependStreamOut
.str( ).empty( ) )
1139 prependStreamIn
.str( prependStreamOut
.str( ) );
1140 Ast::theShapesScanner
.prependStream( & prependStreamIn
);
1143 RefCountPtr
< std::ifstream
> labelDBFile
= RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1144 Kernel::WarmCatalog::ShipoutList documents
;
1149 Kernel::theGlobalEnvironment
= new Kernel::Environment( Kernel::theEnvironmentList
);
1150 Kernel::registerGlobals( Kernel::theGlobalEnvironment
);
1151 Kernel::registerDynamic( Kernel::theGlobalEnvironment
);
1152 Kernel::registerHot( Kernel::theGlobalEnvironment
);
1153 Kernel::registerClasses( Kernel::theGlobalEnvironment
);
1154 Kernel::registerCore_elem( Kernel::theGlobalEnvironment
);
1155 Kernel::registerCore_point( Kernel::theGlobalEnvironment
);
1156 Kernel::registerCore_path( Kernel::theGlobalEnvironment
);
1157 Kernel::registerCore_draw( Kernel::theGlobalEnvironment
);
1158 Kernel::registerCore_construct( Kernel::theGlobalEnvironment
);
1159 Kernel::registerCore_font( Kernel::theGlobalEnvironment
);
1160 Kernel::registerCore_misc( Kernel::theGlobalEnvironment
);
1161 Kernel::registerCore_state( Kernel::theGlobalEnvironment
);
1162 Kernel::registerCore_annotation( Kernel::theGlobalEnvironment
);
1163 Kernel::registerCore_decomp( Kernel::theGlobalEnvironment
);
1164 Ast::theGlobalAnalysisEnvironment
= Kernel::theGlobalEnvironment
->newAnalysisEnvironment( );
1165 Ast::theProgram
->analyze( 0, Ast::theGlobalAnalysisEnvironment
);
1166 if( ! Ast::theAnalysisErrorsList
.empty( ) )
1169 typedef typeof Ast::theAnalysisErrorsList ListType
;
1170 for( ListType::const_iterator i
= Ast::theAnalysisErrorsList
.begin( ); i
!= Ast::theAnalysisErrorsList
.end( ); ++i
)
1173 typedef const Exceptions::StaticInconsistency ErrorType
;
1174 ErrorType
* err
= dynamic_cast< ErrorType
* >( *i
);
1177 std::cerr
<< err
->loc( ) << ": " ;
1178 err
->display( std::cerr
);
1182 std::cerr
<< "(Bad exception type)" << ": " ;
1183 (*i
)->display( std::cerr
);
1185 abortProcedure( Interaction::EXIT_USER_ERROR
);
1188 // The display unit is looked up after the input is scanned, so the user may use her own units
1189 Interaction::displayUnitFactor
= Ast::theShapesScanner
.lookupUnitFactor( Interaction::displayUnitName
);
1190 if( Interaction::displayUnitFactor
<= 0 )
1192 std::cerr
<< "Invalid display unit: " << Interaction::displayUnitName
<< std::endl
;
1193 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
1195 labelDBFile
= performIterativeStartup( labelDBName
);
1196 RefCountPtr
< const Kernel::GraphicsState
> graphicsState( new Kernel::GraphicsState( true ) );
1197 Kernel::PassedDyn
baseDyn( new Kernel::DynamicEnvironment( graphicsState
) );
1200 Kernel::EvalState
evalState( Ast::theProgram
,
1201 Kernel::theGlobalEnvironment
,
1203 Kernel::ContRef( new Kernel::ExitVoidContinuation( & done
, Ast::theProgram
->loc( ) ) ) );
1212 evalState
.cont_
->backTrace( std::cerr
);
1213 std::cerr
<< "--- Bottom of trace ---" << std::endl
;
1217 std::cerr
<< "Eval trace: Cont: " << evalState
.cont_
->traceLoc( ) << " Expr: " << evalState
.expr_
->loc( ) << std::endl
;
1220 Ast::Expression
* expr
= evalState
.expr_
;
1221 expr
->eval( & evalState
);
1224 catch( const Exceptions::StaticInconsistency
& ball
)
1227 std::cerr
<< ball
.loc( ) << ": " ;
1228 ball
.display( std::cerr
);
1229 abortProcedure( ball
.exitCode( ) );
1231 catch( Exceptions::Exception
& ball
)
1234 if( Interaction::debugBacktrace
)
1236 evalState
.cont_
->backTrace( std::cerr
);
1239 std::cerr
<< evalState
.cont_
->traceLoc( ) << Exceptions::Exception::locsep
;
1240 ball
.display( std::cerr
);
1241 abortProcedure( ball
.exitCode( ) );
1244 Kernel::WarmCatalog
* catalog
= dynamic_cast< Kernel::WarmCatalog
* >( Kernel::theGlobalEnvironment
->getStateHandle( Ast::theGlobalAnalysisEnvironment
->findLocalStatePosition( Ast::THE_UNKNOWN_LOCATION
, Lang::CATALOG_ID
) ) );
1245 RefCountPtr
< const Lang::Group2D
> finalPicture
= dynamic_cast< Kernel::WarmGroup2D
* >( Kernel::theGlobalEnvironment
->getStateHandle( Ast::theGlobalAnalysisEnvironment
->findLocalStatePosition( Ast::THE_UNKNOWN_LOCATION
, Lang::CANVAS_ID
) ) )->getPile( );
1246 if( catalog
->isEmpty( ) && finalPicture
->isNull( ) )
1248 throw Exceptions::EmptyFinalPicture( );
1250 if( catalog
->isEmpty( ) )
1252 catalog
->tackOnPage( baseDyn
, finalPicture
, Ast::THE_UNKNOWN_LOCATION
);
1255 catalog
->shipout( splitMode
!= SPLIT_NO
, & documents
);
1259 Kernel::theGlobalEnvironment
->clear( );
1262 delete Kernel::theGlobalEnvironment
;
1263 delete Ast::theProgram
;
1265 catch( const Exceptions::StaticInconsistency
& ball
)
1268 std::cerr
<< ball
.loc( ) << ": " ;
1269 ball
.display( std::cerr
);
1270 abortProcedure( ball
.exitCode( ) );
1272 catch( const Exceptions::Exception
& ball
)
1275 ball
.display( std::cerr
);
1276 abortProcedure( ball
.exitCode( ) );
1278 catch( const NonLocalExit::DynamicBindingNotFound
& ball
)
1280 std::cerr
<< "Caught DynamicBindingNotFound at top level." << std::endl
1281 << "This should really not be possible; it is an internal error." << std::endl
;
1282 exit( Interaction::EXIT_INTERNAL_ERROR
);
1284 catch( const NonLocalExit::NotThisType
& ball
)
1286 std::cerr
<< "Caught NotThisType at top level." << std::endl
1287 << "This should really not be possible; it is an internal error." << std::endl
;
1288 exit( Interaction::EXIT_INTERNAL_ERROR
);
1290 catch( const NonLocalExit::NonLocalExitBase
& ball
)
1292 std::cerr
<< "Caught an unknown descendant to NonLocalExitBase at top level." << std::endl
1293 << "This should really not be possible; it is an internal error." << std::endl
;
1294 exit( Interaction::EXIT_INTERNAL_ERROR
);
1296 catch( const char * ball
)
1298 std::cerr
<< "Caught (char*) ball at top level:" << std::endl
1299 << " " << ball
<< std::endl
;
1300 exit( Interaction::EXIT_GENERIC_ERROR
);
1302 catch( const std::string
& ball
)
1304 std::cerr
<< "Caught (string) ball at top level:" << std::endl
1305 << " " << ball
<< std::endl
;
1306 exit( Interaction::EXIT_GENERIC_ERROR
);
1310 std::cerr
<< "Caught (...) ball at top level." << std::endl
;
1311 exit( Interaction::EXIT_GENERIC_ERROR
);
1314 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1316 abortProcedure( Interaction::EXIT_USER_ERROR
);
1321 std::cerr
<< "Summary:" << std::endl
;
1322 std::cerr
<< "Environments: alive: " << Kernel::Environment::liveCount
<< " of total: " << Kernel::Environment::createdCount
1323 << " (" << 100 * static_cast< double >( Kernel::Environment::liveCount
) / static_cast< double >( Kernel::Environment::createdCount
) << "%)" << std::endl
;
1330 if( documents
.size( ) != 1 )
1332 std::cerr
<< "Internal error: Failed to produce exactly one document of output although --split=no." << std::endl
;
1334 std::ofstream oFile
;
1335 oFile
.open( outputName
.c_str( ) );
1336 if( ! oFile
.good( ) )
1338 /* If this is because the output directory does not exist, we shall inform the user about this. */
1339 std::string::size_type slash
= outputName
.rfind( '/' );
1340 if( slash
!= std::string::npos
)
1342 std::string outputDir
= outputName
.substr( 0, slash
);
1343 struct stat theStat
;
1344 if( stat( outputDir
.c_str( ), & theStat
) == 0 )
1346 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1348 std::cerr
<< "The prefix " << outputDir
<< " of the output name must be a directory." << std::endl
;
1349 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1351 /* In case we reach here, the directory exists, so we fall back on the generic error message below. */
1355 std::cerr
<< "The file " << outputName
<< " cannot be opened for output since the directory " << outputDir
<< " does not exist." << std::endl
;
1356 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1359 std::cerr
<< "Failed to open " << outputName
<< " for output." << std::endl
;
1360 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1362 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
1367 std::ostringstream rmCommand
;
1368 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1369 escapeExtGlobChars( outputName
, rmCommand
);
1370 rmCommand
<< "-+([0-9]).pdf'" ;
1371 Interaction::systemDebugMessage( rmCommand
.str( ) );
1372 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1374 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1376 size_t physicalPageNo
= 1;
1377 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1379 std::ostringstream tmpFilename
;
1380 tmpFilename
<< outputName
<< "-" << physicalPageNo
<< ".pdf" ;
1381 std::ofstream oFile
;
1382 oFile
.open( tmpFilename
.str( ).c_str( ) );
1383 if( ! oFile
.good( ) )
1385 std::cerr
<< "Failed to open " << tmpFilename
.str( ) << " for output." << std::endl
;
1386 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1388 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1394 struct stat theStat
;
1395 if( stat( outputName
.c_str( ), & theStat
) == 0 )
1397 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1399 std::cerr
<< "The path " << outputName
<< " was expected to reference a directory." << std::endl
;
1400 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1405 if( mkdir( outputName
.c_str( ), S_IRWXU
| S_IRWXG
| S_IRWXO
) != 0 )
1407 std::cerr
<< "Failed to create directory for split document files (errno=" << errno
<< "): " << outputName
<< std::endl
;
1408 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1411 std::ostringstream rmCommand
;
1412 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1413 escapeExtGlobChars( outputName
, rmCommand
);
1414 rmCommand
<< "/+([0-9]).pdf'" ;
1415 Interaction::systemDebugMessage( rmCommand
.str( ) );
1416 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1418 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1420 size_t physicalPageNo
= 1;
1421 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1423 std::ostringstream tmpFilename
;
1424 tmpFilename
<< outputName
<< "/" << physicalPageNo
<< ".pdf" ;
1425 std::ofstream oFile
;
1426 oFile
.open( tmpFilename
.str( ).c_str( ) );
1427 if( ! oFile
.good( ) )
1429 std::cerr
<< "Failed to open " << tmpFilename
.str( ) << " for output." << std::endl
;
1430 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1432 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1438 /* This must be done after the output has been written, and before iterativeFinish writes to the labels database file.
1440 Kernel::thePDFImporter
.free( );
1442 if( labelDBFile
!= NullPtr
< std::ifstream
>( ) )
1444 if( labelDBFile
->is_open( ) )
1446 labelDBFile
->close( );
1448 labelDBFile
= NullPtr
< std::ifstream
>( ); // Free the reference.
1453 Kernel::theTeXLabelManager
.iterativeFinish( labelDBName
);
1458 if( splitMode
!= SPLIT_NO
)
1460 std::cerr
<< "Warning: not launching viewer since the documet was split" << std::endl
;
1464 xpdfHelper( outputName
, xpdfServer
, xpdfAction
);
1470 if( splitMode
!= SPLIT_NO
)
1472 std::cerr
<< "Warning: not launching viewer since the documet was split" << std::endl
;
1476 openHelper( outputName
, do_open_application
);
1487 argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
)
1489 if( argc
< argcMin
)
1491 std::cerr
<< "The command line option " << optionSpecifier
<< " requires " << argcMin
- 1 << " parameters." << std::endl
;
1492 exit( Interaction::EXIT_INVOCATION_ERROR
);
1497 strprefixcmp( char * str
, const char * prefix
, char ** endp
)
1499 int len
= strlen( prefix
);
1500 bool res
= ( strncmp( str
, prefix
, len
) == 0 );
1506 strtobool( const char * str
, const char * containingString
, const char * trueLabel
, const char * falseLabel
)
1508 if( trueLabel
!= 0 &&
1509 strcmp( str
, trueLabel
) == 0 )
1513 if( falseLabel
!= 0 &&
1514 strcmp( str
, falseLabel
) == 0 )
1518 if( strcmp( str
, "yes" ) == 0 ||
1519 strcmp( str
, "true" ) == 0 ||
1520 strcmp( str
, "on" ) == 0 )
1524 if( strcmp( str
, "no" ) == 0 ||
1525 strcmp( str
, "false" ) == 0 ||
1526 strcmp( str
, "off" ) == 0)
1530 std::cerr
<< "The string \"" << str
<< "\" in the command line argument \"" << containingString
<< "\" was not recognized as a boolean value." << std::endl
;
1531 exit( Interaction::EXIT_INVOCATION_ERROR
);
1535 RefCountPtr
< std::ifstream
>
1536 performIterativeStartup( const std::string
& labelDBName
)
1539 struct stat theStat
;
1540 if( stat( labelDBName
.c_str( ), & theStat
) != 0 )
1542 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1546 // ostringstream mvCommand;
1547 // mvCommand << "cp '" << oldFilename.str( ) << "' '" << labelDBName.str( ) << "'" ;
1548 // Interaction::systemDebugMessage( mvCommand.str( ) );
1549 // if( system( mvCommand.str( ).c_str( ) ) != 0 )
1551 // return RefCountPtr< std::ifstream >( NullPtr< std::ifstream >( ) );
1554 RefCountPtr
< std::ifstream
> labelsFile( new std::ifstream( labelDBName
.c_str( ) ) );
1555 if( ! labelsFile
->good( ) )
1557 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1561 Kernel::theTeXLabelManager
.iterativeStartup( labelsFile
);
1564 catch( const char * ball
)
1566 std::cerr
<< "Caught (char*) ball from iterative startup:" << std::endl
1567 << " " << ball
<< std::endl
;
1568 exit( Interaction::EXIT_GENERIC_ERROR
);
1570 catch( const std::string
& ball
)
1572 std::cerr
<< "Caught (string) ball from iterative startup:" << std::endl
1573 << " " << ball
<< std::endl
;
1574 exit( Interaction::EXIT_GENERIC_ERROR
);
1576 catch( const Exceptions::Exception
& ball
)
1578 ball
.display( std::cerr
);
1579 exit( ball
.exitCode( ) );
1583 std::cerr
<< "Caught (...) ball from iterative startup." << std::endl
;
1584 exit( Interaction::EXIT_GENERIC_ERROR
);
1590 abortProcedure( int exitCode
)
1592 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1595 while( ! Kernel::thePostCheckErrorsList
.empty( ) )
1597 Exceptions::Exception
* e
= Kernel::thePostCheckErrorsList
.front( );
1598 Kernel::thePostCheckErrorsList
.pop_front( );
1600 typedef const Exceptions::PostCondition ErrorType
;
1601 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1604 std::cerr
<< err
->loc( ) << ": " ;
1605 err
->display( std::cerr
);
1610 typedef const Exceptions::RuntimeError ErrorType
;
1611 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1614 std::cerr
<< err
->getLoc( ) << " (runtime): " ;
1615 err
->display( std::cerr
);
1619 std::cerr
<< "(Bad post-exception type)" << ": " ;
1620 e
->display( std::cerr
);
1623 std::cerr
<< "Aborting job. Output files are left unchanged." << std::endl
;
1631 void setSelfRef( RefCountPtr
< const Lang::Class
> cls
)
1633 cls
->setSelfRef( cls
);
1635 void initMutators( RefCountPtr
< const Lang::Class
> cls
)
1637 Lang::SystemFinalClass
* typedPtr
= dynamic_cast< Lang::SystemFinalClass
* >( const_cast< Lang::Class
* >( cls
.getPtr( ) ) );
1640 typedPtr
->initMutators( );
1644 std::cerr
<< "Helpers::initMutators was called with object of bad type." << std::endl
;
1645 exit( Interaction::EXIT_INTERNAL_ERROR
);
1654 Lang::ElementaryPath2D
* bbox
= new Lang::ElementaryPath2D
;
1655 bbox
->push_back( new Concrete::PathPoint2D( 0, 0 ) );
1657 Lang::THE_POINTPICTURE
= RefCountPtr
< Lang::Drawable2D
>( new Lang::BBoxed2D( Lang::THE_NULL2D
,
1658 RefCountPtr
< Lang::ElementaryPath2D
>( bbox
) ) );
1659 Helpers::setSelfRef( Lang::THE_OBJECT
);
1661 Helpers::setSelfRef( Lang::Void::TypeID
);
1662 Helpers::setSelfRef( Lang::Symbol::TypeID
);
1663 Helpers::setSelfRef( Lang::Float::TypeID
);
1664 Helpers::setSelfRef( Lang::Length::TypeID
);
1665 Helpers::setSelfRef( Lang::Boolean::TypeID
);
1666 Helpers::setSelfRef( Lang::String::TypeID
);
1667 Helpers::setSelfRef( Lang::FloatPair::TypeID
);
1668 Helpers::setSelfRef( Lang::FloatTriple::TypeID
);
1669 Helpers::setSelfRef( Lang::Coords2D::TypeID
);
1670 Helpers::setSelfRef( Lang::CornerCoords2D::TypeID
);
1671 Helpers::setSelfRef( Lang::Coords3D::TypeID
);
1673 Helpers::setSelfRef( Lang::Function::TypeID
);
1674 Helpers::setSelfRef( Lang::Transform2D::TypeID
);
1675 Helpers::setSelfRef( Lang::Transform3D::TypeID
);
1677 Helpers::setSelfRef( Lang::Class::TypeID
);
1679 Helpers::setSelfRef( Lang::TransformedInstance::TypeID
);
1681 Helpers::initMutators( Kernel::WarmGroup2D::TypeID
);
1682 Helpers::initMutators( Kernel::WarmGroup3D::TypeID
);
1683 Helpers::initMutators( Kernel::WarmCatalog::TypeID
);
1686 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric2D" ) );
1687 Lang::Geometric2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1688 Helpers::setSelfRef( Lang::Geometric2D::TypeID
);
1689 /* Note that addVirtual must not be called before the selfRef is set!
1693 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric3D" ) );
1694 Lang::Geometric3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1695 Helpers::setSelfRef( Lang::Geometric3D::TypeID
);
1696 /* Note that addVirtual must not be called before the selfRef is set!
1700 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable2D" ) );
1701 Lang::Drawable2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1702 Helpers::setSelfRef( Lang::Drawable2D::TypeID
);
1703 /* Note that addVirtual must not be called before the selfRef is set!
1705 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1708 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable3D" ) );
1709 Lang::Drawable3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1710 Helpers::setSelfRef( Lang::Drawable3D::TypeID
);
1711 /* Note that addVirtual must not be called before the selfRef is set!
1713 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1716 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Color" ) );
1717 Lang::Color::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1718 Helpers::setSelfRef( Lang::Color::TypeID
);
1719 /* Note that addVirtual must not be called before the selfRef is set!
1721 tmp
->addVirtual( "stroking" );
1722 tmp
->addVirtual( "nonstroking" );
1727 xpdfHelper( const std::string
& filename
, const std::string
& server
, const XpdfAction
& action
)
1729 pid_t xpdfProcess
= fork( );
1730 if( xpdfProcess
== -1 )
1732 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running xpdf." ) );
1735 if( xpdfProcess
== 0 ) /* This is the child */
1737 /* The exec call below never returns, so the child process never leaves this if clause.
1738 * Hence, there is no need to create a special else clasuse below.
1743 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-raise", filename
.c_str( ), static_cast< const char * >( 0 ) );
1746 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-reload", static_cast< const char * >( 0 ) );
1749 execlp( "xpdf", "xpdf", "-remote", server
.c_str( ), "-quit", static_cast< const char * >( 0 ) );
1752 execlp( "xpdf", "xpdf", filename
.c_str( ), static_cast< const char * >( 0 ) );
1755 std::cerr
<< "Internal error: XpdfAction switch out of range." << std::endl
;
1756 exit( Interaction::EXIT_INTERNAL_ERROR
);
1760 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to xpdf." << std::endl
;
1761 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1763 std::cerr
<< "execlp call to xpdf returned with errno == 0." << std::endl
;
1764 exit( Interaction::EXIT_INTERNAL_ERROR
);
1770 openHelper( const std::string
& filename
, const char * application
)
1772 pid_t openProcess
= fork( );
1773 if( openProcess
== -1 )
1775 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running open." ) );
1778 if( openProcess
== 0 ) /* This is the child */
1780 /* The exec call below never returns, so the child process never leaves this if clause.
1781 * Hence, there is no need to create a special else clasuse below.
1783 if( application
!= 0 )
1785 execlp( "open", "open", "-a", application
, filename
.c_str( ), static_cast< const char * >( 0 ) );
1789 execlp( "open", "open", filename
.c_str( ), static_cast< const char * >( 0 ) );
1793 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to open." << std::endl
;
1794 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1796 std::cerr
<< "execlp call to open returned with errno == 0." << std::endl
;
1797 exit( Interaction::EXIT_INTERNAL_ERROR
);
1803 Interaction::systemDebugMessage( const std::string
& msg
)
1805 if( Interaction::debugSystem
)
1807 std::cerr
<< "System command: " << msg
<< std::endl
;
1812 addDefaultNeedPath( )
1814 char * start
= getenv( "SHAPESINPUTS" );
1817 Ast::theShapesScanner
.push_backNeedPath( "./" );
1820 char * tok
= strsep( & start
, ":" );
1823 Ast::theShapesScanner
.push_backNeedPath( tok
);
1824 tok
= strsep( & start
, ":" );
1829 addDefaultFontMetricsPath( )
1831 char * start
= getenv( "SHAPESFONTMETRICS" );
1836 char * tok
= strsep( & start
, ":" );
1839 Lang::Font::push_backFontMetricsPath( tok
);
1840 tok
= strsep( & start
, ":" );
1847 Helpers::requireUTF8ToMacRomanConverter( true ); // true means "cleanup"
1848 Helpers::requireMacRomanToUTF8Converter( true ); // true means "cleanup"
1849 Helpers::requireUTF8ToWinANSIConverter( true ); // true means "cleanup"
1850 Helpers::requireUTF8ToASCIIConverter( true ); // true means "cleanup"
1851 Helpers::requireUTF8ToUCS4Converter( true ); // true means "cleanup"
1852 Helpers::requireUTF16BEToUCS4Converter( true ); // true means "cleanup"
1853 Helpers::requireGlyphList( true ); // true means "cleanup"
1854 Helpers::requireMacRomanEncoding( true ); // true means "cleanup"
1858 absoluteFilename( const char * filename
)
1860 if( *filename
== '/' )
1864 return callDir
+ filename
;
1868 absoluteDirectory( const char * filename
)
1870 if( *filename
== '\0' )
1874 if( filename
[ strlen( filename
) - 1 ] != '/' )
1876 if( *filename
== '/' )
1878 return filename
+ std::string( "/" );
1880 return callDir
+ filename
+ "/";
1882 if( *filename
== '/' )
1886 return callDir
+ filename
;
1892 ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
)
1894 struct stat theStat
;
1895 if( stat( dirname
.c_str( ), & theStat
) == 0 )
1897 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1899 std::cerr
<< "The path " << dirname
<< " was expected to reference a directory." << std::endl
;
1900 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1902 // if( ( theStat.st_mode & S_IWOTH ) == 0 )
1904 // std::cerr << "The directory " << dirname << " was expected have write permission for others." << std::endl ;
1905 // exit( Interaction::EXIT_FILE_PERMISSION_ERROR );
1912 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
;
1913 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1916 size_t i2
= 0; /* We know there's a slash at the first position */
1917 i2
= dirname
.find( '/', i2
+ 1 );
1919 while( stat( dirname
.substr( 0, i2
).c_str( ), & theStat
) == 0 )
1922 i2
= dirname
.find( '/', i2
+ 1 );
1926 std::cerr
<< "Shapes will not create directories for temporary files at the root: " << dirname
<< std::endl
;
1927 exit( Interaction::EXIT_INVOCATION_ERROR
);
1930 mode_t oldUmask
= umask( 0 ); /* We want to be able to create directories with any permissions. */
1931 while( i2
!= std::string::npos
)
1933 if( mkdir( dirname
.substr( 0, i2
).c_str( ), theStat
.st_mode
& ( S_IRWXU
| S_IRWXG
| S_IRWXO
) ) != 0 )
1935 std::cerr
<< "Failed to create directory for temporary files (errno=" << errno
<< "): " << dirname
.substr( 0, i2
) << std::endl
;
1936 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1938 i2
= dirname
.find( '/', i2
+ 1 );
1944 escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
)
1946 const char * special
= "*?[+@!";
1947 for( std::string::const_iterator i
= str
.begin( ); i
!= str
.end( ); ++i
)
1949 if( strchr( special
, *i
) != 0 )