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 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;
55 char * cwd
= getcwd( 0, 0 );
56 callDir
= cwd
+ std::string( "/" );
62 bool allowCreateTmpDir
= false;
64 std::string inputName
;
65 std::string outputName
;
66 std::string texJobName
;
67 std::string labelDBName
;
68 std::string fontmetricsOutputName
;
70 enum FilenameRequests
{ FILENAME_RESOURCE
, FILENAME_IN
, FILENAME_OUT
, FILENAME_TMP
, FILENAME_TEXJOB
, FILENAME_LABELDB
, FILENAME_AFM
, FILENAME_TEXINPUTS
, FILENAME_HTMLDOC
, FILENAME_SHARE
};
72 std::list
< int > filenameRequestList
;
73 std::list
< const char * > resourceRequestList
;
75 bool evalTrace
= false;
76 bool evalBackTrace
= false;
77 bool cleanupMemory
= true;
78 bool memoryStats
= false;
79 SimplePDF::PDF_Version::Version pdfVersion
= SimplePDF::PDF_Version::VERSION_UNDEFINED
;
80 SimplePDF::PDF_Version::Action pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
81 std::ostringstream prependStreamOut
;
83 SplitMode splitMode
= SPLIT_NO
;
88 if( argc
> 0 && strcmp( *argv
, "--help" ) == 0 )
92 std::cerr
<< "The --help command line switch must appear alone." << std::endl
;
93 exit( Interaction::EXIT_INVOCATION_ERROR
);
101 const char * optionPrefix
;
103 if( strcmp( *argv
, "--yydebug" ) == 0 )
109 else if( strcmp( *argv
, "--shapes-debug" ) == 0 )
115 else if( strcmp( *argv
, "--system-debug" ) == 0 )
117 Interaction::debugSystem
= true;
121 else if( strcmp( *argv
, "--afm-debug" ) == 0 )
123 Interaction::fontMetricDebug
= true;
127 else if( strcmp( *argv
, "--afm-messages" ) == 0 )
129 Interaction::fontMetricMessages
= true;
133 else if( strcmp( *argv
, "--tex-debug" ) == 0 )
135 Interaction::pdfLaTeXInteractionTo_stderr
= true;
139 else if( strcmp( *argv
, "--log-globals" ) == 0 )
141 Interaction::logGlobals
= true;
145 else if( strprefixcmp( *argv
, "--bytecolumn=", & optionPrefix
, & optionSuffix
) )
147 Interaction::characterColumnInBytes
= strtobool( optionSuffix
, *argv
);
151 else if( strprefixcmp( *argv
, "--debugstep=", & optionPrefix
, & optionSuffix
) )
154 int tmp
= strtol( optionSuffix
, & endp
, 10 );
157 std::cerr
<< "The --debugstep value must be nonnegative: " << optionSuffix
<< std::endl
;
158 exit( Interaction::EXIT_INVOCATION_ERROR
);
160 Interaction::debugStep
= static_cast< size_t >( tmp
);
164 else if( strcmp( *argv
, "--debuglog" ) == 0 )
166 argcAssertion( *argv
, argc
, 2 );
169 Kernel::theDebugLog
.setFilename( *( argv
+ 1 ) );
171 catch( const char * ball
)
173 std::cerr
<< ball
<< std::endl
;
174 exit( Interaction::EXIT_INVOCATION_ERROR
);
179 else if( strcmp( *argv
, "--debuglog-stderr" ) == 0 )
183 Kernel::theDebugLog
.setStream( & std::cerr
);
185 catch( const char * ball
)
187 std::cerr
<< ball
<< std::endl
;
188 exit( Interaction::EXIT_INVOCATION_ERROR
);
193 else if( strcmp( *argv
, "--debuglog-stdout" ) == 0 )
197 Kernel::theDebugLog
.setStream( & std::cout
);
199 catch( const char * ball
)
201 std::cerr
<< ball
<< std::endl
;
202 exit( Interaction::EXIT_INVOCATION_ERROR
);
207 else if( strprefixcmp( *argv
, "--dtminerror=", & optionPrefix
, & optionSuffix
) )
209 Computation::dtMinIsError
= strtobool( optionSuffix
, *argv
);
213 else if( strprefixcmp( *argv
, "--fmguesserror=", & optionPrefix
, & optionSuffix
) )
215 Computation::fontMetricGuessIsError
= strtobool( optionSuffix
, *argv
);
219 else if( strcmp( *argv
, "--interactive") == 0 ||
220 strcmp( *argv
, "-i") == 0 )
222 interactiveMode
= true;
226 else if( strprefixcmp( *argv
, "--i-format-prompt=", & optionPrefix
, & optionSuffix
) ||
227 strprefixcmp( *argv
, "-?P", & optionPrefix
, & optionSuffix
) )
229 interactionFormats
.setPrompt( strdup( optionSuffix
) );
233 else if( strprefixcmp( *argv
, "--i-format-show=", & optionPrefix
, & optionSuffix
) ||
234 strprefixcmp( *argv
, "-?S", & optionPrefix
, & optionSuffix
) )
236 interactionFormats
.setShow( strdup( optionSuffix
) );
240 else if( strprefixcmp( *argv
, "--i-format-file=", & optionPrefix
, & optionSuffix
) ||
241 strprefixcmp( *argv
, "-?F", & optionPrefix
, & optionSuffix
) )
243 interactionFormats
.setFile( strdup( optionSuffix
) );
247 else if( strprefixcmp( *argv
, "--i-format-eof=", & optionPrefix
, & optionSuffix
) ||
248 strprefixcmp( *argv
, "-?E", & optionPrefix
, & optionSuffix
) )
250 interactionFormats
.setBye( strdup( optionSuffix
) );
254 else if( strcmp( *argv
, "--evaltrace" ) == 0 )
260 else if( strcmp( *argv
, "--evalbacktrace" ) == 0 )
263 evalBackTrace
= true;
267 else if( strprefixcmp( *argv
, "--backtrace=", & optionPrefix
, & optionSuffix
) )
269 Interaction::debugBacktrace
= strtobool( optionSuffix
, *argv
);
273 else if( strprefixcmp( *argv
, "--iteration=", & optionPrefix
, & optionSuffix
) )
275 iterativeMode
= strtobool( optionSuffix
, *argv
);
279 else if( strprefixcmp( *argv
, "--resources=", & optionPrefix
, & optionSuffix
) )
281 useResources
= strtobool( optionSuffix
, *argv
);
285 else if( strprefixcmp( *argv
, "--stats=", & optionPrefix
, & optionSuffix
) )
287 memoryStats
= strtobool( optionSuffix
, *argv
);
291 else if( strprefixcmp( *argv
, "--memclean=", & optionPrefix
, & optionSuffix
) )
293 cleanupMemory
= strtobool( optionSuffix
, *argv
);
297 else if( strprefixcmp( *argv
, "--showfiles=", & optionPrefix
, & optionSuffix
) )
299 Ast::theShapesScanner
.setShowFiles( strtobool( optionSuffix
, *argv
) );
303 else if( strprefixcmp( *argv
, "--pdf-version=", & optionPrefix
, & optionSuffix
) || /* Note that we use that || shortcuts! */
304 strprefixcmp( *argv
, "-v", & optionPrefix
, & optionSuffix
) )
306 if( pdfVersion
!= SimplePDF::PDF_Version::VERSION_UNDEFINED
)
308 std::cerr
<< "Multiply defined pdf version." << std::endl
;
309 exit( Interaction::EXIT_INVOCATION_ERROR
);
312 switch( *optionSuffix
)
315 pdfVersionAction
= SimplePDF::PDF_Version::ERROR
;
318 pdfVersionAction
= SimplePDF::PDF_Version::WARN
;
321 pdfVersionAction
= SimplePDF::PDF_Version::SILENT
;
324 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
;
325 exit( Interaction::EXIT_INVOCATION_ERROR
);
328 if( strncmp( optionSuffix
, "1.", 2 ) == 0 &&
329 '1' <= optionSuffix
[2] && optionSuffix
[2] <= '6' )
331 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
};
332 pdfVersion
= versions
[ optionSuffix
[2] - '1' ];
334 else if( strcmp( optionSuffix
, "X" ) == 0 )
336 std::cerr
<< "Restriction to PDF-X is not implemented, please try using a low version number, such as 1.1 instead." << std::endl
;
340 std::cerr
<< "Unsupported pdf version specification: " << optionSuffix
<< std::endl
;
341 exit( Interaction::EXIT_INVOCATION_ERROR
);
346 else if( strprefixcmp( *argv
, "--warn=", & optionPrefix
, & optionSuffix
) ||
347 strprefixcmp( *argv
, "-W", & optionPrefix
, & optionSuffix
) )
349 if( strcmp( optionSuffix
, "display" ) == 0 ||
350 strcmp( optionSuffix
, "d" ) == 0 )
352 Interaction::warningAction
= Interaction::WARNING_DISPLAY
;
354 else if( strcmp( optionSuffix
, "error" ) == 0 ||
355 strcmp( optionSuffix
, "e" ) == 0 )
357 Interaction::warningAction
= Interaction::WARNING_ERROR
;
359 else if( strcmp( optionSuffix
, "ignore" ) == 0 ||
360 strcmp( optionSuffix
, "i" ) == 0 )
362 Interaction::warningAction
= Interaction::WARNING_IGNORE
;
366 std::cerr
<< "Unsupported warning action: " << optionSuffix
<< std::endl
;
367 exit( Interaction::EXIT_INVOCATION_ERROR
);
372 else if( strprefixcmp( *argv
, "--tp=", & optionPrefix
, & optionSuffix
) )
374 Kernel::allowTransparency
= strtobool( optionSuffix
, *argv
);
378 else if( strprefixcmp( *argv
, "--spot-pair=", & optionPrefix
, & optionSuffix
) )
380 Kernel::allowSingletonPaths
= ! strtobool( optionSuffix
, *argv
);
384 else if( strprefixcmp( *argv
, "--unit=", & optionPrefix
, & optionSuffix
) )
386 Interaction::displayUnitName
= optionSuffix
;
391 else if( strprefixcmp( *argv
, "--splicingtol=", & optionPrefix
, & optionSuffix
) )
395 Computation::theTrixelizeSplicingTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
399 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
400 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
402 if( Computation::theTrixelizeSplicingTol
<= 0 )
404 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeSplicingTol
.offtype
< 1, 0 >( ) << std::endl
;
405 exit( Interaction::EXIT_INVOCATION_ERROR
);
411 else if( strprefixcmp( *argv
, "--overlaptol=", & optionPrefix
, & optionSuffix
) )
415 Computation::theTrixelizeOverlapTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
419 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
420 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
422 if( Computation::theTrixelizeOverlapTol
<= 0 )
424 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeOverlapTol
.offtype
< 1, 0 >( ) << std::endl
;
425 exit( Interaction::EXIT_INVOCATION_ERROR
);
431 else if( strcmp( *argv
, "--needpath" ) == 0 ||
432 strncmp( *argv
, "-N", 2 ) == 0 )
434 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
436 const char * pth
= 0;
439 argcAssertion( *argv
, argc
, 2 );
447 if( strchr( pth
, ':' ) != 0 )
449 const char * flag
= 0;
450 const char * shortFlag
= "-N";
460 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
463 std::cerr
<< " (or " << shortFlag
<< ")" ;
465 std::cerr
<<"." << std::endl
;
466 exit( Interaction::EXIT_INVOCATION_ERROR
);
469 Ast::theShapesScanner
.push_backNeedPath( absoluteDirectory( pth
) );
482 else if( strcmp( *argv
, "--fontmetricspath" ) == 0 ||
483 strncmp( *argv
, "-M", 2 ) == 0 )
485 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
487 const char * pth
= 0;
490 argcAssertion( *argv
, argc
, 2 );
498 if( strchr( pth
, ':' ) != 0 )
500 const char * flag
= 0;
501 const char * shortFlag
= "-M";
511 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
514 std::cerr
<< " (or " << shortFlag
<< ")" ;
516 std::cerr
<<"." << std::endl
;
517 exit( Interaction::EXIT_INVOCATION_ERROR
);
520 Lang::Font::push_backFontMetricsPath( absoluteDirectory( pth
) );
533 else if( strprefixcmp( *argv
, "--seed=", & optionPrefix
, & optionSuffix
) )
536 long s
= strtol( optionSuffix
, &endp
, 10 );
539 std::cerr
<< "Argument to " << optionPrefix
<< " was not an integer: " << optionSuffix
<< std::endl
;
540 exit( Interaction::EXIT_INVOCATION_ERROR
);
548 else if( strprefixcmp( *argv
, "--arcdelta=", & optionPrefix
, & optionSuffix
) )
552 Computation::the_arcdelta
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
556 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
557 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
559 if( Computation::the_arcdelta
<= 0 )
561 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
562 exit( Interaction::EXIT_INVOCATION_ERROR
);
568 else if( strprefixcmp( *argv
, "--dtmin=", & optionPrefix
, & optionSuffix
) )
571 Computation::the_dtMin
= strtod( optionSuffix
, &endp
);
574 std::cerr
<< "Argument to " << optionPrefix
<< " was not a float: " << optionSuffix
<< std::endl
;
575 exit( Interaction::EXIT_INVOCATION_ERROR
);
577 if( Computation::the_dtMin
<= 0 )
579 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::the_dtMin
<< std::endl
;
580 exit( Interaction::EXIT_INVOCATION_ERROR
);
586 else if( strprefixcmp( *argv
, "--disttol=", & optionPrefix
, & optionSuffix
) )
590 Computation::theDistanceTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
594 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
595 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
597 if( Computation::theDistanceTol
<= 0 )
599 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
600 exit( Interaction::EXIT_INVOCATION_ERROR
);
606 else if( strcmp( *argv
, "--prepend" ) == 0 )
608 argcAssertion( *argv
, argc
, 2 );
609 prependStreamOut
<< *( argv
+ 1 ) << std::endl
;
613 else if( strcmp( *argv
, "--base" ) == 0 )
615 argcAssertion( *argv
, argc
, 2 );
618 std::cerr
<< "The name base is multiply specified." << std::endl
;
619 exit( Interaction::EXIT_INVOCATION_ERROR
);
621 baseName
= *( argv
+ 1 );
625 else if( strcmp( *argv
, "--which" ) == 0 )
627 argcAssertion( *argv
, argc
, 2 );
628 filenameRequestList
.push_back( FILENAME_RESOURCE
);
629 resourceRequestList
.push_back( *( argv
+ 1 ) );
633 else if( strcmp( *argv
, "--in" ) == 0 )
635 argcAssertion( *argv
, argc
, 2 );
636 if( inputName
!= "" )
638 std::cerr
<< "The input file is multiply specified." << std::endl
;
639 exit( Interaction::EXIT_INVOCATION_ERROR
);
641 inputName
= absoluteFilename( *( argv
+ 1 ) );
645 else if( strcmp( *argv
, "--which-in" ) == 0 )
647 filenameRequestList
.push_back( FILENAME_IN
);
651 else if( strcmp( *argv
, "--out" ) == 0 )
653 argcAssertion( *argv
, argc
, 2 );
654 if( outputName
!= "" )
656 std::cerr
<< "The output file is multiply specified." << std::endl
;
657 exit( Interaction::EXIT_INVOCATION_ERROR
);
659 outputName
= absoluteFilename( *( argv
+ 1 ) );
663 else if( strcmp( *argv
, "--which-out" ) == 0 )
665 filenameRequestList
.push_back( FILENAME_OUT
);
669 else if( strcmp( *argv
, "--texjob" ) == 0 )
671 argcAssertion( *argv
, argc
, 2 );
672 if( texJobName
!= "" )
674 std::cerr
<< "The tex job name is multiply specified." << std::endl
;
675 exit( Interaction::EXIT_INVOCATION_ERROR
);
677 texJobName
= *( argv
+ 1 );
678 if( texJobName
.find( '/' ) != std::string::npos
)
680 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
;
681 exit( Interaction::EXIT_INVOCATION_ERROR
);
686 else if( strcmp( *argv
, "--which-texjob" ) == 0 )
688 filenameRequestList
.push_back( FILENAME_TEXJOB
);
692 else if( strcmp( *argv
, "--labeldb" ) == 0 )
694 argcAssertion( *argv
, argc
, 2 );
695 if( labelDBName
!= "" )
697 std::cerr
<< "The label database file is multiply specified." << std::endl
;
698 exit( Interaction::EXIT_INVOCATION_ERROR
);
700 labelDBName
= absoluteFilename( *( argv
+ 1 ) );
704 else if( strcmp( *argv
, "--which-labeldb" ) == 0 )
706 filenameRequestList
.push_back( FILENAME_LABELDB
);
710 else if( strcmp( *argv
, "--afmout" ) == 0 )
712 argcAssertion( *argv
, argc
, 2 );
713 if( fontmetricsOutputName
!= "" )
715 std::cerr
<< "The font metrics output name is multiply specified." << std::endl
;
716 exit( Interaction::EXIT_INVOCATION_ERROR
);
718 fontmetricsOutputName
= absoluteFilename( *( argv
+ 1 ) );
722 else if( strcmp( *argv
, "--which-afmout" ) == 0 )
724 filenameRequestList
.push_back( FILENAME_AFM
);
728 else if( strcmp( *argv
, "--which-TEXINPUTS" ) == 0 )
730 filenameRequestList
.push_back( FILENAME_TEXINPUTS
);
734 else if( strcmp( *argv
, "--which-doc" ) == 0 )
736 filenameRequestList
.push_back( FILENAME_HTMLDOC
);
740 else if( strcmp( *argv
, "--which-share" ) == 0 )
742 filenameRequestList
.push_back( FILENAME_SHARE
);
746 else if( strcmp( *argv
, "--outdir" ) == 0 )
748 argcAssertion( *argv
, argc
, 2 );
751 std::cerr
<< "The output directory is multiply specified." << std::endl
;
752 exit( Interaction::EXIT_INVOCATION_ERROR
);
754 outDir
= absoluteDirectory( *( argv
+ 1 ) );
758 else if( strprefixcmp( *argv
, "--tmp*=", & optionPrefix
, & optionSuffix
) )
760 allowCreateTmpDir
= strtobool( optionSuffix
, *argv
);
764 else if( strcmp( *argv
, "--tmpdir" ) == 0 )
766 argcAssertion( *argv
, argc
, 2 );
769 std::cerr
<< "The temporaries directory is multiply specified." << std::endl
;
770 exit( Interaction::EXIT_INVOCATION_ERROR
);
772 tmpDir
= absoluteDirectory( *( argv
+ 1 ) );
776 else if( strcmp( *argv
, "--which-tmp" ) == 0 )
778 filenameRequestList
.push_back( FILENAME_TMP
);
782 else if( strprefixcmp( *argv
, "--split=", & optionPrefix
, & optionSuffix
) )
784 if( strcmp( optionSuffix
, "no" ) == 0 )
786 splitMode
= SPLIT_NO
;
788 else if( strcmp( optionSuffix
, "flat" ) == 0 )
790 splitMode
= SPLIT_FLAT
;
792 else if( strcmp( optionSuffix
, "dir" ) == 0 )
794 splitMode
= SPLIT_DIR
;
798 std::cerr
<< "The string \"" << optionSuffix
<< "\" in the command line argument \"" << *argv
<< "\" was not any of { 'no', 'flat', 'dir' }." << std::endl
;
803 else if( strcmp( *argv
, "--xpdf" ) == 0 )
805 previewOptions
.launch_xpdf
= true;
809 else if( strcmp( *argv
, "--xpdf-remote" ) == 0 )
811 argcAssertion( *argv
, argc
, 2 );
812 if( previewOptions
.xpdfServer
!= "" )
814 std::cerr
<< "The xpdf server is multiply specified." << std::endl
;
815 exit( Interaction::EXIT_INVOCATION_ERROR
);
817 previewOptions
.xpdfServer
= *( argv
+ 1 );
821 else if( strcmp( *argv
, "--xpdf-no-server" ) == 0 )
823 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
825 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
826 exit( Interaction::EXIT_INVOCATION_ERROR
);
828 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_NOSERVER
;
832 else if( strcmp( *argv
, "--xpdf-reload" ) == 0 )
834 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
836 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
837 exit( Interaction::EXIT_INVOCATION_ERROR
);
839 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
843 else if( strcmp( *argv
, "--xpdf-quit" ) == 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_QUIT
;
854 else if( strcmp( *argv
, "--open" ) == 0 )
856 previewOptions
.do_open
= true;
860 else if( strcmp( *argv
, "--open-a" ) == 0 )
862 argcAssertion( *argv
, argc
, 2 );
863 previewOptions
.do_open
= true;
864 previewOptions
.do_open_application
= *( argv
+ 1 );
868 else if( strcmp( *argv
, "--version" ) == 0 )
871 exit( Interaction::EXIT_OK
);
877 std::cerr
<< "The name base is multiply specified." << std::endl
;
878 exit( Interaction::EXIT_INVOCATION_ERROR
);
881 if( stat( *argv
, & theStat
) == 0 &&
882 ( theStat
.st_mode
& S_IFDIR
) == 0 ) /* We are not interested in directories here. */
885 char * ext
= *argv
+ strlen( *argv
) - 6;
888 std::cerr
<< "The file name \"" << *argv
<< "\" is unexpectedly short (it should include the \".shape\" suffix)." << std::endl
;
889 exit( Interaction::EXIT_INVOCATION_ERROR
);
891 if( strcmp( ext
, ".shape" ) != 0 )
893 std::cerr
<< "Expected \".shape\" suffix in the file name \"" << *argv
<< "\"." << std::endl
;
894 exit( Interaction::EXIT_INVOCATION_ERROR
);
899 if( (*argv
)[ strlen( *argv
) - 1 ] == '.' )
901 inputName
= std::string( *argv
) + "shape";
905 inputName
= std::string( *argv
) + ".shape";
907 if( ! stat( inputName
.c_str( ), & theStat
) == 0 )
909 /* It is not entirely clear what is the best error message here,
910 * as the source file may be specified in several different ways.
911 * This should cause the least confusion.
913 std::cerr
<< "Failed to locate input file: " << *argv
<< std::endl
;
914 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
918 const char * slash
= strrchr( inputName
.c_str( ), '/' );
921 slash
= inputName
.c_str( );
927 size_t skipCount
= slash
- inputName
.c_str( );
928 baseName
= inputName
.substr( skipCount
, inputName
.length( ) - skipCount
- 6 );
935 std::cerr
<< "Illegal command line option: " << *argv
<< std::endl
;
936 exit( Interaction::EXIT_INVOCATION_ERROR
);
942 char * start
= getenv( "SHAPESTMPDIR" );
945 tmpDir
= absoluteDirectory( start
);
949 tmpDir
= absoluteDirectory( "" );
954 if( interactiveMode
)
960 outDir
= absoluteDirectory( "" );
963 ensureTmpDirectoryExists( tmpDir
, allowCreateTmpDir
);
967 if( interactiveMode
)
969 if( outputName
== "" )
971 if( splitMode
== SPLIT_NO
)
973 outputName
= outDir
+ "#shapes" + ".pdf";
977 outputName
= outDir
+ "#shapes" ;
981 if( texJobName
== "" )
983 texJobName
= "#shapes.labels";
988 if( inputName
== "" )
990 inputName
= absoluteFilename( ( baseName
+ ".shape" ).c_str( ) );
992 if( outputName
== "" )
994 if( splitMode
== SPLIT_NO
)
996 outputName
= outDir
+ baseName
+ ".pdf";
1000 outputName
= outDir
+ baseName
;
1003 if( texJobName
== "" )
1005 texJobName
= baseName
+ ".labels";
1007 if( labelDBName
== "" )
1009 labelDBName
= outDir
+ baseName
+ ".labels.pdf";
1011 if( fontmetricsOutputName
== "" )
1013 fontmetricsOutputName
= outDir
+ baseName
+ ".afm";
1017 if( outputName
== "" )
1019 if( ! filenameRequestList
.empty( ) )
1021 /* The output name will never really be used, so it's rather harmless to assign a dummy value.
1023 outputName
= "?.pdf" ;
1027 std::cerr
<< "The output file is undetermined. Consider specifying it using \"--out <filename>\"." << std::endl
;
1028 exit( Interaction::EXIT_INVOCATION_ERROR
);
1032 if( labelDBName
== "" )
1034 iterativeMode
= false;
1036 if( iterativeMode
== false )
1038 /* If the iterative mode has explicitly been turned off, we prevent any old labels from being reused. */
1042 if( ! Kernel::theDebugLog
.initialized( ) )
1044 std::string::size_type suffixSep
= outputName
.rfind( '.' );
1045 if( suffixSep
!= std::string::npos
&& outputName
.find( '/', suffixSep
) == std::string::npos
)
1047 /* If there would have been a slash after the '.', the dot would have been part of a directory name.
1048 * Otherwise, we conclude that we have found the extension of a filename, and replace that extension
1051 Kernel::theDebugLog
.setFilename( outputName
.substr( 0, suffixSep
) + ".log" );
1053 else if( baseName
!= "" )
1055 Kernel::theDebugLog
.setFilename( outDir
+ baseName
+ ".log" );
1059 Kernel::theDebugLog
.setFilename( outDir
+ "#shapes.log" );
1065 std::string inPath
= inputName
;
1066 std::string::size_type slash
= inPath
.rfind( '/' );
1067 if( slash
== std::string::npos
)
1069 inDir
= absoluteDirectory( "" );
1073 inDir
= absoluteDirectory( inPath
.substr( 0, slash
).c_str( ) );
1075 Ast::theShapesScanner
.setSourceDir( inDir
);
1076 Kernel::theTeXLabelManager
.setup( inDir
, tmpDir
, texJobName
);
1079 if( Computation::theTrixelizeSplicingTol
>= Computation::theTrixelizeOverlapTol
)
1081 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
;
1082 exit( Interaction::EXIT_INVOCATION_ERROR
);
1085 if( previewOptions
.xpdfServer
== "" )
1087 previewOptions
.xpdfServer
= outputName
;
1090 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_DEFAULT
)
1092 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RAISE
;
1095 addDefaultNeedPath( );
1096 addDefaultFontMetricsPath( );
1100 Ast::theShapesScanner
.push_backNeedPath( std::string( Kernel::RESOURCES_DIR
) + "/extensions/" );
1101 Lang::Font::push_backFontMetricsPath( std::string( Kernel::RESOURCES_DIR
) + "/fontmetrics/" );
1104 if( ! filenameRequestList
.empty( ) )
1106 std::list
< const char * >::const_iterator resource
= resourceRequestList
.begin( );
1107 for( std::list
< int >::const_iterator i
= filenameRequestList
.begin( );
1108 i
!= filenameRequestList
.end( );
1114 if( inputName
== "" )
1116 std::cout
<< "<stdin>" ;
1120 std::cout
<< inputName
;
1124 std::cout
<< outputName
;
1127 std::cout
<< tmpDir
;
1129 case FILENAME_TEXJOB
:
1130 std::cout
<< tmpDir
<< texJobName
;
1132 case FILENAME_LABELDB
:
1133 std::cout
<< labelDBName
;
1136 std::cout
<< fontmetricsOutputName
;
1138 case FILENAME_TEXINPUTS
:
1140 std::cout
<< getenv( "TEXINPUTS" ) ;
1143 case FILENAME_HTMLDOC
:
1145 std::cout
<< Kernel::HTML_DIR
<< "/index.html" ;
1148 case FILENAME_SHARE
:
1150 std::cout
<< Kernel::RESOURCES_DIR
;
1153 case FILENAME_RESOURCE
:
1157 std::cout
<< Ast::theShapesScanner
.searchFile( *resource
) ;
1159 catch( const Exceptions::Exception
& ball
)
1162 ball
.display( std::cerr
);
1163 exit( Interaction::EXIT_INVOCATION_ERROR
);
1169 std::cerr
<< "Internal error: filename request switch in main out of range." << std::endl
;
1170 exit( Interaction::EXIT_INTERNAL_ERROR
);
1172 std::cout
<< std::endl
;
1174 exit( Interaction::EXIT_OK
);
1177 if( pdfVersion
== SimplePDF::PDF_Version::VERSION_UNDEFINED
)
1179 pdfVersion
= SimplePDF::PDF_Version::PDF_1_4
;
1182 Kernel::the_PDF_version
.setVersion( pdfVersion
);
1183 Kernel::the_PDF_version
.setAction( pdfVersionAction
);
1186 std::ostringstream oss
;
1189 struct tm
* now( gmtime( &tmp
) );
1191 << std::setfill( '0' )
1192 << std::setw(4) << 1900 + now
->tm_year
1193 << std::setw(2) << 1 + now
->tm_mon
1194 << std::setw(2) << now
->tm_mday
1195 << std::setw(2) << now
->tm_hour
1196 << std::setw(2) << now
->tm_min
1197 << std::setw(2) << now
->tm_sec
1199 Kernel::theDocInfo
.addInfo( "CreationDate", SimplePDF::newString( oss
.str( ).c_str( ) ) );
1202 std::istringstream prependStreamIn
;
1203 if( ! prependStreamOut
.str( ).empty( ) )
1205 prependStreamIn
.str( prependStreamOut
.str( ) );
1206 Ast::theShapesScanner
.queueStream( & prependStreamIn
, Ast::FileID::build_special( "<--prepend>" ) );
1209 std::ifstream iFile
;
1210 std::istream
* iFilePtr
= 0;
1211 if( inputName
== "" )
1213 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( "<stdin>" ) );
1214 iFilePtr
= & std::cin
;
1215 if( interactiveMode
)
1217 /* On some platforms, the lexer crashes if it is not given a new file at EOF,
1218 * so we need to put an empty file after the prelude to avoid that.
1220 * Note that we use the iFile object here, although this will not be pointed to
1221 * by iFilePtr, which points to std::cin instead.
1223 const char * nullName
= "/dev/null";
1224 iFile
.open( nullName
);
1225 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1227 std::cerr
<< "Failed to open " << nullName
<< " to create empty input file." << std::endl
;
1228 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1230 Ast::theShapesScanner
.queueStream( & iFile
, Ast::FileID::build_special( nullName
) );
1234 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_special( "<stdin>" ) );
1235 // Ast::theShapesScanner.setNameOf_yyin( "<stdin>" );
1240 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( inputName
.c_str( ) ) );
1241 iFile
.open( inputName
.c_str( ) );
1242 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1244 std::cerr
<< "Failed to open " << inputName
<< " for input." << std::endl
;
1245 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1248 if( ! interactiveMode
)
1250 struct stat theStat
;
1251 if( stat( inputName
.c_str( ), & theStat
) != 0 )
1253 std::cerr
<< "Failed to stat " << inputName
<< " (but it could be opened for input...)." << std::endl
;
1254 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1256 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_stat( theStat
, inputName
) );
1260 /* This will initiate the reading of preambles, and when there are no more preambles, we turn to the queue set up by calling queueStream. */
1261 Ast::theShapesScanner
.start( );
1263 RefCountPtr
< std::ifstream
> labelDBFile
= RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1264 Kernel::WarmCatalog::ShipoutList documents
;
1266 /* This is where all the evaluation takes place. It is written as a separate functions to keep the function main short.
1270 if( interactiveMode
)
1272 interactiveEvaluation( *iFilePtr
, std::cout
, outputName
, splitMode
,
1273 evalTrace
, evalBackTrace
, cleanupMemory
,
1274 labelDBFile
, labelDBName
);
1278 nonInteractiveEvaluation( documents
, splitMode
,
1279 evalTrace
, evalBackTrace
, cleanupMemory
,
1280 labelDBFile
, labelDBName
);
1283 catch( const NonLocalExit::DynamicBindingNotFound
& ball
)
1285 std::cerr
<< "Caught DynamicBindingNotFound at top level." << std::endl
1286 << "This should really not be possible; it is an internal error." << std::endl
;
1287 exit( Interaction::EXIT_INTERNAL_ERROR
);
1289 catch( const NonLocalExit::NotThisType
& ball
)
1291 std::cerr
<< "Caught NotThisType at top level." << std::endl
1292 << "This should really not be possible; it is an internal error." << std::endl
;
1293 exit( Interaction::EXIT_INTERNAL_ERROR
);
1295 catch( const NonLocalExit::NonLocalExitBase
& ball
)
1297 std::cerr
<< "Caught an unknown descendant to NonLocalExitBase at top level." << std::endl
1298 << "This should really not be possible; it is an internal error." << std::endl
;
1299 exit( Interaction::EXIT_INTERNAL_ERROR
);
1301 catch( const char * ball
)
1303 std::cerr
<< "Caught (char*) ball at top level:" << std::endl
1304 << " " << ball
<< std::endl
;
1305 exit( Interaction::EXIT_GENERIC_ERROR
);
1307 catch( const std::string
& ball
)
1309 std::cerr
<< "Caught (string) ball at top level:" << std::endl
1310 << " " << ball
<< std::endl
;
1311 exit( Interaction::EXIT_GENERIC_ERROR
);
1313 catch( const std::exception
& ball
)
1315 std::cerr
<< "Caught std::exception at top level:" << std::endl
1316 << " " << ball
.what( ) << std::endl
;
1317 exit( Interaction::EXIT_GENERIC_ERROR
);
1321 std::cerr
<< "Caught (...) ball at top level." << std::endl
;
1322 exit( Interaction::EXIT_GENERIC_ERROR
);
1325 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1327 abortProcedure( Interaction::EXIT_USER_ERROR
);
1332 std::cerr
<< "Summary:" << std::endl
;
1333 std::cerr
<< "Environments: alive: " << Kernel::Environment::liveCount
<< " of total: " << Kernel::Environment::createdCount
1334 << " (" << 100 * static_cast< double >( Kernel::Environment::liveCount
) / static_cast< double >( Kernel::Environment::createdCount
) << "%)" << std::endl
;
1341 if( documents
.size( ) != 1 )
1343 std::cerr
<< "Internal error: Failed to produce exactly one document of output although --split=no." << std::endl
;
1345 std::ofstream oFile
;
1346 noSplitOpen( & oFile
, outputName
);
1347 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
1352 rmSplitFiles( outputName
, "-" );
1353 size_t physicalPageNo
= 1;
1354 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1356 std::ofstream oFile
;
1357 splitOpen( & oFile
, outputName
, "-", physicalPageNo
);
1358 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1364 mkSplitDir( outputName
);
1365 rmSplitFiles( outputName
, "/" );
1366 size_t physicalPageNo
= 1;
1367 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1369 std::ofstream oFile
;
1370 splitOpen( & oFile
, outputName
, "/", physicalPageNo
);
1371 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1377 /* This must be done after the output has been written, and before iterativeFinish writes to the labels database file.
1379 Kernel::thePDFImporter
.free( );
1381 if( labelDBFile
!= NullPtr
< std::ifstream
>( ) )
1383 if( labelDBFile
->is_open( ) )
1385 labelDBFile
->close( );
1387 labelDBFile
= NullPtr
< std::ifstream
>( ); // Free the reference.
1392 Kernel::theTeXLabelManager
.iterativeFinish( labelDBName
);
1395 previewOptions
.preview( outputName
, splitMode
!= SPLIT_NO
);
1404 argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
)
1406 if( argc
< argcMin
)
1408 std::cerr
<< "The command line option " << optionSpecifier
<< " requires " << argcMin
- 1 << " parameters." << std::endl
;
1409 exit( Interaction::EXIT_INVOCATION_ERROR
);
1414 strprefixcmp( char * str
, const char * prefix
, const char ** prefixDst
, char ** endp
)
1416 *prefixDst
= prefix
;
1417 int len
= strlen( prefix
);
1418 bool res
= ( strncmp( str
, prefix
, len
) == 0 );
1424 strtobool( const char * str
, const char * containingString
, const char * trueLabel
, const char * falseLabel
)
1426 if( trueLabel
!= 0 &&
1427 strcmp( str
, trueLabel
) == 0 )
1431 if( falseLabel
!= 0 &&
1432 strcmp( str
, falseLabel
) == 0 )
1436 if( strcmp( str
, "yes" ) == 0 ||
1437 strcmp( str
, "true" ) == 0 ||
1438 strcmp( str
, "on" ) == 0 )
1442 if( strcmp( str
, "no" ) == 0 ||
1443 strcmp( str
, "false" ) == 0 ||
1444 strcmp( str
, "off" ) == 0)
1448 std::cerr
<< "The string \"" << str
<< "\" in the command line argument \"" << containingString
<< "\" was not recognized as a boolean value." << std::endl
;
1449 exit( Interaction::EXIT_INVOCATION_ERROR
);
1453 RefCountPtr
< std::ifstream
>
1454 performIterativeStartup( const std::string
& labelDBName
)
1457 struct stat theStat
;
1458 if( stat( labelDBName
.c_str( ), & theStat
) != 0 )
1460 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1464 // ostringstream mvCommand;
1465 // mvCommand << "cp '" << oldFilename.str( ) << "' '" << labelDBName.str( ) << "'" ;
1466 // Interaction::systemDebugMessage( mvCommand.str( ) );
1467 // if( system( mvCommand.str( ).c_str( ) ) != 0 )
1469 // return RefCountPtr< std::ifstream >( NullPtr< std::ifstream >( ) );
1472 RefCountPtr
< std::ifstream
> labelsFile( new std::ifstream( labelDBName
.c_str( ) ) );
1473 if( ! labelsFile
->good( ) )
1475 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1479 Kernel::theTeXLabelManager
.iterativeStartup( labelsFile
);
1482 catch( const char * ball
)
1484 std::cerr
<< "Caught (char*) ball from iterative startup:" << std::endl
1485 << " " << ball
<< std::endl
;
1486 exit( Interaction::EXIT_GENERIC_ERROR
);
1488 catch( const std::string
& ball
)
1490 std::cerr
<< "Caught (string) ball from iterative startup:" << std::endl
1491 << " " << ball
<< std::endl
;
1492 exit( Interaction::EXIT_GENERIC_ERROR
);
1494 catch( const Exceptions::Exception
& ball
)
1496 ball
.display( std::cerr
);
1497 exit( ball
.exitCode( ) );
1501 std::cerr
<< "Caught (...) ball from iterative startup." << std::endl
;
1502 exit( Interaction::EXIT_GENERIC_ERROR
);
1508 abortProcedure( int exitCode
)
1510 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1513 while( ! Kernel::thePostCheckErrorsList
.empty( ) )
1515 Exceptions::Exception
* e
= Kernel::thePostCheckErrorsList
.front( );
1516 Kernel::thePostCheckErrorsList
.pop_front( );
1518 typedef const Exceptions::PostCondition ErrorType
;
1519 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1522 std::cerr
<< err
->loc( ) << ": " ;
1523 err
->display( std::cerr
);
1528 typedef const Exceptions::RuntimeError ErrorType
;
1529 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1532 std::cerr
<< err
->getLoc( ) << " (runtime): " ;
1533 err
->display( std::cerr
);
1537 std::cerr
<< "(Bad post-exception type)" << ": " ;
1538 e
->display( std::cerr
);
1541 std::cerr
<< "Aborting job. Output files are left unchanged." << std::endl
;
1549 void setSelfRef( RefCountPtr
< const Lang::Class
> cls
)
1551 cls
->setSelfRef( cls
);
1553 void initClass( RefCountPtr
< const Lang::Class
> cls
)
1555 Lang::SystemFinalClass
* typedPtr
= dynamic_cast< Lang::SystemFinalClass
* >( const_cast< Lang::Class
* >( cls
.getPtr( ) ) );
1562 std::cerr
<< "Helpers::initMutators was called with object of bad type." << std::endl
;
1563 exit( Interaction::EXIT_INTERNAL_ERROR
);
1572 Lang::ElementaryPath2D
* bbox
= new Lang::ElementaryPath2D
;
1573 bbox
->push_back( new Concrete::PathPoint2D( 0, 0 ) );
1575 Lang::THE_POINTPICTURE
= RefCountPtr
< Lang::Drawable2D
>( new Lang::BBoxed2D( Lang::THE_NULL2D
,
1576 RefCountPtr
< Lang::ElementaryPath2D
>( bbox
) ) );
1577 Helpers::setSelfRef( Lang::THE_OBJECT
);
1579 Helpers::setSelfRef( Lang::Void::TypeID
);
1580 Helpers::setSelfRef( Lang::Symbol::TypeID
);
1581 Helpers::setSelfRef( Lang::Float::TypeID
);
1582 Helpers::setSelfRef( Lang::Length::TypeID
);
1583 Helpers::setSelfRef( Lang::Integer::TypeID
);
1584 Helpers::setSelfRef( Lang::Boolean::TypeID
);
1585 Helpers::setSelfRef( Lang::String::TypeID
);
1586 Helpers::setSelfRef( Lang::FloatPair::TypeID
);
1587 Helpers::setSelfRef( Lang::FloatTriple::TypeID
);
1588 Helpers::setSelfRef( Lang::Coords2D::TypeID
);
1589 Helpers::setSelfRef( Lang::CornerCoords2D::TypeID
);
1590 Helpers::setSelfRef( Lang::Coords3D::TypeID
);
1592 Helpers::setSelfRef( Lang::Function::TypeID
);
1593 Helpers::setSelfRef( Lang::Transform2D::TypeID
);
1594 Helpers::setSelfRef( Lang::Transform3D::TypeID
);
1596 Helpers::setSelfRef( Lang::Class::TypeID
);
1598 Helpers::setSelfRef( Lang::TransformedInstance::TypeID
);
1600 Helpers::initClass( Lang::String::TypeID
);
1601 Helpers::initClass( Kernel::WarmGroup2D::TypeID
);
1602 Helpers::initClass( Kernel::WarmGroup3D::TypeID
);
1603 Helpers::initClass( Kernel::WarmCatalog::TypeID
);
1604 Helpers::initClass( Kernel::WarmDebugger::TypeID
);
1605 Helpers::initClass( Kernel::Warm_vector::TypeID
);
1606 Helpers::initClass( Lang::Font::TypeID
);
1607 Helpers::initClass( Lang::SingleList::TypeID
);
1608 Helpers::initClass( Lang::ConsPair::TypeID
);
1609 Helpers::initClass( Lang::VectorFunction::TypeID
);
1610 Helpers::initClass( Lang::Transform2D::TypeID
);
1611 Helpers::initClass( Lang::Transform3D::TypeID
);
1614 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric2D" ) );
1615 Lang::Geometric2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1616 Helpers::setSelfRef( Lang::Geometric2D::TypeID
);
1617 /* Note that addVirtual must not be called before the selfRef is set!
1621 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric3D" ) );
1622 Lang::Geometric3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1623 Helpers::setSelfRef( Lang::Geometric3D::TypeID
);
1624 /* Note that addVirtual must not be called before the selfRef is set!
1628 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable2D" ) );
1629 Lang::Drawable2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1630 Helpers::setSelfRef( Lang::Drawable2D::TypeID
);
1631 /* Note that addVirtual must not be called before the selfRef is set!
1633 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1636 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable3D" ) );
1637 Lang::Drawable3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1638 Helpers::setSelfRef( Lang::Drawable3D::TypeID
);
1639 /* Note that addVirtual must not be called before the selfRef is set!
1641 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1644 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Color" ) );
1645 Lang::Color::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1646 Helpers::setSelfRef( Lang::Color::TypeID
);
1647 /* Note that addVirtual must not be called before the selfRef is set!
1649 tmp
->addVirtual( "stroking" );
1650 tmp
->addVirtual( "nonstroking" );
1655 FT_Error error
= FT_Init_FreeType( & Kernel::theFreeType
);
1658 std::cerr
<< "Failed to initialize FreeType library object: " << Kernel::FreeTypeErrorMessage( error
) << std::endl
;
1659 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1663 #ifdef HAVE_FONTCONFIG
1664 if( FcInit( ) != FcTrue
)
1666 std::cerr
<< "Failed to initialize FontConfig library." << std::endl
;
1667 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1673 Interaction::PreviewOptions::preview( const std::string
& filename
, bool splitNoLaunch
) const
1679 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1683 xpdfHelper( filename
);
1691 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1695 openHelper( filename
);
1701 Interaction::PreviewOptions::xpdfHelper( const std::string
& filename
) const
1703 pid_t xpdfProcess
= fork( );
1704 if( xpdfProcess
== -1 )
1706 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running xpdf." ) );
1709 if( xpdfProcess
== 0 ) /* This is the child */
1711 /* The exec call below never returns, so the child process never leaves this if clause.
1712 * Hence, there is no need to create a special else clasuse below.
1714 switch( xpdfAction
)
1717 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-raise", filename
.c_str( ), static_cast< const char * >( 0 ) );
1720 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-reload", static_cast< const char * >( 0 ) );
1723 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-quit", static_cast< const char * >( 0 ) );
1726 execlp( "xpdf", "xpdf", filename
.c_str( ), static_cast< const char * >( 0 ) );
1729 std::cerr
<< "Internal error: XpdfAction switch out of range." << std::endl
;
1730 exit( Interaction::EXIT_INTERNAL_ERROR
);
1734 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to xpdf." << std::endl
;
1735 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1737 std::cerr
<< "execlp call to xpdf returned with errno == 0." << std::endl
;
1738 exit( Interaction::EXIT_INTERNAL_ERROR
);
1744 Interaction::PreviewOptions::openHelper( const std::string
& filename
) const
1746 pid_t openProcess
= fork( );
1747 if( openProcess
== -1 )
1749 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running open." ) );
1752 if( openProcess
== 0 ) /* This is the child */
1754 /* The exec call below never returns, so the child process never leaves this if clause.
1755 * Hence, there is no need to create a special else clasuse below.
1757 if( do_open_application
!= 0 )
1759 execlp( "open", "open", "-a", do_open_application
, filename
.c_str( ), static_cast< const char * >( 0 ) );
1763 execlp( "open", "open", filename
.c_str( ), static_cast< const char * >( 0 ) );
1767 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to open." << std::endl
;
1768 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1770 std::cerr
<< "execlp call to open returned with errno == 0." << std::endl
;
1771 exit( Interaction::EXIT_INTERNAL_ERROR
);
1777 Interaction::systemDebugMessage( const std::string
& msg
)
1779 if( Interaction::debugSystem
)
1781 std::cerr
<< "System command: " << msg
<< std::endl
;
1786 Interaction::warn_or_push( Exceptions::Exception
* message
, PtrOwner_back_Access
< std::list
< Exceptions::Exception
* > > * errorsList
)
1788 switch( Interaction::warningAction
)
1790 case Interaction::WARNING_DISPLAY
:
1791 Interaction::displayWarning( *message
);
1794 case Interaction::WARNING_ERROR
:
1795 errorsList
->push_back( message
);
1797 case Interaction::WARNING_IGNORE
:
1804 Interaction::displayWarning( const Exceptions::Exception
& ball
)
1806 std::cerr
<< "***Warning*** " ;
1807 ball
.display( std::cerr
);
1811 addDefaultNeedPath( )
1813 char * start
= getenv( "SHAPESINPUTS" );
1816 Ast::theShapesScanner
.push_backNeedPath( "./" );
1819 char * tok
= strsep( & start
, ":" );
1822 Ast::theShapesScanner
.push_backNeedPath( tok
);
1823 tok
= strsep( & start
, ":" );
1828 addDefaultFontMetricsPath( )
1830 char * start
= getenv( "SHAPESFONTMETRICS" );
1835 char * tok
= strsep( & start
, ":" );
1838 Lang::Font::push_backFontMetricsPath( tok
);
1839 tok
= strsep( & start
, ":" );
1846 Helpers::requireUTF8ToMacRomanConverter( true ); // true means "cleanup"
1847 Helpers::requireMacRomanToUTF8Converter( true ); // true means "cleanup"
1848 Helpers::requireUTF8ToWinANSIConverter( true ); // true means "cleanup"
1849 Helpers::requireUTF8ToUTF16BEConverter( 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"
1855 #ifdef HAVE_FONTCONFIG
1860 FT_Error error
= FT_Done_FreeType( Kernel::theFreeType
);
1863 std::cerr
<< "Failed to \"destroy\" FreeType library object: " << Kernel::FreeTypeErrorMessage( error
) << std::endl
;
1864 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1871 absoluteFilename( const char * filename
)
1873 if( *filename
== '/' )
1877 return callDir
+ filename
;
1881 absoluteDirectory( const char * filename
)
1883 if( *filename
== '\0' )
1887 if( filename
[ strlen( filename
) - 1 ] != '/' )
1889 if( *filename
== '/' )
1891 return filename
+ std::string( "/" );
1893 return callDir
+ filename
+ "/";
1895 if( *filename
== '/' )
1899 return callDir
+ filename
;
1905 ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
)
1907 struct stat theStat
;
1908 if( stat( dirname
.c_str( ), & theStat
) == 0 )
1910 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1912 std::cerr
<< "The path " << dirname
<< " was expected to reference a directory." << std::endl
;
1913 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1915 // if( ( theStat.st_mode & S_IWOTH ) == 0 )
1917 // std::cerr << "The directory " << dirname << " was expected have write permission for others." << std::endl ;
1918 // exit( Interaction::EXIT_FILE_PERMISSION_ERROR );
1925 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
;
1926 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1929 size_t i2
= 0; /* We know there's a slash at the first position */
1930 i2
= dirname
.find( '/', i2
+ 1 );
1932 while( stat( dirname
.substr( 0, i2
).c_str( ), & theStat
) == 0 )
1935 i2
= dirname
.find( '/', i2
+ 1 );
1939 std::cerr
<< "Shapes will not create directories for temporary files at the root: " << dirname
<< std::endl
;
1940 exit( Interaction::EXIT_INVOCATION_ERROR
);
1943 mode_t oldUmask
= umask( 0 ); /* We want to be able to create directories with any permissions. */
1944 while( i2
!= std::string::npos
)
1946 if( mkdir( dirname
.substr( 0, i2
).c_str( ), theStat
.st_mode
& ( S_IRWXU
| S_IRWXG
| S_IRWXO
) ) != 0 )
1948 std::cerr
<< "Failed to create directory for temporary files (errno=" << errno
<< "): " << dirname
.substr( 0, i2
) << std::endl
;
1949 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1951 i2
= dirname
.find( '/', i2
+ 1 );
1957 escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
)
1959 const char * special
= "*?[+@!";
1960 for( std::string::const_iterator i
= str
.begin( ); i
!= str
.end( ); ++i
)
1962 if( strchr( special
, *i
) != 0 )
1971 rmSplitFiles( const std::string
& outputName
, const char * sep
)
1973 std::ostringstream rmCommand
;
1974 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1975 escapeExtGlobChars( outputName
, rmCommand
);
1976 rmCommand
<< sep
<< "+([0-9]).pdf'" ;
1977 Interaction::systemDebugMessage( rmCommand
.str( ) );
1978 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1980 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1985 mkSplitDir( const std::string
& outputName
)
1987 struct stat theStat
;
1988 if( stat( outputName
.c_str( ), & theStat
) == 0 )
1990 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1992 std::cerr
<< "The path " << outputName
<< " was expected to reference a directory." << std::endl
;
1993 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1998 if( mkdir( outputName
.c_str( ), S_IRWXU
| S_IRWXG
| S_IRWXO
) != 0 )
2000 std::cerr
<< "Failed to create directory for split document files (errno=" << errno
<< "): " << outputName
<< std::endl
;
2001 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2007 noSplitOpen( std::ofstream
* oFile
, const std::string
& outputName
)
2009 oFile
->open( outputName
.c_str( ) );
2010 if( ! oFile
->good( ) )
2012 /* If this is because the output directory does not exist, we shall inform the user about this. */
2013 std::string::size_type slash
= outputName
.rfind( '/' );
2014 if( slash
!= std::string::npos
)
2016 std::string outputDir
= outputName
.substr( 0, slash
);
2017 struct stat theStat
;
2018 if( stat( outputDir
.c_str( ), & theStat
) == 0 )
2020 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
2022 std::cerr
<< "The prefix " << outputDir
<< " of the output name must be a directory." << std::endl
;
2023 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2025 /* In case we reach here, the directory exists, so we fall back on the generic error message below. */
2029 std::cerr
<< "The file " << outputName
<< " cannot be opened for output since the directory " << outputDir
<< " does not exist." << std::endl
;
2030 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
2033 std::cerr
<< "Failed to open " << outputName
<< " for output." << std::endl
;
2034 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2039 splitOpen( std::ofstream
* oFile
, const std::string outputName
, const char * sep
, size_t physicalPageNo
)
2041 std::ostringstream oss
;
2042 oss
<< outputName
<< sep
<< physicalPageNo
<< ".pdf" ;
2043 std::string
filename( oss
.str( ) );
2044 oFile
->open( filename
.c_str( ) );
2045 if( ! oFile
->good( ) )
2047 std::cerr
<< "Failed to open " << filename
<< " for output." << std::endl
;
2048 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
2056 std::string
ind(" ");
2058 << "Usage:" << std::endl
2059 << ind
<< "shapes [OPTIONS] file[.[shape]]" << std::endl
2060 << "A subset of options is listed below, by cathegory. This message is just" << std::endl
2061 << "a reminder; legal option values are only listed in rare cases." << std::endl
2062 << "Files: --in --out --outdir --texjob --tmpdir --tmp*= --labeldb" << std::endl
2063 << "Paths: --needpath -N --fontmetricspath --resources=" << std::endl
2064 << "Multipage: --split=('no'|'flat'|'dir')" << std::endl
2065 << "PDF: (--pdf-version=|-v)(e|w|s)1.N --tp= --spot-pair=" << std::endl
2066 << "Tolerances: --arcdelta= --dtmin= --dtminerror= --splicingtol= --overlaptol=" << std::endl
2067 << "Log file: --debuglog --debuglog-stderr --debuglog-stdout" << std::endl
2068 << "Help: --help --which-doc --showfiles= --which --version" << std::endl
2069 << "Viewing: --xpdf --open --open-a" << std::endl
2070 << "Interactive: --interactive -i" << std::endl
2071 << "See the man page for a complete listing and details." << std::endl