xref: /plan9/sys/src/cmd/gs/src/gp_mswin.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 2000-2003 artofcode LLC.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gp_mswin.c,v 1.25 2005/03/04 21:58:55 ghostgum Exp $ */
18 /*
19  * Microsoft Windows platform support for Ghostscript.
20  *
21  * Original version by Russell Lang and Maurice Castro with help from
22  * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
23  * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
24  */
25 
26 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
27 /* by Friedrich Nowak                                           */
28 
29 /* Original EXE and GSview specific code removed */
30 /* DLL version must now be used under MS-Windows */
31 /* Russell Lang 16 March 1996 */
32 
33 #include "stdio_.h"
34 #include "string_.h"
35 #include "memory_.h"
36 #include "pipe_.h"
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include "ctype_.h"
40 #include <io.h>
41 #include "malloc_.h"
42 #include <fcntl.h>
43 #include <signal.h>
44 #include "gx.h"
45 #include "gp.h"
46 #include "gpcheck.h"
47 #include "gpmisc.h"
48 #include "gserrors.h"
49 #include "gsexit.h"
50 
51 #include "windows_.h"
52 #include <shellapi.h>
53 #include <winspool.h>
54 #include "gp_mswin.h"
55 
56 /* Library routines not declared in a standard header */
57 extern char *getenv(const char *);
58 
59 /* limits */
60 #define MAXSTR 255
61 
62 /* GLOBAL VARIABLE that needs to be removed */
63 char win_prntmp[MAXSTR];	/* filename of PRN temporary file */
64 
65 /* GLOBAL VARIABLES - initialised at DLL load time */
66 HINSTANCE phInstance;
67 BOOL is_win32s = FALSE;
68 
69 const LPSTR szAppName = "Ghostscript";
70 private int is_printer(const char *name);
71 
72 
73 /* ====== Generic platform procedures ====== */
74 
75 /* ------ Initialization/termination (from gp_itbc.c) ------ */
76 
77 /* Do platform-dependent initialization. */
78 void
gp_init(void)79 gp_init(void)
80 {
81 }
82 
83 /* Do platform-dependent cleanup. */
84 void
gp_exit(int exit_status,int code)85 gp_exit(int exit_status, int code)
86 {
87 }
88 
89 /* Exit the program. */
90 void
gp_do_exit(int exit_status)91 gp_do_exit(int exit_status)
92 {
93     exit(exit_status);
94 }
95 
96 /* ------ Persistent data cache ------*/
97 
98 /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)99 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
100 {
101     /* not yet implemented */
102     return 0;
103 }
104 
105 /* look up a (type, key) in the cache */
gp_cache_query(int type,byte * key,int keylen,void ** buffer,gp_cache_alloc alloc,void * userdata)106 int gp_cache_query(int type, byte* key, int keylen, void **buffer,
107     gp_cache_alloc alloc, void *userdata)
108 {
109     /* not yet implemented */
110     return -1;
111 }
112 
113 /* ------ Printer accessing ------ */
114 
115 /* Forward references */
116 private int gp_printfile(const char *, const char *);
117 
118 /* Open a connection to a printer.  A null file name means use the */
119 /* standard printer connected to the machine, if any. */
120 /* Return NULL if the connection could not be opened. */
121 FILE *
gp_open_printer(char fname[gp_file_name_sizeof],int binary_mode)122 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
123 {
124     if (is_printer(fname)) {
125 	FILE *pfile;
126 
127 	/* Open a scratch file, which we will send to the */
128 	/* actual printer in gp_close_printer. */
129 	pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
130 				     win_prntmp, "wb");
131 	return pfile;
132     } else if (fname[0] == '|') 	/* pipe */
133 	return popen(fname + 1, (binary_mode ? "wb" : "w"));
134     else
135 	return fopen(fname, (binary_mode ? "wb" : "w"));
136 }
137 
138 /* Close the connection to the printer. */
139 void
gp_close_printer(FILE * pfile,const char * fname)140 gp_close_printer(FILE * pfile, const char *fname)
141 {
142     fclose(pfile);
143     if (!is_printer(fname))
144 	return;			/* a file, not a printer */
145 
146     gp_printfile(win_prntmp, fname);
147     unlink(win_prntmp);
148 }
149 
150 
151 /* Dialog box to select printer port */
152 DLGRETURN CALLBACK
SpoolDlgProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)153 SpoolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
154 {
155     LPSTR entry;
156 
157     switch (message) {
158 	case WM_INITDIALOG:
159 	    entry = (LPSTR) lParam;
160 	    while (*entry) {
161 		SendDlgItemMessage(hDlg, SPOOL_PORT, LB_ADDSTRING, 0, (LPARAM) entry);
162 		entry += lstrlen(entry) + 1;
163 	    }
164 	    SendDlgItemMessage(hDlg, SPOOL_PORT, LB_SETCURSEL, 0, (LPARAM) 0);
165 	    return TRUE;
166 	case WM_COMMAND:
167 	    switch (LOWORD(wParam)) {
168 		case SPOOL_PORT:
169 		    if (HIWORD(wParam) == LBN_DBLCLK)
170 			PostMessage(hDlg, WM_COMMAND, IDOK, 0L);
171 		    return FALSE;
172 		case IDOK:
173 		    EndDialog(hDlg, 1 + (int)SendDlgItemMessage(hDlg, SPOOL_PORT, LB_GETCURSEL, 0, 0L));
174 		    return TRUE;
175 		case IDCANCEL:
176 		    EndDialog(hDlg, 0);
177 		    return TRUE;
178 	    }
179     }
180     return FALSE;
181 }
182 
183 /* return TRUE if queue looks like a valid printer name */
184 int
is_spool(const char * queue)185 is_spool(const char *queue)
186 {
187     char *prefix = "\\\\spool";	/* 7 characters long */
188     int i;
189 
190     for (i = 0; i < 7; i++) {
191 	if (prefix[i] == '\\') {
192 	    if ((*queue != '\\') && (*queue != '/'))
193 		return FALSE;
194 	} else if (tolower(*queue) != prefix[i])
195 	    return FALSE;
196 	queue++;
197     }
198     if (*queue && (*queue != '\\') && (*queue != '/'))
199 	return FALSE;
200     return TRUE;
201 }
202 
203 
204 private int
is_printer(const char * name)205 is_printer(const char *name)
206 {
207     char buf[128];
208 
209     /* is printer if no name given */
210     if (strlen(name) == 0)
211 	return TRUE;
212 
213     /*  is printer if name appears in win.ini [ports] section */
214     GetProfileString("ports", name, "XYZ", buf, sizeof(buf));
215     if (strlen(name) == 0 || strcmp(buf, "XYZ"))
216 	return TRUE;
217 
218     /* is printer if name prefixed by \\spool\ */
219     if (is_spool(name))
220 	return TRUE;
221 
222     return FALSE;
223 }
224 
225 
226 /******************************************************************/
227 /* Print File to port or queue */
228 /* port==NULL means prompt for port or queue with dialog box */
229 
230 /* This is messy because Microsoft changed the spooler interface */
231 /* between Windows 3.1 and Windows 95/NT */
232 /* and didn't provide the spooler interface in Win32s */
233 
234 /* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */
235 private int gp_printfile_win32(const char *filename, char *port);
236 
237 /* Win32s: Pass to Win16 spooler via gs16spl.exe */
238 private int gp_printfile_gs16spl(const char *filename, const char *port);
239 
240 /*
241  * Valid values for pmport are:
242  *   ""
243  *      action: WinNT and Win95 use default queue, Win32s prompts for port
244  *   "LPT1:" (or other port that appears in win.ini [ports]
245  *      action: start gs16spl.exe to print to the port
246  *   "\\spool\printer name"
247  *      action: send to printer using WritePrinter (WinNT and Win95).
248  *      action: translate to port name using win.ini [Devices]
249  *              then use gs16spl.exe (Win32s).
250  *   "\\spool"
251  *      action: prompt for queue name then send to printer using
252  *              WritePrinter (WinNT and Win95).
253  *      action: prompt for port then use gs16spl.exe (Win32s).
254  */
255 /* Print File */
256 private int
gp_printfile(const char * filename,const char * pmport)257 gp_printfile(const char *filename, const char *pmport)
258 {
259     /* treat WinNT and Win95 differently to Win32s */
260     if (!is_win32s) {
261 	if (strlen(pmport) == 0) {	/* get default printer */
262 	    char buf[256];
263 	    char *p;
264 
265 	    /* WinNT stores default printer in registry and win.ini */
266 	    /* Win95 stores default printer in win.ini */
267 	    GetProfileString("windows", "device", "", buf, sizeof(buf));
268 	    if ((p = strchr(buf, ',')) != NULL)
269 		*p = '\0';
270 	    return gp_printfile_win32(filename, buf);
271 	} else if (is_spool(pmport)) {
272 	    if (strlen(pmport) >= 8)
273 		return gp_printfile_win32(filename, (char *)pmport + 8);
274 	    else
275 		return gp_printfile_win32(filename, (char *)NULL);
276 	} else
277 	    return gp_printfile_gs16spl(filename, pmport);
278     } else {
279 	/* Win32s */
280 	if (is_spool(pmport)) {
281 	    if (strlen(pmport) >= 8) {
282 		/* extract port name from win.ini */
283 		char driverbuf[256];
284 		char *output;
285 
286 		GetProfileString("Devices", pmport + 8, "", driverbuf, sizeof(driverbuf));
287 		strtok(driverbuf, ",");
288 		output = strtok(NULL, ",");
289 		return gp_printfile_gs16spl(filename, output);
290 	    } else
291 		return gp_printfile_gs16spl(filename, (char *)NULL);
292 	} else
293 	    return gp_printfile_gs16spl(filename, pmport);
294     }
295 }
296 
297 #define PRINT_BUF_SIZE 16384u
298 #define PORT_BUF_SIZE 4096
299 
300 char *
get_queues(void)301 get_queues(void)
302 {
303     int i;
304     DWORD count, needed;
305     PRINTER_INFO_1 *prinfo;
306     char *enumbuffer;
307     char *buffer;
308     char *p;
309 
310     /* enumerate all available printers */
311     EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count);
312     if (needed == 0) {
313 	/* no printers */
314 	enumbuffer = malloc(4);
315 	if (enumbuffer == (char *)NULL)
316 	    return NULL;
317 	memset(enumbuffer, 0, 4);
318 	return enumbuffer;
319     }
320     enumbuffer = malloc(needed);
321     if (enumbuffer == (char *)NULL)
322 	return NULL;
323     if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE) enumbuffer, needed, &needed, &count)) {
324 	char buf[256];
325 
326 	free(enumbuffer);
327 	sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError());
328 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
329 	return NULL;
330     }
331     prinfo = (PRINTER_INFO_1 *) enumbuffer;
332     if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) {
333 	free(enumbuffer);
334 	return NULL;
335     }
336     /* copy printer names to single buffer */
337     p = buffer;
338     for (i = 0; i < count; i++) {
339 	if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE - (p - buffer))) {
340 	    strcpy(p, prinfo[i].pName);
341 	    p += strlen(p) + 1;
342 	}
343     }
344     *p = '\0';			/* double null at end */
345     free(enumbuffer);
346     return buffer;
347 }
348 
349 
350 char *
get_ports(void)351 get_ports(void)
352 {
353     char *buffer;
354 
355     if (!is_win32s)
356 	return get_queues();
357 
358     if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL)
359 	return NULL;
360     GetProfileString("ports", NULL, "", buffer, PORT_BUF_SIZE);
361     return buffer;
362 }
363 
364 /* return TRUE if queuename available */
365 /* return FALSE if cancelled or error */
366 /* if queue non-NULL, use as suggested queue */
367 BOOL
get_queuename(char * portname,const char * queue)368 get_queuename(char *portname, const char *queue)
369 {
370     char *buffer;
371     char *p;
372     int i, iport;
373 
374     buffer = get_queues();
375     if (buffer == NULL)
376 	return FALSE;
377     if ((queue == (char *)NULL) || (strlen(queue) == 0)) {
378 	/* select a queue */
379 	iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
380 	if (!iport) {
381 	    free(buffer);
382 	    return FALSE;
383 	}
384 	p = buffer;
385 	for (i = 1; i < iport && strlen(p) != 0; i++)
386 	    p += lstrlen(p) + 1;
387 	/* prepend \\spool\ which is used by Ghostscript to distinguish */
388 	/* real files from queues */
389 	strcpy(portname, "\\\\spool\\");
390 	strcat(portname, p);
391     } else {
392 	strcpy(portname, "\\\\spool\\");
393 	strcat(portname, queue);
394     }
395 
396     free(buffer);
397     return TRUE;
398 }
399 
400 /* return TRUE if portname available */
401 /* return FALSE if cancelled or error */
402 /* if port non-NULL, use as suggested port */
403 BOOL
get_portname(char * portname,const char * port)404 get_portname(char *portname, const char *port)
405 {
406     char *buffer;
407     char *p;
408     int i, iport;
409     char filename[MAXSTR];
410 
411     buffer = get_ports();
412     if (buffer == NULL)
413 	return FALSE;
414     if ((port == (char *)NULL) || (strlen(port) == 0)) {
415 	if (buffer == (char *)NULL)
416 	    return FALSE;
417 	/* select a port */
418 	iport = DialogBoxParam(phInstance, "SpoolDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
419 	if (!iport) {
420 	    free(buffer);
421 	    return FALSE;
422 	}
423 	p = buffer;
424 	for (i = 1; i < iport && strlen(p) != 0; i++)
425 	    p += lstrlen(p) + 1;
426 	strcpy(portname, p);
427     } else
428 	strcpy(portname, port);
429 
430     if (strlen(portname) == 0)
431 	return FALSE;
432     if (strcmp(portname, "FILE:") == 0) {
433 	OPENFILENAME ofn;
434 
435 	filename[0] = '\0';
436 	memset(&ofn, 0, sizeof(OPENFILENAME));
437 	ofn.lStructSize = sizeof(OPENFILENAME);
438 	ofn.hwndOwner = (HWND) NULL;
439 	ofn.lpstrFile = filename;
440 	ofn.nMaxFile = sizeof(filename);
441 	ofn.Flags = OFN_PATHMUSTEXIST;
442 	if (!GetSaveFileName(&ofn)) {
443 	    free(buffer);
444 	    return FALSE;
445 	}
446 	strcpy(portname, filename);
447     }
448     free(buffer);
449     return TRUE;
450 }
451 
452 
453 /* True Win32 method, using OpenPrinter, WritePrinter etc. */
454 private int
gp_printfile_win32(const char * filename,char * port)455 gp_printfile_win32(const char *filename, char *port)
456 {
457     DWORD count;
458     char *buffer;
459     char portname[MAXSTR];
460     FILE *f;
461     HANDLE printer;
462     DOC_INFO_1 di;
463     DWORD written;
464 
465     if (!get_queuename(portname, port))
466 	return FALSE;
467     port = portname + 8;	/* skip over \\spool\ */
468 
469     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
470 	return FALSE;
471 
472     if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
473 	free(buffer);
474 	return FALSE;
475     }
476     /* open a printer */
477     if (!OpenPrinter(port, &printer, NULL)) {
478 	char buf[256];
479 
480 	sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError());
481 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
482 	free(buffer);
483 	return FALSE;
484     }
485     /* from here until ClosePrinter, should AbortPrinter on error */
486 
487     di.pDocName = szAppName;
488     di.pOutputFile = NULL;
489     di.pDatatype = "RAW";	/* for available types see EnumPrintProcessorDatatypes */
490     if (!StartDocPrinter(printer, 1, (LPBYTE) & di)) {
491 	char buf[256];
492 
493 	sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError());
494 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
495 	AbortPrinter(printer);
496 	free(buffer);
497 	return FALSE;
498     }
499     /* copy file to printer */
500     while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
501 	if (!WritePrinter(printer, (LPVOID) buffer, count, &written)) {
502 	    free(buffer);
503 	    fclose(f);
504 	    AbortPrinter(printer);
505 	    return FALSE;
506 	}
507     }
508     fclose(f);
509     free(buffer);
510 
511     if (!EndDocPrinter(printer)) {
512 	char buf[256];
513 
514 	sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError());
515 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
516 	AbortPrinter(printer);
517 	return FALSE;
518     }
519     if (!ClosePrinter(printer)) {
520 	char buf[256];
521 
522 	sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError());
523 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
524 	return FALSE;
525     }
526     return TRUE;
527 }
528 
529 
530 /* Start a 16-bit application gs16spl.exe to print a file */
531 /* Intended for Win32s where 16-bit spooler functions are not available */
532 /* and Win32 spooler functions are not implemented. */
533 int
gp_printfile_gs16spl(const char * filename,const char * port)534 gp_printfile_gs16spl(const char *filename, const char *port)
535 {
536 /* Get printer port list from win.ini */
537     char portname[MAXSTR];
538     HINSTANCE hinst;
539     char command[MAXSTR];
540     char *p;
541     HWND hwndspl;
542 
543     if (!get_portname(portname, port))
544 	return FALSE;
545 
546     /* get path to EXE - same as DLL */
547     GetModuleFileName(phInstance, command, sizeof(command));
548     if ((p = strrchr(command, '\\')) != (char *)NULL)
549 	p++;
550     else
551 	p = command;
552     *p = '\0';
553     sprintf(command + strlen(command), "gs16spl.exe %s %s",
554 	    portname, filename);
555 
556     hinst = (HINSTANCE) WinExec(command, SW_SHOWNORMAL);
557     if (hinst < (HINSTANCE) HINSTANCE_ERROR) {
558 	char buf[MAXSTR];
559 
560 	sprintf(buf, "Can't run: %s", command);
561 	MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
562 	return FALSE;
563     }
564     hwndspl = FindWindow(NULL, "GS Win32s/Win16 spooler");
565 
566     while (IsWindow(hwndspl)) {
567 	gp_check_interrupts(NULL);
568     }
569 
570     return 0;
571 }
572 
573 
574 /******************************************************************/
575 /* MS Windows has popen and pclose in stdio.h, but under different names.
576  * Unfortunately MSVC5 and 6 have a broken implementation of _popen,
577  * so we use own.  Our implementation only supports mode "wb".
578  */
mswin_popen(const char * cmd,const char * mode)579 FILE *mswin_popen(const char *cmd, const char *mode)
580 {
581     SECURITY_ATTRIBUTES saAttr;
582     STARTUPINFO siStartInfo;
583     PROCESS_INFORMATION piProcInfo;
584     HANDLE hPipeTemp = INVALID_HANDLE_VALUE;
585     HANDLE hChildStdinRd = INVALID_HANDLE_VALUE;
586     HANDLE hChildStdinWr = INVALID_HANDLE_VALUE;
587     HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;
588     HANDLE hChildStderrWr = INVALID_HANDLE_VALUE;
589     HANDLE hProcess = GetCurrentProcess();
590     int handle = 0;
591     char *command = NULL;
592     FILE *pipe = NULL;
593 
594     if (strcmp(mode, "wb") != 0)
595 	return NULL;
596 
597     /* Set the bInheritHandle flag so pipe handles are inherited. */
598     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
599     saAttr.bInheritHandle = TRUE;
600     saAttr.lpSecurityDescriptor = NULL;
601 
602     /* Create anonymous inheritable pipes for STDIN for child.
603      * First create a noninheritable duplicate handle of our end of
604      * the pipe, then close the inheritable handle.
605      */
606     if (handle == 0)
607         if (!CreatePipe(&hChildStdinRd, &hPipeTemp, &saAttr, 0))
608 	    handle = -1;
609     if (handle == 0) {
610 	if (!DuplicateHandle(hProcess, hPipeTemp,
611 	    hProcess, &hChildStdinWr, 0, FALSE /* not inherited */,
612 	    DUPLICATE_SAME_ACCESS))
613 	    handle = -1;
614         CloseHandle(hPipeTemp);
615     }
616     /* Create inheritable duplicate handles for our stdout/err */
617     if (handle == 0)
618 	if (!DuplicateHandle(hProcess, GetStdHandle(STD_OUTPUT_HANDLE),
619 	    hProcess, &hChildStdoutWr, 0, TRUE /* inherited */,
620 	    DUPLICATE_SAME_ACCESS))
621 	    handle = -1;
622     if (handle == 0)
623         if (!DuplicateHandle(hProcess, GetStdHandle(STD_ERROR_HANDLE),
624             hProcess, &hChildStderrWr, 0, TRUE /* inherited */,
625 	    DUPLICATE_SAME_ACCESS))
626 	    handle = -1;
627 
628     /* Set up members of STARTUPINFO structure. */
629     memset(&siStartInfo, 0, sizeof(STARTUPINFO));
630     siStartInfo.cb = sizeof(STARTUPINFO);
631     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
632     siStartInfo.hStdInput = hChildStdinRd;
633     siStartInfo.hStdOutput = hChildStdoutWr;
634     siStartInfo.hStdError = hChildStderrWr;
635 
636     if (handle == 0) {
637 	command = (char *)malloc(strlen(cmd)+1);
638 	if (command)
639 	    strcpy(command, cmd);
640 	else
641 	    handle = -1;
642     }
643 
644     if (handle == 0)
645 	if (!CreateProcess(NULL,
646 	    command,  	   /* command line                       */
647 	    NULL,          /* process security attributes        */
648 	    NULL,          /* primary thread security attributes */
649 	    TRUE,          /* handles are inherited              */
650 	    0,             /* creation flags                     */
651 	    NULL,          /* environment                        */
652 	    NULL,          /* use parent's current directory     */
653 	    &siStartInfo,  /* STARTUPINFO pointer                */
654 	    &piProcInfo))  /* receives PROCESS_INFORMATION  */
655 	{
656 	    handle = -1;
657 	}
658 	else {
659 	    CloseHandle(piProcInfo.hProcess);
660 	    CloseHandle(piProcInfo.hThread);
661 	    handle = _open_osfhandle((long)hChildStdinWr, 0);
662 	}
663 
664     if (hChildStdinRd != INVALID_HANDLE_VALUE)
665 	CloseHandle(hChildStdinRd);	/* close our copy */
666     if (hChildStdoutWr != INVALID_HANDLE_VALUE)
667 	CloseHandle(hChildStdoutWr);	/* close our copy */
668     if (hChildStderrWr != INVALID_HANDLE_VALUE)
669 	CloseHandle(hChildStderrWr);	/* close our copy */
670     if (command)
671 	free(command);
672 
673     if (handle < 0) {
674 	if (hChildStdinWr != INVALID_HANDLE_VALUE)
675 	    CloseHandle(hChildStdinWr);
676     }
677     else {
678 	pipe = _fdopen(handle, "wb");
679 	if (pipe == NULL)
680 	    _close(handle);
681     }
682     return pipe;
683 }
684 
685 
686 /* ------ File naming and accessing ------ */
687 
688 /* Create and open a scratch file with a given name prefix. */
689 /* Write the actual file name at fname. */
690 FILE *
gp_open_scratch_file(const char * prefix,char * fname,const char * mode)691 gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
692 {
693     UINT n;
694     DWORD l;
695     HANDLE hfile = INVALID_HANDLE_VALUE;
696     int fd = -1;
697     FILE *f = NULL;
698     char sTempDir[_MAX_PATH];
699     char sTempFileName[_MAX_PATH];
700 
701     memset(fname, 0, gp_file_name_sizeof);
702     if (!gp_file_name_is_absolute(prefix, strlen(prefix))) {
703 	int plen = sizeof(sTempDir);
704 
705 	if (gp_gettmpdir(sTempDir, &plen) != 0)
706 	    l = GetTempPath(sizeof(sTempDir), sTempDir);
707 	else
708 	    l = strlen(sTempDir);
709     } else {
710 	strncpy(sTempDir, prefix, sizeof(sTempDir));
711 	prefix = "";
712 	l = strlen(sTempDir);
713     }
714     /* Fix the trailing terminator so GetTempFileName doesn't get confused */
715     if (sTempDir[l-1] == '/')
716 	sTempDir[l-1] = '\\';		/* What Windoze prefers */
717 
718     if (l <= sizeof(sTempDir)) {
719 	n = GetTempFileName(sTempDir, prefix, 0, sTempFileName);
720 	if (n == 0) {
721 	    /* If 'prefix' is not a directory, it is a path prefix. */
722 	    int l = strlen(sTempDir), i;
723 
724 	    for (i = l - 1; i > 0; i--) {
725 		uint slen = gs_file_name_check_separator(sTempDir + i, l, sTempDir + l);
726 
727 		if (slen > 0) {
728 		    sTempDir[i] = 0;
729 		    i += slen;
730 		    break;
731 		}
732 	    }
733 	    if (i > 0)
734 		n = GetTempFileName(sTempDir, sTempDir + i, 0, sTempFileName);
735 	}
736 	if (n != 0) {
737 	    hfile = CreateFile(sTempFileName,
738 		GENERIC_READ | GENERIC_WRITE | DELETE,
739 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
740 		FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */,
741 		NULL);
742 	    /*
743 	     * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to
744 	     * the logics of clist_fclose. Also note that
745 	     * gdev_prn_render_pages requires multiple temporary files
746 	     * to exist simultaneousely, so that keeping all them opened
747 	     * may exceed available CRTL file handles.
748 	     */
749 	}
750     }
751     if (hfile != INVALID_HANDLE_VALUE) {
752 	/* Associate a C file handle with an OS file handle. */
753 	fd = _open_osfhandle((long)hfile, 0);
754 	if (fd == -1)
755 	    CloseHandle(hfile);
756 	else {
757 	    /* Associate a C file stream with C file handle. */
758 	    f = fdopen(fd, mode);
759 	    if (f == NULL)
760 		_close(fd);
761 	}
762     }
763     if (f != NULL) {
764 	if ((strlen(sTempFileName) < gp_file_name_sizeof))
765 	    strncpy(fname, sTempFileName, gp_file_name_sizeof - 1);
766 	else {
767 	    /* The file name is too long. */
768 	    fclose(f);
769 	    f = NULL;
770 	}
771     }
772     if (f == NULL)
773 	eprintf1("**** Could not open temporary file '%s'\n", fname);
774     return f;
775 }
776 
777 /* Open a file with the given name, as a stream of uninterpreted bytes. */
778 FILE *
gp_fopen(const char * fname,const char * mode)779 gp_fopen(const char *fname, const char *mode)
780 {
781     return fopen(fname, mode);
782 }
783 
784 /* ------ Font enumeration ------ */
785 
786  /* This is used to query the native os for a list of font names and
787   * corresponding paths. The general idea is to save the hassle of
788   * building a custom fontmap file.
789   */
790 
gp_enumerate_fonts_init(gs_memory_t * mem)791 void *gp_enumerate_fonts_init(gs_memory_t *mem)
792 {
793     return NULL;
794 }
795 
gp_enumerate_fonts_next(void * enum_state,char ** fontname,char ** path)796 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
797 {
798     return 0;
799 }
800 
gp_enumerate_fonts_free(void * enum_state)801 void gp_enumerate_fonts_free(void *enum_state)
802 {
803 }
804