1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
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
};
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
, "--tp=", & optionPrefix
, & optionSuffix
) )
348 Kernel::allowTransparency
= strtobool( optionSuffix
, *argv
);
352 else if( strprefixcmp( *argv
, "--spot-pair=", & optionPrefix
, & optionSuffix
) )
354 Kernel::allowSingletonPaths
= ! strtobool( optionSuffix
, *argv
);
358 else if( strprefixcmp( *argv
, "--unit=", & optionPrefix
, & optionSuffix
) )
360 Interaction::displayUnitName
= optionSuffix
;
365 else if( strprefixcmp( *argv
, "--splicingtol=", & optionPrefix
, & optionSuffix
) )
369 Computation::theTrixelizeSplicingTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
373 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
374 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
376 if( Computation::theTrixelizeSplicingTol
<= 0 )
378 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeSplicingTol
.offtype
< 1, 0 >( ) << std::endl
;
379 exit( Interaction::EXIT_INVOCATION_ERROR
);
385 else if( strprefixcmp( *argv
, "--overlaptol=", & optionPrefix
, & optionSuffix
) )
389 Computation::theTrixelizeOverlapTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
393 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
394 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
396 if( Computation::theTrixelizeOverlapTol
<= 0 )
398 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::theTrixelizeOverlapTol
.offtype
< 1, 0 >( ) << std::endl
;
399 exit( Interaction::EXIT_INVOCATION_ERROR
);
405 else if( strcmp( *argv
, "--needpath" ) == 0 ||
406 strncmp( *argv
, "-N", 2 ) == 0 )
408 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
410 const char * pth
= 0;
413 argcAssertion( *argv
, argc
, 2 );
421 if( strchr( pth
, ':' ) != 0 )
423 const char * flag
= 0;
424 const char * shortFlag
= "-N";
434 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
437 std::cerr
<< " (or " << shortFlag
<< ")" ;
439 std::cerr
<<"." << std::endl
;
440 exit( Interaction::EXIT_INVOCATION_ERROR
);
443 Ast::theShapesScanner
.push_backNeedPath( absoluteDirectory( pth
) );
456 else if( strcmp( *argv
, "--fontmetricspath" ) == 0 ||
457 strncmp( *argv
, "-M", 2 ) == 0 )
459 bool longForm
= strncmp( *argv
, "--", 2 ) == 0;
461 const char * pth
= 0;
464 argcAssertion( *argv
, argc
, 2 );
472 if( strchr( pth
, ':' ) != 0 )
474 const char * flag
= 0;
475 const char * shortFlag
= "-M";
485 std::cerr
<< "The path separator ':' is not allowed in the " << flag
<< " argument. Consider repeating " << flag
;
488 std::cerr
<< " (or " << shortFlag
<< ")" ;
490 std::cerr
<<"." << std::endl
;
491 exit( Interaction::EXIT_INVOCATION_ERROR
);
494 Lang::Font::push_backFontMetricsPath( absoluteDirectory( pth
) );
507 else if( strprefixcmp( *argv
, "--seed=", & optionPrefix
, & optionSuffix
) )
510 long s
= strtol( optionSuffix
, &endp
, 10 );
513 std::cerr
<< "Argument to " << optionPrefix
<< " was not an integer: " << optionSuffix
<< std::endl
;
514 exit( Interaction::EXIT_INVOCATION_ERROR
);
522 else if( strprefixcmp( *argv
, "--arcdelta=", & optionPrefix
, & optionSuffix
) )
526 Computation::the_arcdelta
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
530 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
531 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
533 if( Computation::the_arcdelta
<= 0 )
535 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
536 exit( Interaction::EXIT_INVOCATION_ERROR
);
542 else if( strprefixcmp( *argv
, "--dtmin=", & optionPrefix
, & optionSuffix
) )
545 Computation::the_dtMin
= strtod( optionSuffix
, &endp
);
548 std::cerr
<< "Argument to " << optionPrefix
<< " was not a float: " << optionSuffix
<< std::endl
;
549 exit( Interaction::EXIT_INVOCATION_ERROR
);
551 if( Computation::the_dtMin
<= 0 )
553 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << Computation::the_dtMin
<< std::endl
;
554 exit( Interaction::EXIT_INVOCATION_ERROR
);
560 else if( strprefixcmp( *argv
, "--disttol=", & optionPrefix
, & optionSuffix
) )
564 Computation::theDistanceTol
= Ast::theShapesScanner
.strtoLength( optionSuffix
);
568 std::cerr
<< "Argument to " << optionPrefix
<< " was not recognized as a length: " << optionSuffix
<< std::endl
;
569 abortProcedure( Interaction::EXIT_INVOCATION_ERROR
);
571 if( Computation::theDistanceTol
<= 0 )
573 std::cerr
<< "Argument to " << optionPrefix
<< " not positive: " << optionSuffix
<< std::endl
;
574 exit( Interaction::EXIT_INVOCATION_ERROR
);
580 else if( strcmp( *argv
, "--prepend" ) == 0 )
582 argcAssertion( *argv
, argc
, 2 );
583 prependStreamOut
<< *( argv
+ 1 ) << std::endl
;
587 else if( strcmp( *argv
, "--base" ) == 0 )
589 argcAssertion( *argv
, argc
, 2 );
592 std::cerr
<< "The name base is multiply specified." << std::endl
;
593 exit( Interaction::EXIT_INVOCATION_ERROR
);
595 baseName
= *( argv
+ 1 );
599 else if( strcmp( *argv
, "--which" ) == 0 )
601 argcAssertion( *argv
, argc
, 2 );
602 filenameRequestList
.push_back( FILENAME_RESOURCE
);
603 resourceRequestList
.push_back( *( argv
+ 1 ) );
607 else if( strcmp( *argv
, "--in" ) == 0 )
609 argcAssertion( *argv
, argc
, 2 );
610 if( inputName
!= "" )
612 std::cerr
<< "The input file is multiply specified." << std::endl
;
613 exit( Interaction::EXIT_INVOCATION_ERROR
);
615 inputName
= absoluteFilename( *( argv
+ 1 ) );
619 else if( strcmp( *argv
, "--which-in" ) == 0 )
621 filenameRequestList
.push_back( FILENAME_IN
);
625 else if( strcmp( *argv
, "--out" ) == 0 )
627 argcAssertion( *argv
, argc
, 2 );
628 if( outputName
!= "" )
630 std::cerr
<< "The output file is multiply specified." << std::endl
;
631 exit( Interaction::EXIT_INVOCATION_ERROR
);
633 outputName
= absoluteFilename( *( argv
+ 1 ) );
637 else if( strcmp( *argv
, "--which-out" ) == 0 )
639 filenameRequestList
.push_back( FILENAME_OUT
);
643 else if( strcmp( *argv
, "--texjob" ) == 0 )
645 argcAssertion( *argv
, argc
, 2 );
646 if( texJobName
!= "" )
648 std::cerr
<< "The tex job name is multiply specified." << std::endl
;
649 exit( Interaction::EXIT_INVOCATION_ERROR
);
651 texJobName
= *( argv
+ 1 );
652 if( texJobName
.find( '/' ) != std::string::npos
)
654 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
;
655 exit( Interaction::EXIT_INVOCATION_ERROR
);
660 else if( strcmp( *argv
, "--which-texjob" ) == 0 )
662 filenameRequestList
.push_back( FILENAME_TEXJOB
);
666 else if( strcmp( *argv
, "--labeldb" ) == 0 )
668 argcAssertion( *argv
, argc
, 2 );
669 if( labelDBName
!= "" )
671 std::cerr
<< "The label database file is multiply specified." << std::endl
;
672 exit( Interaction::EXIT_INVOCATION_ERROR
);
674 labelDBName
= absoluteFilename( *( argv
+ 1 ) );
678 else if( strcmp( *argv
, "--which-labeldb" ) == 0 )
680 filenameRequestList
.push_back( FILENAME_LABELDB
);
684 else if( strcmp( *argv
, "--afmout" ) == 0 )
686 argcAssertion( *argv
, argc
, 2 );
687 if( fontmetricsOutputName
!= "" )
689 std::cerr
<< "The font metrics output name is multiply specified." << std::endl
;
690 exit( Interaction::EXIT_INVOCATION_ERROR
);
692 fontmetricsOutputName
= absoluteFilename( *( argv
+ 1 ) );
696 else if( strcmp( *argv
, "--which-afmout" ) == 0 )
698 filenameRequestList
.push_back( FILENAME_AFM
);
702 else if( strcmp( *argv
, "--which-TEXINPUTS" ) == 0 )
704 filenameRequestList
.push_back( FILENAME_TEXINPUTS
);
708 else if( strcmp( *argv
, "--which-doc" ) == 0 )
710 filenameRequestList
.push_back( FILENAME_HTMLDOC
);
714 else if( strcmp( *argv
, "--outdir" ) == 0 )
716 argcAssertion( *argv
, argc
, 2 );
719 std::cerr
<< "The output directory is multiply specified." << std::endl
;
720 exit( Interaction::EXIT_INVOCATION_ERROR
);
722 outDir
= absoluteDirectory( *( argv
+ 1 ) );
726 else if( strprefixcmp( *argv
, "--tmp*=", & optionPrefix
, & optionSuffix
) )
728 allowCreateTmpDir
= strtobool( optionSuffix
, *argv
);
732 else if( strcmp( *argv
, "--tmpdir" ) == 0 )
734 argcAssertion( *argv
, argc
, 2 );
737 std::cerr
<< "The temporaries directory is multiply specified." << std::endl
;
738 exit( Interaction::EXIT_INVOCATION_ERROR
);
740 tmpDir
= absoluteDirectory( *( argv
+ 1 ) );
744 else if( strcmp( *argv
, "--which-tmp" ) == 0 )
746 filenameRequestList
.push_back( FILENAME_TMP
);
750 else if( strprefixcmp( *argv
, "--split=", & optionPrefix
, & optionSuffix
) )
752 if( strcmp( optionSuffix
, "no" ) == 0 )
754 splitMode
= SPLIT_NO
;
756 else if( strcmp( optionSuffix
, "flat" ) == 0 )
758 splitMode
= SPLIT_FLAT
;
760 else if( strcmp( optionSuffix
, "dir" ) == 0 )
762 splitMode
= SPLIT_DIR
;
766 std::cerr
<< "The string \"" << optionSuffix
<< "\" in the command line argument \"" << *argv
<< "\" was not any of { 'no', 'flat', 'dir' }." << std::endl
;
771 else if( strcmp( *argv
, "--xpdf" ) == 0 )
773 previewOptions
.launch_xpdf
= true;
777 else if( strcmp( *argv
, "--xpdf-remote" ) == 0 )
779 argcAssertion( *argv
, argc
, 2 );
780 if( previewOptions
.xpdfServer
!= "" )
782 std::cerr
<< "The xpdf server is multiply specified." << std::endl
;
783 exit( Interaction::EXIT_INVOCATION_ERROR
);
785 previewOptions
.xpdfServer
= *( argv
+ 1 );
789 else if( strcmp( *argv
, "--xpdf-no-server" ) == 0 )
791 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
793 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
794 exit( Interaction::EXIT_INVOCATION_ERROR
);
796 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_NOSERVER
;
800 else if( strcmp( *argv
, "--xpdf-reload" ) == 0 )
802 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
804 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
805 exit( Interaction::EXIT_INVOCATION_ERROR
);
807 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RELOAD
;
811 else if( strcmp( *argv
, "--xpdf-quit" ) == 0 )
813 if( previewOptions
.xpdfAction
!= Interaction::PreviewOptions::XPDF_DEFAULT
)
815 std::cerr
<< "The xpdf action is multiply specified." << std::endl
;
816 exit( Interaction::EXIT_INVOCATION_ERROR
);
818 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_QUIT
;
822 else if( strcmp( *argv
, "--open" ) == 0 )
824 previewOptions
.do_open
= true;
828 else if( strcmp( *argv
, "--open-a" ) == 0 )
830 argcAssertion( *argv
, argc
, 2 );
831 previewOptions
.do_open
= true;
832 previewOptions
.do_open_application
= *( argv
+ 1 );
836 else if( strcmp( *argv
, "--version" ) == 0 )
839 exit( Interaction::EXIT_OK
);
845 std::cerr
<< "The name base is multiply specified." << std::endl
;
846 exit( Interaction::EXIT_INVOCATION_ERROR
);
849 if( stat( *argv
, & theStat
) == 0 &&
850 ( theStat
.st_mode
& S_IFDIR
) == 0 ) /* We are not interested in directories here. */
853 char * ext
= *argv
+ strlen( *argv
) - 6;
856 std::cerr
<< "The file name \"" << *argv
<< "\" is unexpectedly short (it should include the \".shape\" suffix)." << std::endl
;
857 exit( Interaction::EXIT_INVOCATION_ERROR
);
859 if( strcmp( ext
, ".shape" ) != 0 )
861 std::cerr
<< "Expected \".shape\" suffix in the file name \"" << *argv
<< "\"." << std::endl
;
862 exit( Interaction::EXIT_INVOCATION_ERROR
);
867 if( (*argv
)[ strlen( *argv
) - 1 ] == '.' )
869 inputName
= std::string( *argv
) + "shape";
873 inputName
= std::string( *argv
) + ".shape";
875 if( ! stat( inputName
.c_str( ), & theStat
) == 0 )
877 /* It is not entirely clear what is the best error message here,
878 * as the source file may be specified in several different ways.
879 * This should cause the least confusion.
881 std::cerr
<< "Failed to locate input file: " << *argv
<< std::endl
;
882 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
886 const char * slash
= strrchr( inputName
.c_str( ), '/' );
889 slash
= inputName
.c_str( );
895 size_t skipCount
= slash
- inputName
.c_str( );
896 baseName
= inputName
.substr( skipCount
, inputName
.length( ) - skipCount
- 6 );
903 std::cerr
<< "Illegal command line option: " << *argv
<< std::endl
;
904 exit( Interaction::EXIT_INVOCATION_ERROR
);
910 char * start
= getenv( "SHAPESTMPDIR" );
913 tmpDir
= absoluteDirectory( start
);
917 tmpDir
= absoluteDirectory( "" );
922 if( interactiveMode
)
928 outDir
= absoluteDirectory( "" );
931 ensureTmpDirectoryExists( tmpDir
, allowCreateTmpDir
);
935 if( interactiveMode
)
937 if( outputName
== "" )
939 if( splitMode
== SPLIT_NO
)
941 outputName
= outDir
+ "#shapes" + ".pdf";
945 outputName
= outDir
+ "#shapes" ;
949 if( texJobName
== "" )
951 texJobName
= "#shapes.labels";
956 if( inputName
== "" )
958 inputName
= absoluteFilename( ( baseName
+ ".shape" ).c_str( ) );
960 if( outputName
== "" )
962 if( splitMode
== SPLIT_NO
)
964 outputName
= outDir
+ baseName
+ ".pdf";
968 outputName
= outDir
+ baseName
;
971 if( texJobName
== "" )
973 texJobName
= baseName
+ ".labels";
975 if( labelDBName
== "" )
977 labelDBName
= outDir
+ baseName
+ ".labels.pdf";
979 if( fontmetricsOutputName
== "" )
981 fontmetricsOutputName
= outDir
+ baseName
+ ".afm";
985 if( outputName
== "" )
987 if( ! filenameRequestList
.empty( ) )
989 /* The output name will never really be used, so it's rather harmless to assign a dummy value.
991 outputName
= "?.pdf" ;
995 std::cerr
<< "The output file is undetermined. Consider specifying it using \"--out <filename>\"." << std::endl
;
996 exit( Interaction::EXIT_INVOCATION_ERROR
);
1000 if( labelDBName
== "" )
1002 iterativeMode
= false;
1005 if( ! Kernel::theDebugLog
.initialized( ) )
1007 std::string::size_type suffixSep
= outputName
.rfind( '.' );
1008 if( suffixSep
!= std::string::npos
&& outputName
.find( '/', suffixSep
) == std::string::npos
)
1010 /* If there would have been a slash after the '.', the dot would have been part of a directory name.
1011 * Otherwise, we conclude that we have found the extension of a filename, and replace that extension
1014 Kernel::theDebugLog
.setFilename( outputName
.substr( 0, suffixSep
) + ".log" );
1016 else if( baseName
!= "" )
1018 Kernel::theDebugLog
.setFilename( outDir
+ baseName
+ ".log" );
1022 Kernel::theDebugLog
.setFilename( outDir
+ "#shapes.log" );
1028 std::string inPath
= inputName
;
1029 std::string::size_type slash
= inPath
.rfind( '/' );
1030 if( slash
== std::string::npos
)
1032 inDir
= absoluteDirectory( "" );
1036 inDir
= absoluteDirectory( inPath
.substr( 0, slash
).c_str( ) );
1038 Ast::theShapesScanner
.setSourceDir( inDir
);
1039 Kernel::theTeXLabelManager
.setup( inDir
, tmpDir
, texJobName
);
1042 if( Computation::theTrixelizeSplicingTol
>= Computation::theTrixelizeOverlapTol
)
1044 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
;
1045 exit( Interaction::EXIT_INVOCATION_ERROR
);
1048 if( previewOptions
.xpdfServer
== "" )
1050 previewOptions
.xpdfServer
= outputName
;
1053 if( previewOptions
.xpdfAction
== Interaction::PreviewOptions::XPDF_DEFAULT
)
1055 previewOptions
.xpdfAction
= Interaction::PreviewOptions::XPDF_RAISE
;
1058 addDefaultNeedPath( );
1059 addDefaultFontMetricsPath( );
1061 #ifdef RESOURCES_DIR
1064 Ast::theShapesScanner
.push_backNeedPath( std::string( RESOURCES_DIR
) + "/extensions/" );
1065 Lang::Font::push_backFontMetricsPath( std::string( RESOURCES_DIR
) + "/fontmetrics/" );
1069 if( ! filenameRequestList
.empty( ) )
1071 std::list
< const char * >::const_iterator resource
= resourceRequestList
.begin( );
1072 for( std::list
< int >::const_iterator i
= filenameRequestList
.begin( );
1073 i
!= filenameRequestList
.end( );
1079 if( inputName
== "" )
1081 std::cout
<< "<stdin>" ;
1085 std::cout
<< inputName
;
1089 std::cout
<< outputName
;
1092 std::cout
<< tmpDir
;
1094 case FILENAME_TEXJOB
:
1095 std::cout
<< tmpDir
<< texJobName
;
1097 case FILENAME_LABELDB
:
1098 std::cout
<< labelDBName
;
1101 std::cout
<< fontmetricsOutputName
;
1103 case FILENAME_TEXINPUTS
:
1105 std::cout
<< getenv( "TEXINPUTS" ) ;
1108 case FILENAME_HTMLDOC
:
1110 std::cout
<< HTMLDIR
<< "/index.html" ;
1113 case FILENAME_RESOURCE
:
1117 std::cout
<< Ast::theShapesScanner
.searchFile( *resource
) ;
1119 catch( const Exceptions::Exception
& ball
)
1122 ball
.display( std::cerr
);
1123 exit( Interaction::EXIT_INVOCATION_ERROR
);
1129 std::cerr
<< "Internal error: filename request switch in main out of range." << std::endl
;
1130 exit( Interaction::EXIT_INTERNAL_ERROR
);
1132 std::cout
<< std::endl
;
1134 exit( Interaction::EXIT_OK
);
1137 if( pdfVersion
== SimplePDF::PDF_Version::VERSION_UNDEFINED
)
1139 pdfVersion
= SimplePDF::PDF_Version::PDF_1_4
;
1142 Kernel::the_PDF_version
.setVersion( pdfVersion
);
1143 Kernel::the_PDF_version
.setAction( pdfVersionAction
);
1146 std::ostringstream oss
;
1149 struct tm
* now( gmtime( &tmp
) );
1151 << std::setfill( '0' )
1152 << std::setw(4) << 1900 + now
->tm_year
1153 << std::setw(2) << 1 + now
->tm_mon
1154 << std::setw(2) << now
->tm_mday
1155 << std::setw(2) << now
->tm_hour
1156 << std::setw(2) << now
->tm_min
1157 << std::setw(2) << now
->tm_sec
1159 Kernel::theDocInfo
.addInfo( "CreationDate", SimplePDF::newString( oss
.str( ).c_str( ) ) );
1162 std::istringstream prependStreamIn
;
1163 if( ! prependStreamOut
.str( ).empty( ) )
1165 prependStreamIn
.str( prependStreamOut
.str( ) );
1166 Ast::theShapesScanner
.queueStream( & prependStreamIn
, Ast::FileID::build_special( "<--prepend>" ) );
1169 std::ifstream iFile
;
1170 std::istream
* iFilePtr
= 0;
1171 if( inputName
== "" )
1173 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( "<stdin>" ) );
1174 iFilePtr
= & std::cin
;
1175 if( interactiveMode
)
1177 /* On some platforms, the lexer crashes if it is not given a new file at EOF,
1178 * so we need to put an empty file after the prelude to avoid that.
1180 * Note that we use the iFile object here, although this will not be pointed to
1181 * by iFilePtr, which points to std::cin instead.
1183 const char * nullName
= "/dev/null";
1184 iFile
.open( nullName
);
1185 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1187 std::cerr
<< "Failed to open " << nullName
<< " to create empty input file." << std::endl
;
1188 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1190 Ast::theShapesScanner
.queueStream( & iFile
, Ast::FileID::build_special( nullName
) );
1194 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_special( "<stdin>" ) );
1195 // Ast::theShapesScanner.setNameOf_yyin( "<stdin>" );
1200 Kernel::theDocInfo
.addInfo( "Title", SimplePDF::newString( inputName
.c_str( ) ) );
1201 iFile
.open( inputName
.c_str( ) );
1202 if( ! iFile
.good( ) || ! iFile
.is_open( ) )
1204 std::cerr
<< "Failed to open " << inputName
<< " for input." << std::endl
;
1205 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1208 if( ! interactiveMode
)
1210 struct stat theStat
;
1211 if( stat( inputName
.c_str( ), & theStat
) != 0 )
1213 std::cerr
<< "Failed to stat " << inputName
<< " (but it could be opened for input...)." << std::endl
;
1214 exit( Interaction::EXIT_INPUT_FILE_ERROR
);
1216 Ast::theShapesScanner
.queueStream( iFilePtr
, Ast::FileID::build_stat( theStat
, inputName
) );
1220 /* This will initiate the reading of preambles, and when there are no more preambles, we turn to the queue set up by calling queueStream. */
1221 Ast::theShapesScanner
.start( );
1223 RefCountPtr
< std::ifstream
> labelDBFile
= RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1224 Kernel::WarmCatalog::ShipoutList documents
;
1226 /* This is where all the evaluation takes place. It is written as a separate functions to keep the function main short.
1230 if( interactiveMode
)
1232 interactiveEvaluation( *iFilePtr
, std::cout
, outputName
, splitMode
,
1233 evalTrace
, evalBackTrace
, cleanupMemory
,
1234 labelDBFile
, labelDBName
);
1238 nonInteractiveEvaluation( documents
, splitMode
,
1239 evalTrace
, evalBackTrace
, cleanupMemory
,
1240 labelDBFile
, labelDBName
);
1243 catch( const NonLocalExit::DynamicBindingNotFound
& ball
)
1245 std::cerr
<< "Caught DynamicBindingNotFound at top level." << std::endl
1246 << "This should really not be possible; it is an internal error." << std::endl
;
1247 exit( Interaction::EXIT_INTERNAL_ERROR
);
1249 catch( const NonLocalExit::NotThisType
& ball
)
1251 std::cerr
<< "Caught NotThisType at top level." << std::endl
1252 << "This should really not be possible; it is an internal error." << std::endl
;
1253 exit( Interaction::EXIT_INTERNAL_ERROR
);
1255 catch( const NonLocalExit::NonLocalExitBase
& ball
)
1257 std::cerr
<< "Caught an unknown descendant to NonLocalExitBase at top level." << std::endl
1258 << "This should really not be possible; it is an internal error." << std::endl
;
1259 exit( Interaction::EXIT_INTERNAL_ERROR
);
1261 catch( const char * ball
)
1263 std::cerr
<< "Caught (char*) ball at top level:" << std::endl
1264 << " " << ball
<< std::endl
;
1265 exit( Interaction::EXIT_GENERIC_ERROR
);
1267 catch( const std::string
& ball
)
1269 std::cerr
<< "Caught (string) ball at top level:" << std::endl
1270 << " " << ball
<< std::endl
;
1271 exit( Interaction::EXIT_GENERIC_ERROR
);
1275 std::cerr
<< "Caught (...) ball at top level." << std::endl
;
1276 exit( Interaction::EXIT_GENERIC_ERROR
);
1279 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1281 abortProcedure( Interaction::EXIT_USER_ERROR
);
1286 std::cerr
<< "Summary:" << std::endl
;
1287 std::cerr
<< "Environments: alive: " << Kernel::Environment::liveCount
<< " of total: " << Kernel::Environment::createdCount
1288 << " (" << 100 * static_cast< double >( Kernel::Environment::liveCount
) / static_cast< double >( Kernel::Environment::createdCount
) << "%)" << std::endl
;
1295 if( documents
.size( ) != 1 )
1297 std::cerr
<< "Internal error: Failed to produce exactly one document of output although --split=no." << std::endl
;
1299 std::ofstream oFile
;
1300 noSplitOpen( & oFile
, outputName
);
1301 documents
.front( ).writeFile( oFile
, Kernel::the_PDF_version
);
1306 rmSplitFiles( outputName
, "-" );
1307 size_t physicalPageNo
= 1;
1308 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1310 std::ofstream oFile
;
1311 splitOpen( & oFile
, outputName
, "-", physicalPageNo
);
1312 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1318 mkSplitDir( outputName
);
1319 rmSplitFiles( outputName
, "/" );
1320 size_t physicalPageNo
= 1;
1321 for( Kernel::WarmCatalog::ShipoutList::iterator i
= documents
.begin( ); i
!= documents
.end( ); ++i
, ++physicalPageNo
)
1323 std::ofstream oFile
;
1324 splitOpen( & oFile
, outputName
, "/", physicalPageNo
);
1325 i
->writeFile( oFile
, Kernel::the_PDF_version
);
1331 /* This must be done after the output has been written, and before iterativeFinish writes to the labels database file.
1333 Kernel::thePDFImporter
.free( );
1335 if( labelDBFile
!= NullPtr
< std::ifstream
>( ) )
1337 if( labelDBFile
->is_open( ) )
1339 labelDBFile
->close( );
1341 labelDBFile
= NullPtr
< std::ifstream
>( ); // Free the reference.
1346 Kernel::theTeXLabelManager
.iterativeFinish( labelDBName
);
1349 previewOptions
.preview( outputName
, splitMode
!= SPLIT_NO
);
1358 argcAssertion( const char * optionSpecifier
, int argc
, int argcMin
)
1360 if( argc
< argcMin
)
1362 std::cerr
<< "The command line option " << optionSpecifier
<< " requires " << argcMin
- 1 << " parameters." << std::endl
;
1363 exit( Interaction::EXIT_INVOCATION_ERROR
);
1368 strprefixcmp( char * str
, const char * prefix
, const char ** prefixDst
, char ** endp
)
1370 *prefixDst
= prefix
;
1371 int len
= strlen( prefix
);
1372 bool res
= ( strncmp( str
, prefix
, len
) == 0 );
1378 strtobool( const char * str
, const char * containingString
, const char * trueLabel
, const char * falseLabel
)
1380 if( trueLabel
!= 0 &&
1381 strcmp( str
, trueLabel
) == 0 )
1385 if( falseLabel
!= 0 &&
1386 strcmp( str
, falseLabel
) == 0 )
1390 if( strcmp( str
, "yes" ) == 0 ||
1391 strcmp( str
, "true" ) == 0 ||
1392 strcmp( str
, "on" ) == 0 )
1396 if( strcmp( str
, "no" ) == 0 ||
1397 strcmp( str
, "false" ) == 0 ||
1398 strcmp( str
, "off" ) == 0)
1402 std::cerr
<< "The string \"" << str
<< "\" in the command line argument \"" << containingString
<< "\" was not recognized as a boolean value." << std::endl
;
1403 exit( Interaction::EXIT_INVOCATION_ERROR
);
1407 RefCountPtr
< std::ifstream
>
1408 performIterativeStartup( const std::string
& labelDBName
)
1411 struct stat theStat
;
1412 if( stat( labelDBName
.c_str( ), & theStat
) != 0 )
1414 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1418 // ostringstream mvCommand;
1419 // mvCommand << "cp '" << oldFilename.str( ) << "' '" << labelDBName.str( ) << "'" ;
1420 // Interaction::systemDebugMessage( mvCommand.str( ) );
1421 // if( system( mvCommand.str( ).c_str( ) ) != 0 )
1423 // return RefCountPtr< std::ifstream >( NullPtr< std::ifstream >( ) );
1426 RefCountPtr
< std::ifstream
> labelsFile( new std::ifstream( labelDBName
.c_str( ) ) );
1427 if( ! labelsFile
->good( ) )
1429 return RefCountPtr
< std::ifstream
>( NullPtr
< std::ifstream
>( ) );
1433 Kernel::theTeXLabelManager
.iterativeStartup( labelsFile
);
1436 catch( const char * ball
)
1438 std::cerr
<< "Caught (char*) ball from iterative startup:" << std::endl
1439 << " " << ball
<< std::endl
;
1440 exit( Interaction::EXIT_GENERIC_ERROR
);
1442 catch( const std::string
& ball
)
1444 std::cerr
<< "Caught (string) ball from iterative startup:" << std::endl
1445 << " " << ball
<< std::endl
;
1446 exit( Interaction::EXIT_GENERIC_ERROR
);
1448 catch( const Exceptions::Exception
& ball
)
1450 ball
.display( std::cerr
);
1451 exit( ball
.exitCode( ) );
1455 std::cerr
<< "Caught (...) ball from iterative startup." << std::endl
;
1456 exit( Interaction::EXIT_GENERIC_ERROR
);
1462 abortProcedure( int exitCode
)
1464 if( ! Kernel::thePostCheckErrorsList
.empty( ) )
1467 while( ! Kernel::thePostCheckErrorsList
.empty( ) )
1469 Exceptions::Exception
* e
= Kernel::thePostCheckErrorsList
.front( );
1470 Kernel::thePostCheckErrorsList
.pop_front( );
1472 typedef const Exceptions::PostCondition ErrorType
;
1473 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1476 std::cerr
<< err
->loc( ) << ": " ;
1477 err
->display( std::cerr
);
1482 typedef const Exceptions::RuntimeError ErrorType
;
1483 ErrorType
* err
= dynamic_cast< ErrorType
* >( e
);
1486 std::cerr
<< err
->getLoc( ) << " (runtime): " ;
1487 err
->display( std::cerr
);
1491 std::cerr
<< "(Bad post-exception type)" << ": " ;
1492 e
->display( std::cerr
);
1495 std::cerr
<< "Aborting job. Output files are left unchanged." << std::endl
;
1503 void setSelfRef( RefCountPtr
< const Lang::Class
> cls
)
1505 cls
->setSelfRef( cls
);
1507 void initClass( RefCountPtr
< const Lang::Class
> cls
)
1509 Lang::SystemFinalClass
* typedPtr
= dynamic_cast< Lang::SystemFinalClass
* >( const_cast< Lang::Class
* >( cls
.getPtr( ) ) );
1516 std::cerr
<< "Helpers::initMutators was called with object of bad type." << std::endl
;
1517 exit( Interaction::EXIT_INTERNAL_ERROR
);
1526 Lang::ElementaryPath2D
* bbox
= new Lang::ElementaryPath2D
;
1527 bbox
->push_back( new Concrete::PathPoint2D( 0, 0 ) );
1529 Lang::THE_POINTPICTURE
= RefCountPtr
< Lang::Drawable2D
>( new Lang::BBoxed2D( Lang::THE_NULL2D
,
1530 RefCountPtr
< Lang::ElementaryPath2D
>( bbox
) ) );
1531 Helpers::setSelfRef( Lang::THE_OBJECT
);
1533 Helpers::setSelfRef( Lang::Void::TypeID
);
1534 Helpers::setSelfRef( Lang::Symbol::TypeID
);
1535 Helpers::setSelfRef( Lang::Float::TypeID
);
1536 Helpers::setSelfRef( Lang::Length::TypeID
);
1537 Helpers::setSelfRef( Lang::Integer::TypeID
);
1538 Helpers::setSelfRef( Lang::Boolean::TypeID
);
1539 Helpers::setSelfRef( Lang::String::TypeID
);
1540 Helpers::setSelfRef( Lang::FloatPair::TypeID
);
1541 Helpers::setSelfRef( Lang::FloatTriple::TypeID
);
1542 Helpers::setSelfRef( Lang::Coords2D::TypeID
);
1543 Helpers::setSelfRef( Lang::CornerCoords2D::TypeID
);
1544 Helpers::setSelfRef( Lang::Coords3D::TypeID
);
1546 Helpers::setSelfRef( Lang::Function::TypeID
);
1547 Helpers::setSelfRef( Lang::Transform2D::TypeID
);
1548 Helpers::setSelfRef( Lang::Transform3D::TypeID
);
1550 Helpers::setSelfRef( Lang::Class::TypeID
);
1552 Helpers::setSelfRef( Lang::TransformedInstance::TypeID
);
1554 Helpers::initClass( Kernel::WarmGroup2D::TypeID
);
1555 Helpers::initClass( Kernel::WarmGroup3D::TypeID
);
1556 Helpers::initClass( Kernel::WarmCatalog::TypeID
);
1557 Helpers::initClass( Kernel::WarmDebugger::TypeID
);
1558 Helpers::initClass( Lang::SingleList::TypeID
);
1559 Helpers::initClass( Lang::Transform2D::TypeID
);
1560 Helpers::initClass( Lang::Transform3D::TypeID
);
1563 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric2D" ) );
1564 Lang::Geometric2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1565 Helpers::setSelfRef( Lang::Geometric2D::TypeID
);
1566 /* Note that addVirtual must not be called before the selfRef is set!
1570 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Geometric3D" ) );
1571 Lang::Geometric3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1572 Helpers::setSelfRef( Lang::Geometric3D::TypeID
);
1573 /* Note that addVirtual must not be called before the selfRef is set!
1577 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable2D" ) );
1578 Lang::Drawable2D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1579 Helpers::setSelfRef( Lang::Drawable2D::TypeID
);
1580 /* Note that addVirtual must not be called before the selfRef is set!
1582 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1585 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Drawable3D" ) );
1586 Lang::Drawable3D::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1587 Helpers::setSelfRef( Lang::Drawable3D::TypeID
);
1588 /* Note that addVirtual must not be called before the selfRef is set!
1590 tmp
->addVirtual( Lang::MESSAGE_DRAWABLE_DRAW_ID
);
1593 Lang::SystemVirtualInterface
* tmp
= new Lang::SystemVirtualInterface( strrefdup( "Color" ) );
1594 Lang::Color::TypeID
= RefCountPtr
< const Lang::Class
>( tmp
);
1595 Helpers::setSelfRef( Lang::Color::TypeID
);
1596 /* Note that addVirtual must not be called before the selfRef is set!
1598 tmp
->addVirtual( "stroking" );
1599 tmp
->addVirtual( "nonstroking" );
1604 Interaction::PreviewOptions::preview( const std::string
& filename
, bool splitNoLaunch
) const
1610 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1614 xpdfHelper( filename
);
1622 std::cerr
<< "Warning: Not launching viewer since the documet was split." << std::endl
;
1626 openHelper( filename
);
1632 Interaction::PreviewOptions::xpdfHelper( const std::string
& filename
) const
1634 pid_t xpdfProcess
= fork( );
1635 if( xpdfProcess
== -1 )
1637 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running xpdf." ) );
1640 if( xpdfProcess
== 0 ) /* This is the child */
1642 /* The exec call below never returns, so the child process never leaves this if clause.
1643 * Hence, there is no need to create a special else clasuse below.
1645 switch( xpdfAction
)
1648 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-raise", filename
.c_str( ), static_cast< const char * >( 0 ) );
1651 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-reload", static_cast< const char * >( 0 ) );
1654 execlp( "xpdf", "xpdf", "-remote", xpdfServer
.c_str( ), "-quit", static_cast< const char * >( 0 ) );
1657 execlp( "xpdf", "xpdf", filename
.c_str( ), static_cast< const char * >( 0 ) );
1660 std::cerr
<< "Internal error: XpdfAction switch out of range." << std::endl
;
1661 exit( Interaction::EXIT_INTERNAL_ERROR
);
1665 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to xpdf." << std::endl
;
1666 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1668 std::cerr
<< "execlp call to xpdf returned with errno == 0." << std::endl
;
1669 exit( Interaction::EXIT_INTERNAL_ERROR
);
1675 Interaction::PreviewOptions::openHelper( const std::string
& filename
) const
1677 pid_t openProcess
= fork( );
1678 if( openProcess
== -1 )
1680 throw Exceptions::InternalError( strrefdup( "Failed to fork a process for running open." ) );
1683 if( openProcess
== 0 ) /* This is the child */
1685 /* The exec call below never returns, so the child process never leaves this if clause.
1686 * Hence, there is no need to create a special else clasuse below.
1688 if( do_open_application
!= 0 )
1690 execlp( "open", "open", "-a", do_open_application
, filename
.c_str( ), static_cast< const char * >( 0 ) );
1694 execlp( "open", "open", filename
.c_str( ), static_cast< const char * >( 0 ) );
1698 std::cerr
<< "Recieved errno = " << errno
<< " from execlp call to open." << std::endl
;
1699 exit( Interaction::EXIT_EXTERNAL_ERROR
);
1701 std::cerr
<< "execlp call to open returned with errno == 0." << std::endl
;
1702 exit( Interaction::EXIT_INTERNAL_ERROR
);
1708 Interaction::systemDebugMessage( const std::string
& msg
)
1710 if( Interaction::debugSystem
)
1712 std::cerr
<< "System command: " << msg
<< std::endl
;
1717 addDefaultNeedPath( )
1719 char * start
= getenv( "SHAPESINPUTS" );
1722 Ast::theShapesScanner
.push_backNeedPath( "./" );
1725 char * tok
= strsep( & start
, ":" );
1728 Ast::theShapesScanner
.push_backNeedPath( tok
);
1729 tok
= strsep( & start
, ":" );
1734 addDefaultFontMetricsPath( )
1736 char * start
= getenv( "SHAPESFONTMETRICS" );
1741 char * tok
= strsep( & start
, ":" );
1744 Lang::Font::push_backFontMetricsPath( tok
);
1745 tok
= strsep( & start
, ":" );
1752 Helpers::requireUTF8ToMacRomanConverter( true ); // true means "cleanup"
1753 Helpers::requireMacRomanToUTF8Converter( true ); // true means "cleanup"
1754 Helpers::requireUTF8ToWinANSIConverter( true ); // true means "cleanup"
1755 Helpers::requireUTF8ToASCIIConverter( true ); // true means "cleanup"
1756 Helpers::requireUTF8ToUCS4Converter( true ); // true means "cleanup"
1757 Helpers::requireUTF16BEToUCS4Converter( true ); // true means "cleanup"
1758 Helpers::requireGlyphList( true ); // true means "cleanup"
1759 Helpers::requireMacRomanEncoding( true ); // true means "cleanup"
1763 absoluteFilename( const char * filename
)
1765 if( *filename
== '/' )
1769 return callDir
+ filename
;
1773 absoluteDirectory( const char * filename
)
1775 if( *filename
== '\0' )
1779 if( filename
[ strlen( filename
) - 1 ] != '/' )
1781 if( *filename
== '/' )
1783 return filename
+ std::string( "/" );
1785 return callDir
+ filename
+ "/";
1787 if( *filename
== '/' )
1791 return callDir
+ filename
;
1797 ensureTmpDirectoryExists( const std::string
& dirname
, bool allowCreate
)
1799 struct stat theStat
;
1800 if( stat( dirname
.c_str( ), & theStat
) == 0 )
1802 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1804 std::cerr
<< "The path " << dirname
<< " was expected to reference a directory." << std::endl
;
1805 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1807 // if( ( theStat.st_mode & S_IWOTH ) == 0 )
1809 // std::cerr << "The directory " << dirname << " was expected have write permission for others." << std::endl ;
1810 // exit( Interaction::EXIT_FILE_PERMISSION_ERROR );
1817 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
;
1818 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1821 size_t i2
= 0; /* We know there's a slash at the first position */
1822 i2
= dirname
.find( '/', i2
+ 1 );
1824 while( stat( dirname
.substr( 0, i2
).c_str( ), & theStat
) == 0 )
1827 i2
= dirname
.find( '/', i2
+ 1 );
1831 std::cerr
<< "Shapes will not create directories for temporary files at the root: " << dirname
<< std::endl
;
1832 exit( Interaction::EXIT_INVOCATION_ERROR
);
1835 mode_t oldUmask
= umask( 0 ); /* We want to be able to create directories with any permissions. */
1836 while( i2
!= std::string::npos
)
1838 if( mkdir( dirname
.substr( 0, i2
).c_str( ), theStat
.st_mode
& ( S_IRWXU
| S_IRWXG
| S_IRWXO
) ) != 0 )
1840 std::cerr
<< "Failed to create directory for temporary files (errno=" << errno
<< "): " << dirname
.substr( 0, i2
) << std::endl
;
1841 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1843 i2
= dirname
.find( '/', i2
+ 1 );
1849 escapeExtGlobChars( const std::string
& str
, std::ostream
& dst
)
1851 const char * special
= "*?[+@!";
1852 for( std::string::const_iterator i
= str
.begin( ); i
!= str
.end( ); ++i
)
1854 if( strchr( special
, *i
) != 0 )
1863 rmSplitFiles( const std::string
& outputName
, const char * sep
)
1865 std::ostringstream rmCommand
;
1866 rmCommand
<< "sh -O extglob -c 'rm -f " ;
1867 escapeExtGlobChars( outputName
, rmCommand
);
1868 rmCommand
<< sep
<< "+([0-9]).pdf'" ;
1869 Interaction::systemDebugMessage( rmCommand
.str( ) );
1870 if( system( rmCommand
.str( ).c_str( ) ) != 0 )
1872 /* Never mind; we made a try, and this probably means that there were no files to remove. */
1877 mkSplitDir( const std::string
& outputName
)
1879 struct stat theStat
;
1880 if( stat( outputName
.c_str( ), & theStat
) == 0 )
1882 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1884 std::cerr
<< "The path " << outputName
<< " was expected to reference a directory." << std::endl
;
1885 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1890 if( mkdir( outputName
.c_str( ), S_IRWXU
| S_IRWXG
| S_IRWXO
) != 0 )
1892 std::cerr
<< "Failed to create directory for split document files (errno=" << errno
<< "): " << outputName
<< std::endl
;
1893 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1899 noSplitOpen( std::ofstream
* oFile
, const std::string
& outputName
)
1901 oFile
->open( outputName
.c_str( ) );
1902 if( ! oFile
->good( ) )
1904 /* If this is because the output directory does not exist, we shall inform the user about this. */
1905 std::string::size_type slash
= outputName
.rfind( '/' );
1906 if( slash
!= std::string::npos
)
1908 std::string outputDir
= outputName
.substr( 0, slash
);
1909 struct stat theStat
;
1910 if( stat( outputDir
.c_str( ), & theStat
) == 0 )
1912 if( ( theStat
.st_mode
& S_IFDIR
) == 0 )
1914 std::cerr
<< "The prefix " << outputDir
<< " of the output name must be a directory." << std::endl
;
1915 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1917 /* In case we reach here, the directory exists, so we fall back on the generic error message below. */
1921 std::cerr
<< "The file " << outputName
<< " cannot be opened for output since the directory " << outputDir
<< " does not exist." << std::endl
;
1922 exit( Interaction::EXIT_NO_DIRECTORY_ERROR
);
1925 std::cerr
<< "Failed to open " << outputName
<< " for output." << std::endl
;
1926 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1931 splitOpen( std::ofstream
* oFile
, const std::string outputName
, const char * sep
, size_t physicalPageNo
)
1933 std::ostringstream oss
;
1934 oss
<< outputName
<< sep
<< physicalPageNo
<< ".pdf" ;
1935 std::string
filename( oss
.str( ) );
1936 oFile
->open( filename
.c_str( ) );
1937 if( ! oFile
->good( ) )
1939 std::cerr
<< "Failed to open " << filename
<< " for output." << std::endl
;
1940 exit( Interaction::EXIT_OUTPUT_FILE_ERROR
);
1948 std::string
ind(" ");
1950 << "Usage:" << std::endl
1951 << ind
<< "shapes [OPTIONS] file[.[shape]]" << std::endl
1952 << "A subset of options is listed below, by cathegory. This message is just" << std::endl
1953 << "a reminder; legal option values are only listed in rare cases." << std::endl
1954 << "Files: --in --out --outdir --texjob --tmpdir --tmp*= --labeldb" << std::endl
1955 << "Paths: --needpath -N --fontmetricspath --resources=" << std::endl
1956 << "Multipage: --split=('no'|'flat'|'dir')" << std::endl
1957 << "PDF: (--pdf-version=|-v)(e|w|s)1.N --tp= --spot-pair=" << std::endl
1958 << "Tolerances: --arcdelta= --dtmin= --dtminerror= --splicingtol= --overlaptol=" << std::endl
1959 << "Log file: --debuglog --debuglog-stderr --debuglog-stdout" << std::endl
1960 << "Help: --help --which-doc --showfiles= --which --version" << std::endl
1961 << "Viewing: --xpdf --open --open-a" << std::endl
1962 << "Interactive: --interactive -i" << std::endl
1963 << "See the man page for a complete listing and details." << std::endl