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, 2010, 2013, 2014 Henrik Tidefelt
21 using namespace Shapes
;
22 using namespace SimplePDF
;
28 void systemDebugMessage( const std::string
& msg
);
32 Interaction::PreviewOptions::PreviewOptions( )
33 : launch_xpdf( false ),
34 xpdfAction( XPDF_DEFAULT
),
36 do_open_application( 0 )
40 Shapes::Interaction::PreviewOptions previewOptions
;
41 Shapes::Interaction::InteractionFormats interactionFormats
;
44 main( int argc
, char ** argv
)
50 bool iterativeMode
= true;
51 bool useResources
= true;
52 bool interactiveMode
= false;
53 bool forceBlankMode
= false;
54 bool forceShapeMode
= false;
57 char * cwd
= getcwd( 0, 0 );
58 callDir
= cwd
+ std::string( "/" );
64 bool allowCreateTmpDir
= false;
66 std::string inputName
;
67 std::string outputName
;
68 std::string texJobName
;
69 std::string labelDBName
;
70 std::string fontmetricsOutputName
;
72 enum FilenameRequests
{ FILENAME_RESOURCE
, FILENAME_IN
, FILENAME_OUT
, FILENAME_TMP
, FILENAME_TEXJOB
, FILENAME_LABELDB
, FILENAME_AFM
, FILENAME_TEXINPUTS
, FILENAME_HTMLDOC
, FILENAME_SHARE
};
74 std::list
< int > filenameRequestList
;
75 std::list
< const char * > resourceRequestList
;
77 bool evalTrace
= false;
78 bool evalBackTrace
= false;
79 bool cleanupMemory
= true;
80 bool memoryStats
= false;
81 SimplePDF::PDF_Version::Version pdfVersion
= SimplePDF::PDF_Version::VERSION_UNDEFINED
;
82 SimplePDF::PDF_Version::Action pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
83 std::ostringstream prependStreamOut
;
85 SplitMode splitMode
= SPLIT_NO
;
90 if( argc
> 0 && strcmp( *argv
, "--help" ) == 0 )
94 std::cerr
<< "The --help command line switch must appear alone." << std::endl
;
95 exit( Interaction::EXIT_INVOCATION_ERROR
);
103 const char * optionPrefix
;
105 if( strcmp( *argv
, "--yydebug" ) == 0 )
111 else if( strcmp( *argv
, "--shapes-debug" ) == 0 )
117 else if( strcmp( *argv
, "--system-debug" ) == 0 )
119 Interaction::debugSystem
= true;
123 else if( strcmp( *argv
, "--afm-debug" ) == 0 )
125 Interaction::fontMetricDebug
= true;
129 else if( strcmp( *argv
, "--afm-messages" ) == 0 )
131 Interaction::fontMetricMessages
= true;
135 else if( strcmp( *argv
, "--tex-debug" ) == 0 )
137 Interaction::pdfLaTeXInteractionTo_stderr
= true;
141 else if( strcmp( *argv
, "--log-globals" ) == 0 )
143 Interaction::logGlobals
= true;
147 else if( strprefixcmp( *argv
, "--bytecolumn=", & optionPrefix
, & optionSuffix
) )
149 Interaction::characterColumnInBytes
= strtobool( optionSuffix
, *argv
);
153 else if( strprefixcmp( *argv
, "--debugstep=", & optionPrefix
, & optionSuffix
) )
156 int tmp
= strtol( optionSuffix
, & endp
, 10 );
159 std::cerr
<< "The --debugstep value must be nonnegative: " << optionSuffix
<< std::endl
;
160 exit( Interaction::EXIT_INVOCATION_ERROR
);
162 Interaction::debugStep
= static_cast< size_t >( tmp
);
166 else if( strcmp( *argv
, "--debuglog" ) == 0 )
168 argcAssertion( *argv
, argc
, 2 );
171 Kernel::theDebugLog
.setFilename( *( argv
+ 1 ) );
173 catch( const char * ball
)
175 std::cerr
<< ball
<< std::endl
;
176 exit( Interaction::EXIT_INVOCATION_ERROR
);
181 else if( strcmp( *argv
, "--debuglog-stderr" ) == 0 )
185 Kernel::theDebugLog
.setStream( & std::cerr
);
187 catch( const char * ball
)
189 std::cerr
<< ball
<< std::endl
;
190 exit( Interaction::EXIT_INVOCATION_ERROR
);
195 else if( strcmp( *argv
, "--debuglog-stdout" ) == 0 )
199 Kernel::theDebugLog
.setStream( & std::cout
);
201 catch( const char * ball
)
203 std::cerr
<< ball
<< std::endl
;
204 exit( Interaction::EXIT_INVOCATION_ERROR
);
209 else if( strprefixcmp( *argv
, "--dtminerror=", & optionPrefix
, & optionSuffix
) )
211 Computation::dtMinIsError
= strtobool( optionSuffix
, *argv
);
215 else if( strprefixcmp( *argv
, "--fmguesserror=", & optionPrefix
, & optionSuffix
) )
217 Computation::fontMetricGuessIsError
= strtobool( optionSuffix
, *argv
);
221 else if( strcmp( *argv
, "--interactive") == 0 ||
222 strcmp( *argv
, "-i") == 0 )
224 interactiveMode
= true;
228 else if( strcmp( *argv
, "--blank") == 0 )
230 if( forceShapeMode
){
231 std::cerr
<< "Conflicting forcing of both blank mode and shape mode." << std::endl
;
232 exit( Interaction::EXIT_INVOCATION_ERROR
);
234 forceBlankMode
= true;
238 else if( strcmp( *argv
, "--shape") == 0 )
240 if( forceBlankMode
){
241 std::cerr
<< "Conflicting forcing of both blank mode and shape mode." << std::endl
;
242 exit( Interaction::EXIT_INVOCATION_ERROR
);
244 forceShapeMode
= true;
248 else if( strprefixcmp( *argv
, "--i-format-prompt=", & optionPrefix
, & optionSuffix
) ||
249 strprefixcmp( *argv
, "-?P", & optionPrefix
, & optionSuffix
) )
251 interactionFormats
.setPrompt( strdup( optionSuffix
) );
255 else if( strprefixcmp( *argv
, "--i-format-show=", & optionPrefix
, & optionSuffix
) ||
256 strprefixcmp( *argv
, "-?S", & optionPrefix
, & optionSuffix
) )
258 interactionFormats
.setShow( strdup( optionSuffix
) );
262 else if( strprefixcmp( *argv
, "--i-format-file=", & optionPrefix
, & optionSuffix
) ||
263 strprefixcmp( *argv
, "-?F", & optionPrefix
, & optionSuffix
) )
265 interactionFormats
.setFile( strdup( optionSuffix
) );
269 else if( strprefixcmp( *argv
, "--i-format-eof=", & optionPrefix
, & optionSuffix
) ||
270 strprefixcmp( *argv
, "-?E", & optionPrefix
, & optionSuffix
) )
272 interactionFormats
.setBye( strdup( optionSuffix
) );
276 else if( strcmp( *argv
, "--evaltrace" ) == 0 )
282 else if( strcmp( *argv
, "--evalbacktrace" ) == 0 )
285 evalBackTrace
= true;
289 else if( strprefixcmp( *argv
, "--backtrace=", & optionPrefix
, & optionSuffix
) )
291 Interaction::debugBacktrace
= strtobool( optionSuffix
, *argv
);
295 else if( strprefixcmp( *argv
, "--iteration=", & optionPrefix
, & optionSuffix
) )
297 iterativeMode
= strtobool( optionSuffix
, *argv
);
301 else if( strprefixcmp( *argv
, "--resources=", & optionPrefix
, & optionSuffix
) )
303 useResources
= strtobool( optionSuffix
, *argv
);
307 else if( strprefixcmp( *argv
, "--stats=", & optionPrefix
, & optionSuffix
) )
309 memoryStats
= strtobool( optionSuffix
, *argv
);
313 else if( strprefixcmp( *argv
, "--memclean=", & optionPrefix
, & optionSuffix
) )
315 cleanupMemory
= strtobool( optionSuffix
, *argv
);
319 else if( strprefixcmp( *argv
, "--showfiles=", & optionPrefix
, & optionSuffix
) )
321 Ast::theShapesScanner
.setShowFiles( strtobool( optionSuffix
, *argv
) );
325 else if( strprefixcmp( *argv
, "--pdf-version=", & optionPrefix
, & optionSuffix
) || /* Note that we use that || shortcuts! */
326 strprefixcmp( *argv
, "-v", & optionPrefix
, & optionSuffix
) )
328 if( pdfVersion
!= SimplePDF::PDF_Version::VERSION_UNDEFINED
)
330 std::cerr
<< "Multiply defined pdf version." << std::endl
;
331 exit( Interaction::EXIT_INVOCATION_ERROR
);
334 switch( *optionSuffix
)
337 pdfVersionAction
= SimplePDF::PDF_Version::ERROR
;
340 pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
343 pdfVersionAction
= SimplePDF::PDF_Version::SILENT
;
346 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
;
347 exit( Interaction::EXIT_INVOCATION_ERROR
);
350 if( strncmp( optionSuffix
, "1.", 2 ) == 0 &&
351 '1' <= optionSuffix
[2] && optionSuffix
[2] <= '6' )
353 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
};
354 pdfVersion
= versions
[ optionSuffix
[2] - '1' ];
356 else if( strcmp( optionSuffix
, "X" ) == 0 )
358 std::cerr
<< "Restriction to PDF-X is not implemented, please try using a low version number, such as 1.1 instead." << std::endl
;
362 std::cerr
<< "Unsupported pdf version specification: " << optionSuffix
<< std::endl
;
363 exit( Interaction::EXIT_INVOCATION_ERROR
);
368 else if( strprefixcmp( *argv
, "--warn=", & optionPrefix
, & optionSuffix
) ||
369 strprefixcmp( *argv
, "-W", & optionPrefix
, & optionSuffix
) )
371 if( strcmp( optionSuffix
, "display" ) == 0 ||
372 strcmp( optionSuffix
, "d" ) == 0 )
374 Interaction::warningAction
= Interaction::WARNING_DISPLAY
;
376 else if( strcmp( optionSuffix
, "error" ) == 0 ||
377 strcmp( optionSuffix
, "e" ) == 0 )
379 Interaction::warningAction
= Interaction::WARNING_ERROR
;
381 else if( strcmp( optionSuffix
, "ignore" ) == 0 ||
382 strcmp( optionSuffix
, "i" ) == 0 )
384 Interaction::warningAction
= Interaction::WARNING_IGNORE
;
388 std::cerr
<< "Unsupported warning action: " << optionSuffix
<< std::endl
;
389 exit( Interaction::EXIT_INVOCATION_ERROR
);
394 else if( strprefixcmp( *argv
, "--tp=", & optionPrefix
, & optionSuffix
) )
396 Kernel::allowTransparency
= strtobool( optionSuffix
, *argv
);
400 else if( strprefixcmp( *argv
, "--spot-pair=", & optionPrefix
, & optionSuffix
) )
402 Kernel::allowSingletonPaths
= ! strtobool( optionSuffix
, *argv
);
406 else if( strprefixcmp( *argv
, "--unit=", & optionPrefix
, & optionSuffix
) )
408 Interaction::displayUnitName
= optionSuffix
;
413 else if( strprefixcmp( *argv
, "--splicingtol=", & optionPrefix
, & optionSuffix
) )
417 Computation::theTrixelizeSplicingTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
421 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
422 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
424 if( Computation::theTrixelizeSplicingTol
<= 0 )
426 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeSplicingTol
.offtype
< 1, 0 >( ) << std::endl
;
427 exit( Interaction::EXIT_INVOCATION_ERROR
);
433 else if( strprefixcmp( *argv
, "--overlaptol=", & optionPrefix
, & optionSuffix
) )
437 Computation::theTrixelizeOverlapTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
441 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
442 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
444 if( Computation::theTrixelizeOverlapTol
<= 0 )
446 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeOverlapTol
.offtype
< 1, 0 >( ) << std::endl
;
447 exit( Interaction::EXIT_INVOCATION_ERROR
);
453 else if( strcmp( *argv
, "--needpath" ) == 0 ||
454 strncmp( *argv
, "-N", 2 ) == 0 )
456 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
458 const char * pth
= 0;
461 argcAssertion( *argv
, argc
, 2 );
469 if( strchr( pth
, ':' ) != 0 )
471 const char * flag
= 0;
472 const char * shortFlag
= "-N";
482 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
485 std::cerr
<< " (or " << shortFlag
<< ")" ;
487 std::cerr
<<"." << std::endl
;
488 exit( Interaction::EXIT_INVOCATION_ERROR
);
491 Ast::theShapesScanner
.push_backNeedPath( absoluteDirectory( pth
) );
504 else if( strcmp( *argv
, "--fontmetricspath" ) == 0 ||
505 strncmp( *argv
, "-M", 2 ) == 0 )
507 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
509 const char * pth
= 0;
512 argcAssertion( *argv
, argc
, 2 );
520 if( strchr( pth
, ':' ) != 0 )
522 const char * flag
= 0;
523 const char * shortFlag
= "-M";
533 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
536 std::cerr
<< " (or " << shortFlag
<< ")" ;
538 std::cerr
<<"." << std::endl
;
539 exit( Interaction::EXIT_INVOCATION_ERROR
);
542 Lang::Font::push_backFontMetricsPath( absoluteDirectory( pth
) );
555 else if( strprefixcmp( *argv
, "--seed=", & optionPrefix
, & optionSuffix
) )
558 long s
= strtol( optionSuffix
, &endp
, 10 );
561 std::cerr
<< "Argument to " << optionPrefix
<< " was not an integer: " << optionSuffix
<< std::endl
;
562 exit( Interaction::EXIT_INVOCATION_ERROR
);
570 else if( strprefixcmp( *argv
, "--arcdelta=", & optionPrefix
, & optionSuffix
) )
574 Computation::the_arcdelta
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
578 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
579 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
581 if( Computation::the_arcdelta
<= 0 )
583 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
584 exit( Interaction::EXIT_INVOCATION_ERROR
);
590 else if( strprefixcmp( *argv
, "--dtmin=", & optionPrefix
, & optionSuffix
) )
593 Computation::the_dtMin
= strtod( optionSuffix
, &endp
);
596 std::cerr
<< "Argument to " << optionPrefix
<< " was not a float: " << optionSuffix
<< std::endl
;
597 exit( Interaction::EXIT_INVOCATION_ERROR
);
599 if( Computation::the_dtMin
<= 0 )
601 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::the_dtMin
<< std::endl
;
602 exit( Interaction::EXIT_INVOCATION_ERROR
);
608 else if( strprefixcmp( *argv
, "--disttol=", & optionPrefix
, & optionSuffix
) )
612 Computation::theDistanceTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
616 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
617 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
619 if( Computation::theDistanceTol
<= 0 )
621 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
622 exit( Interaction::EXIT_INVOCATION_ERROR
);
628 else if( strcmp( *argv
, "--prepend" ) == 0 )
630 argcAssertion( *argv
, argc
, 2 );
631 prependStreamOut
<< *( argv
+ 1 ) << std::endl
;
635 else if( strcmp( *argv
, "--base" ) == 0 )
637 argcAssertion( *argv
, argc
, 2 );
640 std::cerr
<< "The name base is multiply specified." << std::endl
;
641 exit( Interaction::EXIT_INVOCATION_ERROR
);
643 baseName
= *( argv
+ 1 );
647 else if( strcmp( *argv
, "--which" ) == 0 )
649 argcAssertion( *argv
, argc
, 2 );
650 filenameRequestList
.push_back( FILENAME_RESOURCE
);
651 resourceRequestList
.push_back( *( argv
+ 1 ) );
655 else if( strcmp( *argv
, "--in" ) == 0 )
657 argcAssertion( *argv
, argc
, 2 );
658 if( inputName
!= "" )
660 std::cerr
<< "The input file is multiply specified." << std::endl
;
661 exit( Interaction::EXIT_INVOCATION_ERROR
);
663 inputName
= absoluteFilename( *( argv
+ 1 ) );
667 else if( strcmp( *argv
, "--which-in" ) == 0 )
669 filenameRequestList
.push_back( FILENAME_IN
);
673 else if( strcmp( *argv
, "--out" ) == 0 )
675 argcAssertion( *argv
, argc
, 2 );
676 if( outputName
!= "" )
678 std::cerr
<< "The output file is multiply specified." << std::endl
;
679 exit( Interaction::EXIT_INVOCATION_ERROR
);
681 outputName
= absoluteFilename( *( argv
+ 1 ) );
685 else if( strcmp( *argv
, "--which-out" ) == 0 )
687 filenameRequestList
.push_back( FILENAME_OUT
);
691 else if( strcmp( *argv
, "--texjob" ) == 0 )
693 argcAssertion( *argv
, argc
, 2 );
694 if( texJobName
!= "" )
696 std::cerr
<< "The tex job name is multiply specified." << std::endl
;
697 exit( Interaction::EXIT_INVOCATION_ERROR
);
699 texJobName
= *( argv
+ 1 );
700 if( texJobName
.find( '/' ) != std::string::npos
)
702 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
;
703 exit( Interaction::EXIT_INVOCATION_ERROR
);
708 else if( strcmp( *argv
, "--which-texjob" ) == 0 )
710 filenameRequestList
.push_back( FILENAME_TEXJOB
);
714 else if( strcmp( *argv
, "--labeldb" ) == 0 )
716 argcAssertion( *argv
, argc
, 2 );
717 if( labelDBName
!= "" )
719 std::cerr
<< "The label database file is multiply specified." << std::endl
;
720 exit( Interaction::EXIT_INVOCATION_ERROR
);
722 labelDBName
= absoluteFilename( *( argv
+ 1 ) );
726 else if( strcmp( *argv
, "--which-labeldb" ) == 0 )
728 filenameRequestList
.push_back( FILENAME_LABELDB
);
732 else if( strcmp( *argv
, "--afmout" ) == 0 )
734 argcAssertion( *argv
, argc
, 2 );
735 if( fontmetricsOutputName
!= "" )
737 std::cerr
<< "The font metrics output name is multiply specified." << std::endl
;
738 exit( Interaction::EXIT_INVOCATION_ERROR
);
740 fontmetricsOutputName
= absoluteFilename( *( argv
+ 1 ) );
744 else if( strcmp( *argv
, "--which-afmout" ) == 0 )
746 filenameRequestList
.push_back( FILENAME_AFM
);
750 else if( strcmp( *argv
, "--which-TEXINPUTS" ) == 0 )
752 filenameRequestList
.push_back( FILENAME_TEXINPUTS
);
756 else if( strcmp( *argv
, "--which-doc" ) == 0 )
758 filenameRequestList
.push_back( FILENAME_HTMLDOC
);
762 else if( strcmp( *argv
, "--which-share" ) == 0 )
764 filenameRequestList
.push_back( FILENAME_SHARE
);
768 else if( strcmp( *argv
, "--outdir" ) == 0 )
770 argcAssertion( *argv
, argc
, 2 );
773 std::cerr
<< "The output directory is multiply specified." << std::endl
;
774 exit( Interaction::EXIT_INVOCATION_ERROR
);
776 outDir
= absoluteDirectory( *( argv
+ 1 ) );
780 else if( strprefixcmp( *argv
, "--tmp*=", & optionPrefix
, & optionSuffix
) )
782 allowCreateTmpDir
= strtobool( optionSuffix
, *argv
);
786 else if( strcmp( *argv
, "--tmpdir" ) == 0 )
788 argcAssertion( *argv
, argc
, 2 );
791 std::cerr
<< "The temporaries directory is multiply specified." << std::endl
;
792 exit( Interaction::EXIT_INVOCATION_ERROR
);
794 tmpDir
= absoluteDirectory( *( argv
+ 1 ) );
798 else if( strcmp( *argv
, "--which-tmp" ) == 0 )
800 filenameRequestList
.push_back( FILENAME_TMP
);
804 else if( strprefixcmp( *argv
, "--split=", & optionPrefix
, & optionSuffix
) )
806 if( strcmp( optionSuffix
, "no" ) == 0 )
808 splitMode
= SPLIT_NO
;
810 else if( strcmp( optionSuffix
, "flat" ) == 0 )
812 splitMode
= SPLIT_FLAT
;
814 else if( strcmp( optionSuffix
, "dir" ) == 0 )
816 splitMode
= SPLIT_DIR
;
820 std::cerr
<< "The string \"" << optionSuffix
<< "\" in the command line argument \"" << *argv
<< "\" was not any of { 'no', 'flat', 'dir' }." << std::endl
;
825 else if( strcmp( *argv
, "--xpdf" ) == 0 )
827 previewOptions
.launch_xpdf
= true;
831 else if( strcmp( *argv
, "--xpdf-remote" ) == 0 )
833 argcAssertion( *argv
, argc
, 2 );
834 if( previewOptions
.xpdfServer
!= "" )
836 std::cerr
<< "The xpdf server is multiply specified." << std::endl
;
837 exit( Interaction::EXIT_INVOCATION_ERROR
);
839 previewOptions
.xpdfServer
= *( argv
+ 1 );
843 else if( strcmp( *argv
, "--xpdf-no-server" ) == 0 )
845 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
847 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
848 exit( Interaction::EXIT_INVOCATION_ERROR
);
850 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_NOSERVER
;
854 else if( strcmp( *argv
, "--xpdf-reload" ) == 0 )
856 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
858 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
859 exit( Interaction::EXIT_INVOCATION_ERROR
);
861 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
865 else if( strcmp( *argv
, "--xpdf-quit" ) == 0 )
867 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
869 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
870 exit( Interaction::EXIT_INVOCATION_ERROR
);
872 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_QUIT
;
876 else if( strcmp( *argv
, "--open" ) == 0 )
878 previewOptions
.do_open
= true;
882 else if( strcmp( *argv
, "--open-a" ) == 0 )
884 argcAssertion( *argv
, argc
, 2 );
885 previewOptions
.do_open
= true;
886 previewOptions
.do_open_application
= *( argv
+ 1 );
890 else if( strcmp( *argv
, "--version" ) == 0 )
893 exit( Interaction::EXIT_OK
);
899 std::cerr
<< "The name base is multiply specified." << std::endl
;
900 exit( Interaction::EXIT_INVOCATION_ERROR
);
902 typedef std::list
< const char * > SuffixesType
;
903 SuffixesType suffixes
;
904 if( ! forceBlankMode
){
905 suffixes
.push_back( "shape" );
907 if( ! forceShapeMode
){
908 suffixes
.push_back( "blank" );
911 if( stat( *argv
, & theStat
) == 0 &&
912 ( theStat
.st_mode
& S_IFDIR
) == 0 ) /* We are not interested in directories here. */
915 char * ext
= *argv
+ strlen( *argv
) - 6;
918 std::cerr
<< "The file name \"" << *argv
<< "\" is unexpectedly short (it should include the" ;
919 for( SuffixesType::const_iterator i
= suffixes
.begin( ); i
!= suffixes
.end( ); ++i
){
920 if( i
!= suffixes
.begin( ) )
922 std::cerr
<< " \"." << *i
<< "\"" ;
924 std::cerr
<< " suffix)." << std::endl
;
925 exit( Interaction::EXIT_INVOCATION_ERROR
);
927 SuffixesType::const_iterator i
= suffixes
.begin( );
928 for( ; i
!= suffixes
.end( ); ++i
){
929 if( ext
[0] == '.' && strcmp( ext
+ 1, *i
) == 0 )
930 break; /* Found, leave iterator before end. */
932 if( i
== suffixes
.end( ) ){
933 std::cerr
<< "Expected" ;
934 for( SuffixesType::const_iterator i
= suffixes
.begin( ); i
!= suffixes
.end( ); ++i
){
935 if( i
!= suffixes
.begin( ) )
937 std::cerr
<< " \"." << *i
<< "\"" ;
939 std::cerr
<< " suffix in the file name \"" << *argv
<< "\"." << std::endl
;
940 exit( Interaction::EXIT_INVOCATION_ERROR
);
945 SuffixesType::const_iterator i
= suffixes
.begin( );
946 for( ; i
!= suffixes
.end( ); ++i
){
947 if( (*argv
)[ strlen( *argv
) - 1 ] == '.' ){
948 inputName
= std::string( *argv
) + *i
;
950 inputName
= std::string( *argv
) + "." + *i
;
953 if( stat( inputName
.c_str( ), & theStat
) == 0 )
954 break; /* Found, leave iterator before end. */
956 if( i
== suffixes
.end( ) ){
957 /* No matching suffix was found.
958 * It is not entirely clear what is the best error message here,
959 * as the source file may be specified in several different ways.
960 * This should cause the least confusion.
962 std::cerr
<< "Failed to locate input file: " << *argv
<< std::endl
;
963 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
967 const char * slash
= strrchr( inputName
.c_str( ), '/' );
970 slash
= inputName
.c_str( );
976 size_t skipCount
= slash
- inputName
.c_str( );
977 baseName
= inputName
.substr( skipCount
, inputName
.length( ) - skipCount
- 6 );
984 std::cerr
<< "Illegal command line option: " << *argv
<< std::endl
;
985 exit( Interaction::EXIT_INVOCATION_ERROR
);
991 char * start
= getenv( "SHAPESTMPDIR" );
994 tmpDir
= absoluteDirectory( start
);
998 tmpDir
= absoluteDirectory( "" );
1003 if( interactiveMode
)
1009 outDir
= absoluteDirectory( "" );
1012 ensureTmpDirectoryExists( tmpDir
, allowCreateTmpDir
);
1014 if( baseName
== "" )
1016 if( interactiveMode
)
1018 if( outputName
== "" )
1020 if( splitMode
== SPLIT_NO
)
1022 outputName
= outDir
+ "#shapes" + ".pdf";
1026 outputName
= outDir
+ "#shapes" ;
1030 if( texJobName
== "" )
1032 texJobName
= "#shapes.labels";
1037 if( inputName
== "" )
1039 typedef std::list
< const char * > SuffixesType
;
1040 SuffixesType suffixes
;
1041 if( ! forceBlankMode
){
1042 suffixes
.push_back( "shape" );
1044 if( ! forceShapeMode
){
1045 suffixes
.push_back( "blank" );
1047 SuffixesType::const_iterator i
= suffixes
.begin( );
1048 for( ; i
!= suffixes
.end( ); ++i
){
1049 struct stat theStat
;
1050 inputName
= absoluteFilename( ( baseName
+ "." + *i
).c_str( ) );
1051 if( stat( inputName
.c_str( ), & theStat
) == 0 )
1052 break; /* Found, leave iterator before end. */
1054 if( i
== suffixes
.end( ) ){
1055 inputName
= absoluteFilename( ( baseName
+ "." + suffixes
.front( ) ).c_str( ) );
1058 if( outputName
== "" )
1060 if( splitMode
== SPLIT_NO
)
1062 outputName
= outDir
+ baseName
+ ".pdf";
1066 outputName
= outDir
+ baseName
;
1069 if( texJobName
== "" )
1071 texJobName
= baseName
+ ".labels";
1073 if( labelDBName
== "" )
1075 labelDBName
= outDir
+ baseName
+ ".labels.pdf";
1077 if( fontmetricsOutputName
== "" )
1079 fontmetricsOutputName
= outDir
+ baseName
+ ".afm";
1083 if( forceBlankMode
) {
1084 Interaction::blankMode
= true;
1085 } else if( forceShapeMode
){
1086 Interaction::blankMode
= false;
1088 Interaction::blankMode
= ( inputName
.size() >= 6 && inputName
.compare(inputName
.size() - 6, std::string::npos
, ".blank") == 0 );
1091 if( outputName
== "" )
1093 if( ! filenameRequestList
.empty( ) || Interaction::blankMode
)
1095 /* The output name will never really be used, so it's rather harmless to assign a dummy value.
1097 outputName
= "?.pdf" ;
1101 std::cerr
<< "The output file is undetermined. Consider specifying it using \"--out <filename>\"." << std::endl
;
1102 exit( Interaction::EXIT_INVOCATION_ERROR
);
1106 if( labelDBName
== "" )
1108 iterativeMode
= false;
1110 if( iterativeMode
== false )
1112 /* If the iterative mode has explicitly been turned off, we prevent any old labels from being reused. */
1116 if( ! Kernel::theDebugLog
.initialized( ) )
1118 std::string::size_type suffixSep
= outputName
.rfind( '.' );
1119 if( suffixSep
!= std::string::npos
&& outputName
.find( '/', suffixSep
) == std::string::npos
)
1121 /* If there would have been a slash after the '.', the dot would have been part of a directory name.
1122 * Otherwise, we conclude that we have found the extension of a filename, and replace that extension
1125 Kernel::theDebugLog
.setFilename( outputName
.substr( 0, suffixSep
) + ".log" );
1127 else if( baseName
!= "" )
1129 Kernel::theDebugLog
.setFilename( outDir
+ baseName
+ ".log" );
1133 Kernel::theDebugLog
.setFilename( outDir
+ "#shapes.log" );
1139 std::string inPath
= inputName
;
1140 std::string::size_type slash
= inPath
.rfind( '/' );
1141 if( slash
== std::string::npos
)
1143 inDir
= absoluteDirectory( "" );
1147 inDir
= absoluteDirectory( inPath
.substr( 0, slash
).c_str( ) );
1149 Ast::theShapesScanner
.setSourceDir( inDir
);
1150 Kernel::theTeXLabelManager
.setup( inDir
, tmpDir
, texJobName
);
1153 if( Computation::theTrixelizeSplicingTol
>= Computation::theTrixelizeOverlapTol
)
1155 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
;
1156 exit( Interaction::EXIT_INVOCATION_ERROR
);
1159 if( previewOptions
.xpdfServer
== "" )
1161 previewOptions
.xpdfServer
= outputName
;
1164 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_DEFAULT
)
1166 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RAISE
;
1169 addDefaultNeedPath( );
1170 addDefaultFontMetricsPath( );
1174 Ast::theShapesScanner
.push_backNeedPath( std::string( Kernel::RESOURCES_DIR
) + "/extensions/" );
1175 Lang::Font::push_backFontMetricsPath( std::string( Kernel::RESOURCES_DIR
) + "/fontmetrics/" );
1178 if( ! filenameRequestList
.empty( ) )
1180 std::list
< const char * >::const_iterator resource
= resourceRequestList
.begin( );
1181 for( std::list
< int >::const_iterator i
= filenameRequestList
.begin( );
1182 i
!= filenameRequestList
.end( );
1188 if( inputName
== "" )
1190 std::cout
<< "<stdin>" ;
1194 std::cout
<< inputName
;
1198 std::cout
<< outputName
;
1201 std::cout
<< tmpDir
;
1203 case FILENAME_TEXJOB
:
1204 std::cout
<< tmpDir
<< texJobName
;
1206 case FILENAME_LABELDB
:
1207 std::cout
<< labelDBName
;
1210 std::cout
<< fontmetricsOutputName
;
1212 case FILENAME_TEXINPUTS
:
1214 std::cout
<< getenv( "TEXINPUTS" ) ;
1217 case FILENAME_HTMLDOC
:
1219 std::cout
<< Kernel::HTML_DIR
<< "/index.html" ;
1222 case FILENAME_SHARE
:
1224 std::cout
<< Kernel::RESOURCES_DIR
;
1227 case FILENAME_RESOURCE
:
1231 std::cout
<< Ast::theShapesScanner
.searchFile( *resource
) ;
1233 catch( const Exceptions::Exception
& ball
)
1236 ball
.display( std::cerr
);
1237 exit( Interaction::EXIT_INVOCATION_ERROR
);
1243 std::cerr
<< "Internal error: filename request switch in main out of range." << std::endl
;
1244 exit( Interaction::EXIT_INTERNAL_ERROR
);
1246 std::cout
<< std::endl
;
1248 exit( Interaction::EXIT_OK
);
1251 if( pdfVersion
== SimplePDF::PDF_Version::VERSION_UNDEFINED
)
1253 pdfVersion
= SimplePDF::PDF_Version::PDF_1_4
;
1256 Kernel::the_PDF_version
.setVersion( pdfVersion
);
1257 Kernel::the_PDF_version
.setAction( pdfVersionAction
);
1260 std::ostringstream oss
;
1263 struct tm
* now( gmtime( &tmp
) );
1265 << std::setfill( '0' )
1266 << std::setw(4) << 1900 + now
->tm_year
1267 << std::setw(2) << 1 + now
->tm_mon
1268 << std::setw(2) << now
->tm_mday
1269 << std::setw(2) << now
->tm_hour
1270 << std::setw(2) << now
->tm_min
1271 << std::setw(2) << now
->tm_sec
1273 Kernel::theDocInfo
.addInfo( "CreationDate", SimplePDF::newString( oss
.str( ).c_str( ) ) );
1276 std::istringstream prependStreamIn
;
1277 if( ! prependStreamOut
.str( ).empty( ) )
1279 prependStreamIn
.str( prependStreamOut
.str( ) );
1280 Ast::theShapesScanner
.queueStream( & prependStreamIn
, Ast::FileID::build_special( "<--prepend>" ) );
1283 std::ifstream iFile
;
1284 std::istream
* iFilePtr
= 0;
1285 if( inputName
== "" )
1287 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( "<stdin>" ) );
1288 iFilePtr
= & std::cin
;
1289 if( interactiveMode
)
1291 /* On some platforms, the lexer crashes if it is not given a new file at EOF,
1292 * so we need to put an empty file after the prelude to avoid that.
1294 * Note that we use the iFile object here, although this will not be pointed to
1295 * by iFilePtr, which points to std::cin instead.
1297 const char * nullName
= "/dev/null";
1298 iFile
.open( nullName
);
1299 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1301 std::cerr
<< "Failed to open " << nullName
<< " to create empty input file." << std::endl
;
1302 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1304 Ast::theShapesScanner
.queueStream( & iFile
, Ast::FileID::build_special( nullName
) );
1308 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_special( "<stdin>" ) );
1309 // Ast::theShapesScanner.setNameOf_yyin( "<stdin>" );
1314 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( inputName
.c_str( ) ) );
1315 iFile
.open( inputName
.c_str( ) );
1316 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1318 std::cerr
<< "Failed to open " << inputName
<< " for input." << std::endl
;
1319 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1322 if( ! interactiveMode
)
1324 struct stat theStat
;
1325 if( stat( inputName
.c_str( ), & theStat
) != 0 )
1327 std::cerr
<< "Failed to stat " << inputName
<< " (but it could be opened for input...)." << std::endl
;
1328 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1330 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_stat( theStat
, inputName
) );
1336 /* This will initiate the reading of preludes, and when there are no more preludes, we turn to the queue set up by calling queueStream. */
1337 Ast::theShapesScanner
.start( );
1339 catch( const Exceptions::StaticInconsistency
& ball
)
1342 std::cerr
<< ball
.loc( ) << ": " ;
1343 ball
.display( std::cerr
);
1344 std::cerr
<< "There were errors in the namespace directory hierarchy." << std::endl
;
1345 abortProcedure( ball
.exitCode( ) );
1347 catch( const Exceptions::Exception
& ball
)
1350 ball
.display( std::cerr
);
1351 std::cerr
<< "There were errors in the namespace directory hierarchy." << std::endl
;
1352 abortProcedure( ball
.exitCode( ) );
1355 RefCountPtr
< std::ifstream
> labelDBFile
= RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1356 Kernel::WarmCatalog::ShipoutList documents
;
1358 /* This is where all the evaluation takes place. It is written as a separate functions to keep the function main short.
1362 if( interactiveMode
)
1364 interactiveEvaluation( *iFilePtr
, std::cout
, outputName
, splitMode
,
1365 evalTrace
, evalBackTrace
, cleanupMemory
,
1366 labelDBFile
, labelDBName
);
1370 nonInteractiveEvaluation( documents
, splitMode
,
1371 evalTrace
, evalBackTrace
, cleanupMemory
,
1372 labelDBFile
, labelDBName
);
1375 catch( const NonLocalExit::DynamicBindingNotFound
& ball
)
1377 std::cerr
<< "Caught DynamicBindingNotFound at top level." << std::endl
1378 << "This should really not be possible; it is an internal error." << std::endl
;
1379 exit( Interaction::EXIT_INTERNAL_ERROR
);
1381 catch( const NonLocalExit::NotThisType
& ball
)
1383 std::cerr
<< "Caught NotThisType at top level." << std::endl
1384 << "This should really not be possible; it is an internal error." << std::endl
;
1385 exit( Interaction::EXIT_INTERNAL_ERROR
);
1387 catch( const NonLocalExit::NonLocalExitBase
& ball
)
1389 std::cerr
<< "Caught an unknown descendant to NonLocalExitBase at top level." << std::endl
1390 << "This should really not be possible; it is an internal error." << std::endl
;
1391 exit( Interaction::EXIT_INTERNAL_ERROR
);
1393 catch( const char * ball
)
1395 std::cerr
<< "Caught (char*) ball at top level:" << std::endl
1396 << " " << ball
<< std::endl
;
1397 exit( Interaction::EXIT_GENERIC_ERROR
);
1399 catch( const std::string
& ball
)
1401 std::cerr
<< "Caught (string) ball at top level:" << std::endl
1402 << " " << ball
<< std::endl
;
1403 exit( Interaction::EXIT_GENERIC_ERROR
);
1405 catch( const std::exception
& ball
)
1407 std::cerr
<< "Caught std::exception at top level:" << std::endl
1408 << " " << ball
.what( ) << std::endl
;
1409 exit( Interaction::EXIT_GENERIC_ERROR
);
1413 std::cerr
<< "Caught (...) ball at top level." << std::endl
;
1414 exit( Interaction::EXIT_GENERIC_ERROR
);
1417 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1419 abortProcedure( Interaction::EXIT_USER_ERROR
);
1424 std::cerr
<< "Summary:" << std::endl
;
1425 std::cerr
<< "Environments: alive: " << Kernel::Environment::liveCount
<< " of total: " << Kernel::Environment::createdCount
1426 << " (" << 100 * static_cast< double >( Kernel::Environment::liveCount
) / static_cast< double >( Kernel::Environment::createdCount
) << "%)" << std::endl
;
1429 if( ! Interaction::blankMode
)
1430 writeOutput( outputName
, documents
, splitMode
);
1432 /* This must be done after the output has been written, and before iterativeFinish writes to the labels database file.
1434 Kernel::thePDFImporter
.free( );
1436 if( labelDBFile
!= NullPtr
< std::ifstream
>( ) )
1438 if( labelDBFile
->is_open( ) )
1440 labelDBFile
->close( );
1442 labelDBFile
= NullPtr
< std::ifstream
>( ); // Free the reference.
1447 Kernel::theTeXLabelManager
.iterativeFinish( labelDBName
);
1450 if( ! Interaction::blankMode
)
1451 previewOptions
.preview( outputName
, splitMode
!= SPLIT_NO
);
1460 argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
)
1462 if( argc
< argcMin
)
1464 std::cerr
<< "The command line option " << optionSpecifier
<< " requires " << argcMin
- 1 << " parameters." << std::endl
;
1465 exit( Interaction::EXIT_INVOCATION_ERROR
);
1470 strprefixcmp( char * str
, const char * prefix
, const char ** prefixDst
, char ** endp
)
1472 *prefixDst
= prefix
;
1473 int len
= strlen( prefix
);
1474 bool res
= ( strncmp( str
, prefix
, len
) == 0 );
1480 strtobool( const char * str
, const char * containingString
, const char * trueLabel
, const char * falseLabel
)
1482 if( trueLabel
!= 0 &&
1483 strcmp( str
, trueLabel
) == 0 )
1487 if( falseLabel
!= 0 &&
1488 strcmp( str
, falseLabel
) == 0 )
1492 if( strcmp( str
, "yes" ) == 0 ||
1493 strcmp( str
, "true" ) == 0 ||
1494 strcmp( str
, "on" ) == 0 )
1498 if( strcmp( str
, "no" ) == 0 ||
1499 strcmp( str
, "false" ) == 0 ||
1500 strcmp( str
, "off" ) == 0)
1504 std::cerr
<< "The string \"" << str
<< "\" in the command line argument \"" << containingString
<< "\" was not recognized as a boolean value." << std::endl
;
1505 exit( Interaction::EXIT_INVOCATION_ERROR
);
1509 RefCountPtr
< std::ifstream
>
1510 performIterativeStartup( const std::string
& labelDBName
)
1513 struct stat theStat
;
1514 if( stat( labelDBName
.c_str( ), & theStat
) != 0 )
1516 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1520 // ostringstream mvCommand;
1521 // mvCommand << "cp '" << oldFilename.str( ) << "' '" << labelDBName.str( ) << "'" ;
1522 // Interaction::systemDebugMessage( mvCommand.str( ) );
1523 // if( system( mvCommand.str( ).c_str( ) ) != 0 )
1525 // return RefCountPtr< std::ifstream >( NullPtr< std::ifstream >( ) );
1528 RefCountPtr
< std::ifstream
> labelsFile( new std::ifstream( labelDBName
.c_str( ) ) );
1529 if( ! labelsFile
->good( ) )
1531 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1535 Kernel::theTeXLabelManager
.iterativeStartup( labelsFile
);
1538 catch( const char * ball
)
1540 std::cerr
<< "Caught (char*) ball from iterative startup:" << std::endl
1541 << " " << ball
<< std::endl
;
1542 exit( Interaction::EXIT_GENERIC_ERROR
);
1544 catch( const std::string
& ball
)
1546 std::cerr
<< "Caught (string) ball from iterative startup:" << std::endl
1547 << " " << ball
<< std::endl
;
1548 exit( Interaction::EXIT_GENERIC_ERROR
);
1550 catch( const Exceptions::Exception
& ball
)
1552 ball
.display( std::cerr
);
1553 exit( ball
.exitCode( ) );
1557 std::cerr
<< "Caught (...) ball from iterative startup." << std::endl
;
1558 exit( Interaction::EXIT_GENERIC_ERROR
);
1564 abortProcedure( int exitCode
)
1566 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1569 while( ! Kernel::thePostCheckErrorsList
.empty( ) )
1571 Exceptions::Exception
* e
= Kernel::thePostCheckErrorsList
.front( );
1572 Kernel::thePostCheckErrorsList
.pop_front( );
1574 typedef const Exceptions::PostCondition ErrorType
;
1575 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1578 std::cerr
<< err
->loc( ) << ": " ;
1579 err
->display( std::cerr
);
1584 typedef const Exceptions::RuntimeError ErrorType
;
1585 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1588 std::cerr
<< err
->getLoc( ) << " (runtime): " ;
1589 err
->display( std::cerr
);
1593 std::cerr
<< "(Bad post-exception type)" << ": " ;
1594 e
->display( std::cerr
);
1597 std::cerr
<< "Aborting job. Output files are left unchanged." << std::endl
;
1605 void setSelfRef( RefCountPtr
< const Lang::Class
> cls
)
1607 cls
->setSelfRef( cls
);
1609 void initClass( RefCountPtr
< const Lang::Class
> cls
)
1611 Lang::SystemFinalClass
* typedPtr
= dynamic_cast< Lang::SystemFinalClass
* >( const_cast< Lang::Class
* >( cls
.getPtr( ) ) );
1618 std::cerr
<< "Helpers::initMutators was called with object of bad type." << std::endl
;
1619 exit( Interaction::EXIT_INTERNAL_ERROR
);
1626 writeOutput( std::string
& outputName
, const Kernel::WarmCatalog::ShipoutList
& documents
, SplitMode splitMode
)
1634 if( documents
.size( ) != 1 )
1636 std::cerr
<< "Internal error: Failed to produce exactly one document of output although --split=no." << std::endl
;
1638 std::ofstream oFile
;
1639 noSplitOpen( & oFile
, outputName
);
1640 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
1645 rmSplitFiles( outputName
, "-" );
1646 size_t physicalPageNo
= 1;
1647 for( Kernel::WarmCatalog::ShipoutList::const_iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1649 std::ofstream oFile
;
1650 splitOpen( & oFile
, outputName
, "-", physicalPageNo
);
1651 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1657 mkSplitDir( outputName
);
1658 rmSplitFiles( outputName
, "/" );
1659 size_t physicalPageNo
= 1;
1660 for( Kernel::WarmCatalog::ShipoutList::const_iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1662 std::ofstream oFile
;
1663 splitOpen( & oFile
, outputName
, "/", physicalPageNo
);
1664 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1670 catch( const char * ball
)
1672 std::cerr
<< "Writing output file failed:" << std::endl
1673 << " " << ball
<< std::endl
;
1674 exit( Interaction::EXIT_GENERIC_ERROR
);
1676 catch( const std::string
& ball
)
1678 std::cerr
<< "Writing output file failed:" << std::endl
1679 << " " << ball
<< std::endl
;
1680 exit( Interaction::EXIT_GENERIC_ERROR
);
1687 Lang::ElementaryPath2D
* bbox
= new Lang::ElementaryPath2D
;
1688 bbox
->push_back( new Concrete::PathPoint2D( 0, 0 ) );
1690 Lang::THE_POINTPICTURE
= RefCountPtr
< Lang::Drawable2D
>( new Lang::BBoxed2D( Lang::THE_NULL2D
,
1691 RefCountPtr
< Lang::ElementaryPath2D
>( bbox
) ) );
1692 Helpers::setSelfRef( Lang::THE_OBJECT
);
1694 Helpers::setSelfRef( Lang::Void::TypeID
);
1695 Helpers::setSelfRef( Lang::Symbol::TypeID
);
1696 Helpers::setSelfRef( Lang::Float::TypeID
);
1697 Helpers::setSelfRef( Lang::Length::TypeID
);
1698 Helpers::setSelfRef( Lang::Integer::TypeID
);
1699 Helpers::setSelfRef( Lang::Boolean::TypeID
);
1700 Helpers::setSelfRef( Lang::String::TypeID
);
1701 Helpers::setSelfRef( Lang::FloatPair::TypeID
);
1702 Helpers::setSelfRef( Lang::FloatTriple::TypeID
);
1703 Helpers::setSelfRef( Lang::Coords2D::TypeID
);
1704 Helpers::setSelfRef( Lang::CornerCoords2D::TypeID
);
1705 Helpers::setSelfRef( Lang::Coords3D::TypeID
);
1707 Helpers::setSelfRef( Lang::Function::TypeID
);
1708 Helpers::setSelfRef( Lang::Transform2D::TypeID
);
1709 Helpers::setSelfRef( Lang::Transform3D::TypeID
);
1711 Helpers::setSelfRef( Lang::Class::TypeID
);
1713 Helpers::setSelfRef( Lang::TransformedInstance::TypeID
);
1715 Helpers::initClass( Lang::String::TypeID
);
1716 Helpers::initClass( Kernel::WarmGroup2D::TypeID
);
1717 Helpers::initClass( Kernel::WarmGroup3D::TypeID
);
1718 Helpers::initClass( Kernel::WarmCatalog::TypeID
);
1719 Helpers::initClass( Kernel::WarmDebugger::TypeID
);
1720 Helpers::initClass( Kernel::Warm_vector::TypeID
);
1721 Helpers::initClass( Kernel::WarmGraph::TypeID
);
1722 Helpers::initClass( Lang::Font::TypeID
);
1723 Helpers::initClass( Lang::SingleList::TypeID
);
1724 Helpers::initClass( Lang::SingleListNull::TypeID
);
1725 Helpers::initClass( Lang::ConsPair::TypeID
);
1726 Helpers::initClass( Lang::VectorFunction::TypeID
);
1727 Helpers::initClass( Lang::Transform2D::TypeID
);
1728 Helpers::initClass( Lang::Transform3D::TypeID
);
1729 Helpers::initClass( Lang::Graph::TypeID
);
1730 Helpers::initClass( Lang::Node::TypeID
);
1731 Helpers::initClass( Lang::Edge::TypeID
);
1734 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric2D" ) );
1735 Lang::Geometric2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1736 Helpers::setSelfRef( Lang::Geometric2D::TypeID
);
1737 /* Note that addVirtual must not be called before the selfRef is set!
1741 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric3D" ) );
1742 Lang::Geometric3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1743 Helpers::setSelfRef( Lang::Geometric3D::TypeID
);
1744 /* Note that addVirtual must not be called before the selfRef is set!
1748 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable2D" ) );
1749 Lang::Drawable2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1750 Helpers::setSelfRef( Lang::Drawable2D::TypeID
);
1751 /* Note that addVirtual must not be called before the selfRef is set!
1753 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1756 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable3D" ) );
1757 Lang::Drawable3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1758 Helpers::setSelfRef( Lang::Drawable3D::TypeID
);
1759 /* Note that addVirtual must not be called before the selfRef is set!
1761 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1764 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Color" ) );
1765 Lang::Color::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1766 Helpers::setSelfRef( Lang::Color::TypeID
);
1767 /* Note that addVirtual must not be called before the selfRef is set!
1769 tmp
->addVirtual( "stroking" );
1770 tmp
->addVirtual( "nonstroking" );
1775 FT_Error error
= FT_Init_FreeType( & Kernel::theFreeType
);
1778 std::cerr
<< "Failed to initialize FreeType library object: " << Kernel::FreeTypeErrorMessage( error
) << std::endl
;
1779 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1783 #ifdef HAVE_FONTCONFIG
1784 if( FcInit( ) != FcTrue
)
1786 std::cerr
<< "Failed to initialize FontConfig library." << std::endl
;
1787 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1793 Interaction::PreviewOptions::preview( const std::string
& filename
, bool splitNoLaunch
) const
1799 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1803 xpdfHelper( filename
);
1811 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1815 openHelper( filename
);
1821 Interaction::PreviewOptions::xpdfHelper( const std::string
& filename
) const
1823 pid_t xpdfProcess
= fork( );
1824 if( xpdfProcess
== -1 )
1826 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running xpdf." ) );
1829 if( xpdfProcess
== 0 ) /* This is the child */
1831 /* The exec call below never returns, so the child process never leaves this if clause.
1832 * Hence, there is no need to create a special else clasuse below.
1834 switch( xpdfAction
)
1837 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-raise", filename
.c_str( ), static_cast< const char * >( 0 ) );
1840 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-reload", static_cast< const char * >( 0 ) );
1843 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-quit", static_cast< const char * >( 0 ) );
1846 execlp( "xpdf", "xpdf", filename
.c_str( ), static_cast< const char * >( 0 ) );
1849 std::cerr
<< "Internal error: XpdfAction switch out of range." << std::endl
;
1850 exit( Interaction::EXIT_INTERNAL_ERROR
);
1854 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to xpdf." << std::endl
;
1855 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1857 std::cerr
<< "execlp call to xpdf returned with errno == 0." << std::endl
;
1858 exit( Interaction::EXIT_INTERNAL_ERROR
);
1864 Interaction::PreviewOptions::openHelper( const std::string
& filename
) const
1866 pid_t openProcess
= fork( );
1867 if( openProcess
== -1 )
1869 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running open." ) );
1872 if( openProcess
== 0 ) /* This is the child */
1874 /* The exec call below never returns, so the child process never leaves this if clause.
1875 * Hence, there is no need to create a special else clasuse below.
1877 if( do_open_application
!= 0 )
1879 execlp( "open", "open", "-a", do_open_application
, filename
.c_str( ), static_cast< const char * >( 0 ) );
1883 execlp( "open", "open", filename
.c_str( ), static_cast< const char * >( 0 ) );
1887 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to open." << std::endl
;
1888 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1890 std::cerr
<< "execlp call to open returned with errno == 0." << std::endl
;
1891 exit( Interaction::EXIT_INTERNAL_ERROR
);
1897 Interaction::systemDebugMessage( const std::string
& msg
)
1899 if( Interaction::debugSystem
)
1901 std::cerr
<< "System command: " << msg
<< std::endl
;
1906 Interaction::warn_or_push( Exceptions::Exception
* message
, PtrOwner_back_Access
< std::list
< Exceptions::Exception
* > > * errorsList
)
1908 switch( Interaction::warningAction
)
1910 case Interaction::WARNING_DISPLAY
:
1911 Interaction::displayWarning( *message
);
1914 case Interaction::WARNING_ERROR
:
1915 errorsList
->push_back( message
);
1917 case Interaction::WARNING_IGNORE
:
1924 Interaction::displayWarning( const Exceptions::Exception
& ball
)
1926 std::cerr
<< "***Warning*** " ;
1927 ball
.display( std::cerr
);
1931 addDefaultNeedPath( )
1933 char * start
= getenv( "SHAPESINPUTS" );
1936 Ast::theShapesScanner
.push_backNeedPath( "./" );
1939 char * tok
= strsep( & start
, ":" );
1942 Ast::theShapesScanner
.push_backNeedPath( tok
);
1943 tok
= strsep( & start
, ":" );
1948 addDefaultFontMetricsPath( )
1950 char * start
= getenv( "SHAPESFONTMETRICS" );
1955 char * tok
= strsep( & start
, ":" );
1958 Lang::Font::push_backFontMetricsPath( tok
);
1959 tok
= strsep( & start
, ":" );
1966 Helpers::requireUTF8ToMacRomanConverter( true ); // true means "cleanup"
1967 Helpers::requireMacRomanToUTF8Converter( true ); // true means "cleanup"
1968 Helpers::requireUTF8ToWinANSIConverter( true ); // true means "cleanup"
1969 Helpers::requireUTF8ToUTF16BEConverter( true ); // true means "cleanup"
1970 Helpers::requireUTF8ToASCIIConverter( true ); // true means "cleanup"
1971 Helpers::requireUTF8ToUCS4Converter( true ); // true means "cleanup"
1972 Helpers::requireUTF16BEToUCS4Converter( true ); // true means "cleanup"
1973 Helpers::requireGlyphList( true ); // true means "cleanup"
1974 Helpers::requireMacRomanEncoding( true ); // true means "cleanup"
1975 #ifdef HAVE_FONTCONFIG
1980 FT_Error error
= FT_Done_FreeType( Kernel::theFreeType
);
1983 std::cerr
<< "Failed to \"destroy\" FreeType library object: " << Kernel::FreeTypeErrorMessage( error
) << std::endl
;
1984 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1991 absoluteFilename( const char * filename
)
1993 if( *filename
== '/' )
1997 return callDir
+ filename
;
2001 absoluteDirectory( const char * filename
)
2003 if( *filename
== '\0' )
2007 if( filename
[ strlen( filename
) - 1 ] != '/' )
2009 if( *filename
== '/' )
2011 return filename
+ std::string( "/" );
2013 return callDir
+ filename
+ "/";
2015 if( *filename
== '/' )
2019 return callDir
+ filename
;
2025 ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
)
2027 struct stat theStat
;
2028 if( stat( dirname
.c_str( ), & theStat
) == 0 )
2030 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
2032 std::cerr
<< "The path " << dirname
<< " was expected to reference a directory." << std::endl
;
2033 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2035 // if( ( theStat.st_mode & S_IWOTH ) == 0 )
2037 // std::cerr << "The directory " << dirname << " was expected have write permission for others." << std::endl ;
2038 // exit( Interaction::EXIT_FILE_PERMISSION_ERROR );
2045 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
;
2046 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2049 size_t i2
= 0; /* We know there's a slash at the first position */
2050 i2
= dirname
.find( '/', i2
+ 1 );
2052 while( stat( dirname
.substr( 0, i2
).c_str( ), & theStat
) == 0 )
2055 i2
= dirname
.find( '/', i2
+ 1 );
2059 std::cerr
<< "Shapes will not create directories for temporary files at the root: " << dirname
<< std::endl
;
2060 exit( Interaction::EXIT_INVOCATION_ERROR
);
2063 mode_t oldUmask
= umask( 0 ); /* We want to be able to create directories with any permissions. */
2064 while( i2
!= std::string::npos
)
2066 if( mkdir( dirname
.substr( 0, i2
).c_str( ), theStat
.st_mode
& ( S_IRWXU
| S_IRWXG
| S_IRWXO
) ) != 0 )
2068 std::cerr
<< "Failed to create directory for temporary files (errno=" << errno
<< "): " << dirname
.substr( 0, i2
) << std::endl
;
2069 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2071 i2
= dirname
.find( '/', i2
+ 1 );
2077 escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
)
2079 const char * special
= "*?[+@!";
2080 for( std::string::const_iterator i
= str
.begin( ); i
!= str
.end( ); ++i
)
2082 if( strchr( special
, *i
) != 0 )
2091 rmSplitFiles( const std::string
& outputName
, const char * sep
)
2093 std::ostringstream rmCommand
;
2094 rmCommand
<< "sh -O extglob -c 'rm -f " ;
2095 escapeExtGlobChars( outputName
, rmCommand
);
2096 rmCommand
<< sep
<< "+([0-9]).pdf'" ;
2097 Interaction::systemDebugMessage( rmCommand
.str( ) );
2098 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
2100 /* Never mind; we made a try, and this probably means that there were no files to remove. */
2105 mkSplitDir( const std::string
& outputName
)
2107 struct stat theStat
;
2108 if( stat( outputName
.c_str( ), & theStat
) == 0 )
2110 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
2112 std::cerr
<< "The path " << outputName
<< " was expected to reference a directory." << std::endl
;
2113 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2118 if( mkdir( outputName
.c_str( ), S_IRWXU
| S_IRWXG
| S_IRWXO
) != 0 )
2120 std::cerr
<< "Failed to create directory for split document files (errno=" << errno
<< "): " << outputName
<< std::endl
;
2121 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2127 noSplitOpen( std::ofstream
* oFile
, const std::string
& outputName
)
2129 oFile
->open( outputName
.c_str( ) );
2130 if( ! oFile
->good( ) )
2132 /* If this is because the output directory does not exist, we shall inform the user about this. */
2133 std::string::size_type slash
= outputName
.rfind( '/' );
2134 if( slash
!= std::string::npos
)
2136 std::string outputDir
= outputName
.substr( 0, slash
);
2137 struct stat theStat
;
2138 if( stat( outputDir
.c_str( ), & theStat
) == 0 )
2140 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
2142 std::cerr
<< "The prefix " << outputDir
<< " of the output name must be a directory." << std::endl
;
2143 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2145 /* In case we reach here, the directory exists, so we fall back on the generic error message below. */
2149 std::cerr
<< "The file " << outputName
<< " cannot be opened for output since the directory " << outputDir
<< " does not exist." << std::endl
;
2150 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2153 std::cerr
<< "Failed to open " << outputName
<< " for output." << std::endl
;
2154 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2159 splitOpen( std::ofstream
* oFile
, const std::string outputName
, const char * sep
, size_t physicalPageNo
)
2161 std::ostringstream oss
;
2162 oss
<< outputName
<< sep
<< physicalPageNo
<< ".pdf" ;
2163 std::string
filename( oss
.str( ) );
2164 oFile
->open( filename
.c_str( ) );
2165 if( ! oFile
->good( ) )
2167 std::cerr
<< "Failed to open " << filename
<< " for output." << std::endl
;
2168 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2176 std::string
ind(" ");
2178 << "Usage:" << std::endl
2179 << ind
<< "shapes [OPTIONS] file[.[shape|blank]]" << std::endl
2180 << "A subset of options is listed below, by cathegory. This message is just" << std::endl
2181 << "a reminder; legal option values are only listed in rare cases." << std::endl
2182 << "Files: --in --out --outdir --texjob --tmpdir --tmp*= --labeldb" << std::endl
2183 << "Paths: --needpath -N --fontmetricspath --resources=" << std::endl
2184 << "Multipage: --split=('no'|'flat'|'dir')" << std::endl
2185 << "PDF: (--pdf-version=|-v)(e|w|s)1.N --tp= --spot-pair=" << std::endl
2186 << "Tolerances: --arcdelta= --dtmin= --dtminerror= --splicingtol= --overlaptol=" << std::endl
2187 << "Log file: --debuglog --debuglog-stderr --debuglog-stdout" << std::endl
2188 << "Help: --help --which-doc --showfiles= --which --version" << std::endl
2189 << "Viewing: --xpdf --open --open-a" << std::endl
2190 << "Interactive: --interactive -i" << std::endl
2191 << "See the man page for a complete listing and details." << std::endl