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