aboutsummaryrefslogtreecommitdiffstats
path: root/fileprinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fileprinter.cpp')
-rw-r--r--fileprinter.cpp684
1 files changed, 684 insertions, 0 deletions
diff --git a/fileprinter.cpp b/fileprinter.cpp
new file mode 100644
index 0000000..96d2a15
--- /dev/null
+++ b/fileprinter.cpp
@@ -0,0 +1,684 @@
+// fileprinter.cpp
+// Revision 9-jan-2005
+
+#include "file.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "sysvar.h"
+#include "showerror.h"
+
+#include "trace.h"
+
+// para strerror (errno)
+//#include <string.h>
+//#include <errno.h>
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <memory>
+using std::auto_ptr;
+
+#include <cassert>
+#define ASSERT assert
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <windows.h>
+#undef min
+#undef max
+
+#else
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#endif
+
+//***********************************************
+// Auxiliary functions
+//***********************************************
+
+namespace {
+
+#ifdef BLASSIC_USE_WINDOWS
+
+class GuardCharp {
+public:
+ GuardCharp (char * pc) :
+ pc (pc)
+ { }
+ ~GuardCharp ()
+ {
+ delete [] pc;
+ }
+private:
+ char * pc;
+};
+
+class GuardHMODULE {
+public:
+ GuardHMODULE (HMODULE h) :
+ h (h)
+ { }
+ ~GuardHMODULE ()
+ {
+ FreeLibrary (h);
+ }
+private:
+ HMODULE h;
+};
+
+class GuardHPRINTER {
+public:
+ GuardHPRINTER (HANDLE h) :
+ h (h)
+ { }
+ ~GuardHPRINTER ()
+ {
+ ClosePrinter (h);
+ }
+private:
+ HANDLE h;
+};
+
+std::string getdefaultprinter ()
+{
+ // This routine is based in several founded on the web,
+ // correcting several errors and adapted to C++.
+ OSVERSIONINFO osv;
+ osv.dwOSVersionInfoSize= sizeof (OSVERSIONINFO);
+ GetVersionEx (& osv);
+ switch (osv.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ // Windows 95 or 98, use EnumPrinters
+ {
+ SetLastError (0);
+ DWORD dwNeeded= 0, dwReturned= 0;
+ EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 2,
+ NULL, 0, & dwNeeded, & dwReturned);
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER ||
+ dwNeeded == 0)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "EnumPrinters get buffer "
+ "failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal; // Provisional
+ }
+ char * aux= new char [dwNeeded];
+ GuardCharp guardcharp (aux);
+ PRINTER_INFO_2 * ppi2=
+ reinterpret_cast <PRINTER_INFO_2 *> (aux);
+ if (! EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 2,
+ (LPBYTE) ppi2, dwNeeded,
+ &dwNeeded, & dwReturned) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "EnumPrinters failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal; // Provisional
+ }
+ return ppi2->pPrinterName;
+ }
+ case VER_PLATFORM_WIN32_NT:
+ if (osv.dwMajorVersion >= 5) // Windows 2000 or later
+ {
+ HMODULE hWinSpool= LoadLibrary ("winspool.drv");
+ if (! hWinSpool)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "LoadLibrary failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ GuardHMODULE guardh (hWinSpool);
+ #ifdef UNICODE
+ static const TCHAR GETDEFAULTPRINTER []=
+ "GetDefaultPrinterW";
+ #else
+ static const TCHAR GETDEFAULTPRINTER []=
+ "GetDefaultPrinterA";
+ #endif
+ PROC fnGetDefaultPrinter= GetProcAddress (hWinSpool,
+ GETDEFAULTPRINTER);
+ if (! fnGetDefaultPrinter)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetProcAddress failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ typedef BOOL (* GetDefaultPrinter_t) (LPTSTR, LPDWORD);
+ GetDefaultPrinter_t callGetDefaultPrinter=
+ (GetDefaultPrinter_t) fnGetDefaultPrinter;
+ DWORD dwBufferLength= 0;
+ SetLastError (0);
+ callGetDefaultPrinter (NULL, & dwBufferLength);
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetDefaultPrinter get buffer "
+ "failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ char * buffer= new char [dwBufferLength];
+ GuardCharp guardcharp (buffer);
+ if (! callGetDefaultPrinter
+ (buffer, & dwBufferLength) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetDefaultPrinter failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ return std::string (buffer);
+ }
+ else // NT 4.0 or earlier
+ {
+ const DWORD MAXBUFFERSIZE= 250;
+ TCHAR cBuffer [MAXBUFFERSIZE];
+ if (GetProfileString ("windows", "device", ",,,",
+ cBuffer, MAXBUFFERSIZE) <= 0)
+ {
+ if (showdebuginfo () )
+ cerr << "GetProfileString failed" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ strtok (cBuffer, ",");
+ return std::string (cBuffer);
+ }
+ default:
+ ASSERT (false);
+ return std::string (); // Make the compiler happy.
+ }
+}
+
+#else
+
+class GuardHandle {
+public:
+ GuardHandle (int handle) :
+ handle (handle)
+ {
+ TRACEFUNC (tr, "GuardHandle::GuardHandle");
+
+ if (handle == -1)
+ {
+ if (showdebuginfo () )
+ cerr << "GuardHandle with invalid handle" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ }
+ ~GuardHandle ()
+ {
+ do_close (true);
+ }
+ void close ()
+ {
+ do_close (false);
+ }
+private:
+ void do_close (bool destructing)
+ {
+ TRACEFUNC (tr, "GuardHandle::do_close");
+
+ if (handle != CLOSED)
+ {
+ int aux= handle;
+ handle= CLOSED;
+ if (::close (aux) != 0)
+ {
+ // Problem: this message can be lost because
+ // stdeerr may be redirected to null when
+ // using this.
+
+ #if 0
+ const char * message= strerror (errno);
+ TRMESSAGE (tr, message);
+ if (showdebuginfo () )
+ cerr << "Error closing handle: " <<
+ message << endl;
+ #else
+
+ showlasterror ("Error closing handle");
+
+ #endif
+
+ if (! destructing)
+ throw ErrBlassicInternal;
+ }
+ }
+ }
+
+ static const int CLOSED= -1;
+ int handle;
+};
+
+class Dup2Save {
+ // Checks are not done because the functions can fail
+ // if Blassic is running in detached mode.
+ // More work required to make checks that works in
+ // all cases.
+public:
+ Dup2Save (int newhandle, int oldhandle) :
+ oldhandle (oldhandle)
+ {
+ savedhandle= dup (oldhandle);
+ dup2 (newhandle, oldhandle);
+ }
+ ~Dup2Save ()
+ {
+ release ();
+ }
+ void release ()
+ {
+ if (savedhandle != RELEASED)
+ {
+ dup2 (savedhandle, oldhandle);
+ close (savedhandle);
+ savedhandle= RELEASED;
+ }
+ }
+private:
+ static const int RELEASED= -1;
+ int oldhandle;
+ int savedhandle;
+};
+
+#endif
+
+} // namespace
+
+namespace blassic {
+
+namespace file {
+
+class BlFilePrinter : public BlFile {
+public:
+ BlFilePrinter ();
+ ~BlFilePrinter ();
+ bool isfile () const { return false; }
+ void flush ();
+ size_t getwidth () const;
+ void tab ();
+ void tab (size_t n);
+ void endline ();
+ void setwidth (size_t w);
+ void setmargin (size_t m);
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ class Internal;
+ Internal * pin;
+};
+
+//***********************************************
+// BlFilePrinter::Internal
+//***********************************************
+
+class BlFilePrinter::Internal {
+public:
+ Internal () :
+ pos (0),
+ width (80),
+ margin (0)
+ { }
+ ~Internal ();
+ void close ();
+ size_t getwidth () const { return width; }
+ void checkmargin ();
+ void tab ();
+ void tab (size_t n);
+ void endline ();
+ void outstring (std::string str);
+ void outchar (char c);
+ void setwidth (size_t w)
+ { width= w; }
+ void setmargin (size_t m)
+ { margin= m - 1; }
+private:
+ void do_printing (const char * printcommand);
+
+ std::string text;
+ size_t pos;
+ size_t width;
+ size_t margin;
+};
+
+BlFilePrinter::Internal::~Internal ()
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::~Internal");
+
+ try
+ {
+ close ();
+ }
+ catch (...)
+ {
+ if (showdebuginfo () )
+ cerr << "Error closing printer buffer" << endl;
+ }
+}
+
+void BlFilePrinter::Internal::close ()
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::close");
+
+ static const char blassic_print_command []= "BLASSIC_PRINT_COMMAND";
+
+ // Print only if there is somethnig to print.
+ if (text.empty () )
+ {
+ TRMESSAGE (tr, "Nothing to print.");
+ return;
+ }
+ TRMESSAGE (tr, "Begin printing");
+
+ const char * printcommand= getenv (blassic_print_command);
+ do_printing (printcommand);
+}
+
+
+
+#ifdef BLASSIC_USE_WINDOWS
+
+void BlFilePrinter::Internal::do_printing (const char * printcommand)
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::do_printing");
+
+ if (printcommand != NULL)
+ {
+ TRMESSAGE (tr, std::string ("Popening to ") + printcommand);
+ //BlFilePopen bfp (printcommand, Output);
+ //bfp << text;
+ auto_ptr <BlFile> pbfp (newBlFilePopen (printcommand, Output) );
+ * pbfp << text;
+ return;
+ }
+
+ std::string printername= getdefaultprinter ();
+ TRMESSAGE (tr, std::string ("Printer is ") + printername);
+
+ HANDLE hPrinter;
+ if (! OpenPrinter ( (char *) printername.c_str (), & hPrinter, NULL) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "OpenPrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ GuardHPRINTER guardhprinter (hPrinter);
+ DOC_INFO_1 doc_info;
+ doc_info.pDocName= (char *) "Blassic printing output";
+ doc_info.pOutputFile= NULL;
+ doc_info.pDatatype= NULL;
+ DWORD jobid= StartDocPrinter (hPrinter, 1, (LPBYTE) & doc_info);
+ if (jobid == 0)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "StartDocPrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ DWORD written= 0;
+ WritePrinter (hPrinter, (void *) text.data (), text.size (),
+ & written);
+ if (written != text.size () )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "WritePrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ EndDocPrinter (hPrinter);
+ // ClosePrinter is done by the guard.
+}
+
+#else
+
+void BlFilePrinter::Internal::do_printing (const char * printcommand)
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::do_printing");
+
+ if (printcommand == NULL)
+ printcommand= "lp";
+
+ FILE * f;
+
+ // Block opened to automatically restore
+ // saved handles when closing it.
+ {
+ // Redirect standard handles not used to /dev/null
+ int newstd= open ("/dev/null", O_RDWR);
+ if (newstd == -1)
+ {
+ #if 0
+ if (showdebuginfo () )
+ cerr << "open /dev/null failed: " <<
+ strerror (errno) << endl;
+ #else
+
+ showlasterror ("open /dev/null failed");
+
+ #endif
+
+ throw ErrFunctionCall;
+ }
+
+ // Save standard handles not used
+ #if 0
+ int savestdout= dup (STDOUT_FILENO);
+ int savestderr= dup (STDERR_FILENO);
+
+ dup2 (newstd, STDOUT_FILENO);
+ dup2 (newstd, STDERR_FILENO);
+ ::close (newstd);
+ #else
+ GuardHandle guardnew (newstd);
+ Dup2Save saveout (newstd, STDOUT_FILENO);
+ Dup2Save saveerr (newstd, STDERR_FILENO);
+ guardnew.close ();
+ #endif
+
+ f= popen (printcommand, "w");
+
+ #if 0
+ // Restore saved standard handles
+ dup2 (savestdout, STDOUT_FILENO);
+ dup2 (savestderr, STDERR_FILENO);
+ ::close (savestdout);
+ ::close (savestderr);
+ #endif
+ }
+
+ if (f == NULL)
+ {
+ if (showdebuginfo () )
+ cerr << "Error in popen print command" << endl;
+ throw ErrBlassicInternal;
+ }
+ size_t size= text.size ();
+ size_t written= write (fileno (f), text.data (), size);
+ if (written != size)
+ showlasterror ("Error writing to print command");
+ pclose (f);
+}
+
+#endif
+
+void BlFilePrinter::Internal::checkmargin ()
+{
+ if (pos == 0)
+ text+= std::string (margin, ' ');
+}
+
+void BlFilePrinter::Internal::tab ()
+{
+ size_t zone= sysvar::get16 (sysvar::Zone);
+ if (zone == 0)
+ {
+ outchar ('\t');
+ return;
+ }
+ if (width > 0 && pos >= (width / zone) * zone)
+ endline ();
+ else
+ {
+ do
+ {
+ outchar (' ');
+ } while (pos % zone);
+ }
+}
+
+void BlFilePrinter::Internal::tab (size_t n)
+{
+ if (pos > n)
+ endline ();
+ size_t maxpos= std::min (width, n);
+ while (pos < maxpos)
+ outchar (' ');
+}
+
+void BlFilePrinter::Internal::endline ()
+{
+ switch (sysvar::get (sysvar::PrinterLine) )
+ {
+ case 0:
+ text+= '\n'; break;
+ case 1:
+ text+= "\r\n"; break;
+ case 2:
+ text+= '\r'; break;
+ }
+ pos= 0;
+}
+
+void BlFilePrinter::Internal::outstring (std::string str)
+{
+ if (width > 0)
+ {
+ size_t l= str.size ();
+ while (pos + l > width)
+ {
+ checkmargin ();
+ text+= str.substr (0, width - pos);
+ str.erase (0, width - pos);
+ endline ();
+ l= str.size ();
+ }
+ }
+ checkmargin ();
+ text+= str;
+ pos+= str.size ();
+}
+
+void BlFilePrinter::Internal::outchar (char c)
+{
+ if (width > 0 && pos>= width)
+ endline ();
+ checkmargin ();
+ text+= c;
+ ++pos;
+}
+
+//***********************************************
+// BlFilePrinter
+//***********************************************
+
+BlFile * newBlFilePrinter ()
+{
+ return new BlFilePrinter;
+}
+
+BlFilePrinter::BlFilePrinter () :
+ BlFile (Output),
+ pin (new Internal)
+{ }
+
+BlFilePrinter::~BlFilePrinter ()
+{
+ delete pin;
+}
+
+void BlFilePrinter::flush ()
+{
+}
+
+size_t BlFilePrinter::getwidth () const
+{
+ return pin->getwidth ();
+}
+
+void BlFilePrinter::tab ()
+{
+ pin->tab ();
+}
+
+void BlFilePrinter::tab (size_t n)
+{
+ pin->tab (n);
+}
+
+void BlFilePrinter::endline ()
+{
+ pin->endline ();
+}
+
+void BlFilePrinter::outstring (const std::string & str)
+{
+ pin->outstring (str);
+}
+
+void BlFilePrinter::outchar (char c)
+{
+ pin->outchar (c);
+}
+
+void BlFilePrinter::setwidth (size_t w)
+{
+ pin->setwidth (w);
+}
+
+void BlFilePrinter::setmargin (size_t m)
+{
+ pin->setmargin (m);
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of fileprinter.cpp
Un proyecto texto-plano.xyz