/* pstoedit.cc : This file is part of pstoedit main program Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #if !defined(unix) && !defined(__unix__) && !defined(__unix) #include #else #include #endif #include #include #include #include "version.h" #include CONFIGFILE #ifdef WITHTGIF #include "drvtgif.h" #endif #ifdef WITHMIF #include "drvmif.h" #endif #ifdef WITHFIG #include "drvfig.h" #endif #ifdef WITHGNUPLOT #include "drvgnplt.h" #endif #ifdef WITHDXF #include "drvdxf.h" #endif #if defined (WITHMET) && defined(__OS2__) #include #include "drvMET.h" #endif #ifdef WITHPDF #include "drvpdf.h" #endif #ifdef WITHCGM #include "drvcgm.h" #endif // next include only for verifying that drvsampl is kept up to date #ifdef WITHSAMPLE #include "drvsampl.h" #endif #ifndef USEPROLOGFROMFILE #include "pstoedit.ph" #endif void usage() { cerr << "usage: pstoedit [-help] [-dt] [-merge] [-s nn] [-dis] [-flat nn] [-bo] -f format [infile [outfile]]" << endl; } // cannot make this static, because it's used in a template, that might be // stored in a repository (separate .o file) int checkNextArgument(int argc, char ** argv, int arg) { // if there is no next arg, usage is printed and // the program is terminated if ((arg+1>= argc ) || (argv[arg+1] == 0)) { cerr << "missing value for option " << argv[arg] << endl; usage(); exit(1); } return 1; } // made non template, because some compilers (cfront) have // problems with instantiating this // template // void getvalue(int argc, char ** argv, int arg, T & value) void getvalue(int argc, char ** argv, int arg, float & value) { // get value for option arg (value is next argument) if (checkNextArgument(argc,argv,arg)) { istrstream strvalue(argv[arg+1]); strvalue >> value; } } void copy_file(istream& infile,ostream& outfile) { outfile << infile.rdbuf(); } static int grep(const char * const matchstring, const char * const filename) { // for call: gsresult = grep("% normal end reached by pstoedit.pro",gsout); ifstream inFile; inFile.open(filename); if (inFile.fail() ) { cerr << "Could not open file " << filename << " in grep" << endl; return 1; // fail } else { const unsigned int matchlen = strlen(matchstring) ; const unsigned int bufferlen = matchlen + 1; // allocate buffer for reading begin of lines char * buffer = new char[bufferlen]; while (inFile.get(buffer,bufferlen,'\n'), !inFile.eof() ) { // cerr << " read in grep :" << buffer << endl; if ((inFile.gcount() == matchlen) && (strcmp(buffer,matchstring) == 0) ) { delete [] buffer; return 0; } if ( inFile.peek() == '\n' ) inFile.ignore(); } delete [] buffer; } return 1; // fail } enum driverType { unknown, tgif, mif, fig, cgm, cgmt, pdf, gnuplot, ps, debug, met, wmf, dxf, sample }; struct driverdescription_T { driverdescription_T(const char * s_name, const char * expl, driverType code): symbolicname(s_name), explanation(expl), internalcode(code) {} const char * const symbolicname; const char * const explanation; const driverType internalcode; }; static const driverdescription_T driverdescription [] = { #ifdef WITHTGIF driverdescription_T("tgif","Tgif .obj format (for tgif version >= 3)",tgif), #endif #ifdef WITHMIF driverdescription_T("mif","(Frame)Maker Intermediate Format",mif), #endif #ifdef WITHFIG driverdescription_T("fig",".fig format for xfig",fig), #endif #ifdef WITHPDF driverdescription_T("pdf","Adobe's Portable Document Format",pdf), #endif #ifdef WITHGNUPLOT driverdescription_T("gnuplot","gnuplot format",pdf), #endif driverdescription_T("ps","Flattened PostScript",ps), driverdescription_T("debug","for test purposes ",debug), driverdescription_T("dump","for test purposes (same as debug)",debug), #if defined (WITHMET) && defined(__OS2__) driverdescription_T("met","OS/2 meta files",met), #endif #ifdef NOTYET driverdescription_T("wmf","Windows meta files",wmf), #endif #ifdef WITHDXF driverdescription_T("dxf","CAD exchange format",dxf), #endif #ifdef WITHCGM driverdescription_T("cgm","CGM Format (binary)",cgm), driverdescription_T("cgmt","CGM Format (textual)",cgmt), #endif #ifdef WITHSAMPLE driverdescription_T("sample","insert your new format here ",sample) #endif }; driverType getdrivertype(const char * drivername) { const unsigned int nrOfFormats = sizeof(driverdescription) / sizeof(driverdescription_T); for (unsigned int i = 0; i < nrOfFormats; i++ ) { if ( strcmp(drivername,driverdescription[i].symbolicname) == 0 ) { return driverdescription[i].internalcode ; } } return unknown; } static void explainformats(ostream & out) { const unsigned int nrOfFormats = sizeof(driverdescription) / sizeof(driverdescription_T); out << "Available formats :\n"; for (unsigned int i = 0; i < nrOfFormats; i++ ) { out << driverdescription[i].symbolicname << ":\t" ; if (strlen(driverdescription[i].symbolicname) <7) { out << '\t'; } out << driverdescription[i].explanation << endl; } } #if !defined(unix) && !defined(__unix__) && !defined(__unix) void convertBackSlashes(const char* string) { char* c; while ((c = strchr(string,'\\')) != NULL) *c = '/'; } #endif int main(int argc, char **argv) { const char *nameOfInputFile = 0; const char *nameOfOutputFile = 0; bool withdisplay = false; bool merge = false; bool drawtext = false; bool escapetext = false; // only for PostScript backend bool usepdfmark = false; // only for PDF backend float flatness = 1.0; // used for setflat // in combination with -dt char *drivername = 0; float magnification = 1.0; bool backendonly = false; // used for easier debugging of backends // directly read input file by backend // bypass ghostscript. The input file // is assumed to be produced by a // previous call with -f debug cerr << "pstoedit: version " << version << " : Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz\n" ; int arg = 1; while (arg < argc) { if ( argv[arg][0] == '-' ) { // it is an option if (strncmp(argv[arg],"-s",2) == 0) { getvalue(argc,argv,arg,magnification); arg++; } else if (strncmp(argv[arg],"-help",2) == 0) { usage(); explainformats(cerr); return 1; } else if (strncmp(argv[arg],"-flat",3) == 0) { getvalue(argc,argv,arg,flatness); arg++; } else if (strncmp(argv[arg],"-bo",3) == 0) { backendonly = true; } else if (strncmp(argv[arg],"-merge",6) == 0) { merge = true; } else if (strncmp(argv[arg],"-dt",3) == 0) { drawtext = true; } else if (strncmp(argv[arg],"-dis",4) == 0) { withdisplay = true; } else if (strcmp(argv[arg],"-f") == 0) { if (checkNextArgument(argc,argv,arg)) { drivername = argv[arg+1]; arg++; } } else { cerr << "unknown option " << argv[arg] << endl; usage(); return 1; } } else { if (nameOfInputFile == 0) { nameOfInputFile = argv[arg]; } else if (nameOfOutputFile == 0) { nameOfOutputFile = argv[arg]; } else { cerr << "more than two file arguments " << endl; usage(); return 1; } } // cerr << "argv[" << arg << "] = " << argv[arg] << endl; arg++; } if (drivername == 0) { cerr << "No backend specified" << endl; usage(); return 1; } else { char * driveroptions = strchr(drivername,':'); if (driveroptions) { *driveroptions = '\0'; // replace : with 0 to separate drivername driveroptions++; } driverType currentDriver = getdrivertype(drivername); if (currentDriver == unknown) { cerr << "unsupported driver " << drivername << endl; explainformats(cerr); return 1; } else { //istream *inputFilePtr = 0; const char * const stdinFileName = "%stdin"; // for PostScript if (nameOfInputFile) { // an input file was given as argument ifstream inFile; // just test whether InputFile is readable. // The file will be read directly from the PostScrip // interpreter later on #if !defined(unix) && !defined(__unix__) && !defined(__unix) convertBackSlashes(nameOfInputFile); #endif inFile.open(nameOfInputFile); if (inFile.fail() ) { cerr << "Could not open file " << nameOfInputFile << " for input" << endl; return 1; } inFile.close(); //inputFilePtr = &inFile; } else { //inputFilePtr = &cin; nameOfInputFile = stdinFileName; } ostream *outputFilePtr = 0; ofstream outFile; if (nameOfOutputFile) { #if !defined(unix) && !defined(__unix__) && !defined(__unix) // binary is not available on UNIX if (currentDriver == cgm) { outFile.open(nameOfOutputFile,ios::binary); } else #endif { outFile.open(nameOfOutputFile); } if (outFile.fail() ) { cerr << "Could not open file " << nameOfOutputFile << " for output" << endl; return 1; } outputFilePtr = &outFile; } else { outputFilePtr = &cout; } drvbase * outputdriver = 0; switch (currentDriver) { #ifdef WITHCGM case cgm: outputdriver = new drvCGM(*outputFilePtr,1); break; case cgmt: outputdriver = new drvCGM(*outputFilePtr,0); break; #endif #ifdef WITHDXF case dxf: outputdriver = new drvDXF(*outputFilePtr); break; #endif case debug: // no driver needed for debug/dump output usepdfmark = true; break; #ifdef WITHGNUPLOT case gnuplot: outputdriver = new drvGNUPLOT(*outputFilePtr); #endif #ifdef WITHFIG case fig: outputdriver = new drvFIG(*outputFilePtr); break; #endif #ifdef WITHSAMPLE case sample: outputdriver = new drvSAMPL(*outputFilePtr); break; #endif #ifdef WITHMIF case mif: outputdriver = new drvMIF(*outputFilePtr); break; #endif #if defined (WITHMET) && defined(__OS2__) case met: // driver specific options are appended to the drivers name // e.g. -f met:wp // The backend is responsible for parsing the additional option string outFile.close(); pDrvMETsetup = new DRVMETSETUP(driveroptions); if (pDrvMETsetup->exit) { delete pDrvMETsetup; return 0; } if (!nameOfOutputFile) { nameOfOutputFile = "stdout.met"; } pDrvMETsetup->pMetaFileName = new char[strlen(nameOfOutputFile)+1]; strcpy(pDrvMETsetup->pMetaFileName,nameOfOutputFile); break; #endif #ifdef WITHPDF case pdf: outputdriver = new drvPDF(*outputFilePtr); usepdfmark = true; break; #endif case ps: escapetext = true; break; #ifdef WITHTGIF case tgif: outputdriver = new drvTGIF(*outputFilePtr,magnification); break; #endif default: cerr << "unsupported driver " << drivername << endl; explainformats(cerr); return 1; // unreachable break; } char gsoutName[L_tmpnam]; const char * gsout; int gsresult = 0; if (backendonly) { gsout = nameOfInputFile; gsresult = 0; // gs was skipped, so there is no problem } else { char gsin[L_tmpnam]; tmpnam(gsin); ofstream inFileStream(gsin); if (drawtext) { inFileStream << "/textastext false def" << endl; inFileStream << "/flatnesstouse " << flatness << " def" << endl; } if (escapetext) { inFileStream << "/escapetext true def" << endl; } if (usepdfmark) { inFileStream << "/usepdfmark true def" << endl; } gsout = tmpnam(gsoutName); inFileStream << "/outputfilename (" << gsout <<") def" << endl; inFileStream << "/inputfilename (" << nameOfInputFile <<") def" << endl; if (outputdriver && outputdriver->backendSupportsCurveto ) { inFileStream << "/doflatten false def" << endl; } #ifdef USEPROLOGFROMFILE ifstream prologue("pstoedit.pro"); // cerr << " copying prologue file to " << gsin << endl; copy_file(prologue,inFileStream); #else const char * * prologueline = PS_prologue; while (prologueline && *prologueline ) { inFileStream << *prologueline << '\n'; prologueline++; } #endif inFileStream.close(); // now call ghostscript char commandline[1000]; // TODO check for overflow commandline[0]= '\0'; #ifdef DEFAULTGS #define str(x) #x #define xstr(x) str(x) const char * const defaultgs = xstr(DEFAULTGS); // cerr << "Default interpreter is " << defaultgs << endl; #else const char * const defaultgs = ""; #endif const char * gstocall; if ( (gstocall = getenv("GS")) == 0 ) { // env var GS not set, so try default if ( strlen(defaultgs) > 0 ) { gstocall = defaultgs; } else { cerr << "Fatal: don't know which interpreter to call. " << "Either setenv GS or compile again with -DDEFAULTGS=..." << endl; exit(1); } } strcat(commandline,gstocall); strcat(commandline," -q "); if (usepdfmark) { // for overloading pdfmark, we need write access to systemdict strcat(commandline,"-dWRITESYSTEMDICT "); } if (!withdisplay) strcat(commandline,"-dNODISPLAY "); strcat(commandline,gsin); strcat(commandline," quit.ps "); cerr << "now calling the interpreter via: " << commandline << endl; gsresult = system(commandline); cerr << "Interpreter finished. Return status " << gsresult << endl; // ghostscript seems to return always 0, so // check whether the normal end was reached by pstoedit.pro remove(gsin); // if really returned !0 don't grep if (!gsresult) gsresult = grep("% normal end reached by pstoedit.pro",gsout); } if (gsresult != 0) { cerr << "The interpreter seems to have failed, cannot proceed !" << endl; remove(gsout); return 1; } else { if ((currentDriver != debug) && (currentDriver != ps )) { extern FILE * yyin; // used by lexer if ( backendonly && (nameOfInputFile == stdinFileName) ) { yyin = stdin; } else { yyin = fopen(gsout,"r"); if (!yyin) { cerr << "Error opening file " << gsout << endl; return 1; } } // cerr << "now postprocessing the interpreter output" << endl; if (currentDriver != met) { outputdriver->run(merge); delete outputdriver; } #if defined (WITHMET) && defined(__OS2__) else { // driver is met OS2WIN os2win; os2win.run(); delete pDrvMETsetup->pMetaFileName; delete pDrvMETsetup; } #endif // cerr << "done " << endl; if ( !( backendonly && (nameOfInputFile == stdinFileName) ) ) { fclose(yyin); } } else { // Debug or PostScript driver ifstream gsoutStream(gsout); // cerr << "now copying " << gsout << " to output " << endl; copy_file(gsoutStream,*outputFilePtr); // cerr << " done \n"; } if ( !backendonly ) { remove(gsout); } } } } return 0; }