1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* %printer% IODevice */
18 
19 #define INCL_DOS
20 #define INCL_SPL
21 #define INCL_SPLDOSPRINT
22 #define INCL_SPLERRORS
23 #define INCL_BASE
24 #define INCL_ERRORS
25 #define INCL_WIN
26 #include <os2.h>
27 
28 #include "errno_.h"
29 #include "stdio_.h"
30 #include "string_.h"
31 #include "gp.h"
32 #include "gscdefs.h"
33 #include "gserrors.h"
34 #include "gstypes.h"
35 #include "gsmemory.h"		/* for gxiodev.h */
36 #include "gxiodev.h"
37 
38 /* The OS/2 printer IODevice */
39 
40 /*
41  * This allows an OS/2 printer to be specified as an
42  * output using
43  *  -sOutputFile="%printer%AppleLas"
44  * where "AppleLas" is the physical name of the queue.
45  *
46  * If you don't supply a printer name you will get
47  *  Error: /undefinedfilename in --.outputpage--
48  * If the printer name is invalid you will get
49  *  Error: /invalidfileaccess in --.outputpage--
50  *
51  * This is implemented by writing to a temporary file
52  * then copying it to the spooler.
53  *
54  * A better method would be to return a file pointer
55  * to the write end of a pipe, and starting a thread
56  * which reads the pipe and writes to an OS/2 printer.
57  * This method didn't work properly on the second
58  * thread within ghostscript.
59  */
60 
61 static iodev_proc_init(os2_printer_init);
62 static iodev_proc_finit(os2_printer_finit);
63 static iodev_proc_fopen(os2_printer_fopen);
64 static iodev_proc_fclose(os2_printer_fclose);
65 const gx_io_device gs_iodev_printer = {
66     "%printer%", "FileSystem",
67     {os2_printer_init, os2_printer_finit, iodev_no_open_device,
68      NULL /*iodev_os_open_file */ , os2_printer_fopen, os2_printer_fclose,
69      iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status,
70      iodev_no_enumerate_files, NULL, NULL,
71      iodev_no_get_params, iodev_no_put_params
72     },
73     NULL,
74     NULL
75 };
76 
77 typedef struct os2_printer_s {
78     char queue[gp_file_name_sizeof];
79     char filename[gp_file_name_sizeof];
80     const gs_memory_t *memory;
81 } os2_printer_t;
82 
83 /* The file device procedures */
84 static int
os2_printer_init(gx_io_device * iodev,gs_memory_t * mem)85 os2_printer_init(gx_io_device * iodev, gs_memory_t * mem)
86 {
87     /* state -> structure containing thread handle */
88     iodev->state = gs_alloc_bytes(mem, sizeof(os2_printer_t),
89         "os2_printer_init");
90     if (iodev->state == NULL)
91         return_error(gs_error_VMerror);
92     memset(iodev->state, 0, sizeof(os2_printer_t));
93     iodev->state->memory = mem;
94     return 0;
95 }
96 
97 static void
os2_printer_finit(gx_io_device * iodev,gs_memory_t * mem)98 os2_printer_finit(gx_io_device * iodev, gs_memory_t * mem)
99 {
100     gs_free_object(mem, iodev->state, "os2_printer_finit");
101     iodev->state = NULL;
102     return;
103 }
104 
105 static int
os2_printer_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)106 os2_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
107            FILE ** pfile, char *rfname, uint rnamelen)
108 {
109     os2_printer_t *pr = (os2_printer_t *)iodev->state;
110     char driver_name[256];
111     gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
112     gs_fs_list_t *fs = ctx->core->fs;
113 
114     /* First we try the open_printer method. */
115     /* Note that the loop condition here ensures we don't
116      * trigger on the last registered fs entry (out standard
117      * file one). */
118     *pfile = NULL;
119     for (fs = ctx->core->fs; fs != NULL && fs->next != NULL; fs = fs->next)
120     {
121         int code = 0;
122         if (fs->fs.open_printer)
123             code = fs->fs.open_printer(mem, fs->secret, fname, access, pfile);
124         if (code < 0)
125             return code;
126         if (*pfile != NULL)
127             return code;
128     }
129 
130     /* If nothing claimed that, then continue with the
131      * standard OS/2 way of working. */
132 
133     /* Make sure that printer exists. */
134     if (pm_find_queue(pr->memory, fname, driver_name)) {
135         /* error, list valid queue names */
136         emprintf(pr->memory, "Invalid queue name.  Use one of:\n");
137         pm_find_queue(pr->memory, NULL, NULL);
138         return_error(gs_error_undefinedfilename);
139     }
140 
141     strncpy(pr->queue, fname, sizeof(pr->queue)-1);
142 
143     /* Create a temporary file */
144     *pfile = gp_open_scratch_file_impl(pr->memory, "gs", pr->filename, access, 0);
145     if (*pfile == NULL)
146         return_error(gs_fopen_errno_to_code(errno));
147 
148     return 0;
149 }
150 
151 static int
os2_printer_fclose(gx_io_device * iodev,FILE * file)152 os2_printer_fclose(gx_io_device * iodev, FILE * file)
153 {
154     os2_printer_t *pr = (os2_printer_t *)iodev->state;
155     fclose(file);
156     pm_spool(pr->memory, pr->filename, pr->queue);
157     unlink(pr->filename);
158     return 0;
159 }
160