1 /* Copyright (C) 2001-2006 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, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gp_mswin.c 8250 2007-09-25 13:31:24Z giles $ */
15 /*
16 * Microsoft Windows platform support for Ghostscript.
17 *
18 * Original version by Russell Lang and Maurice Castro with help from
19 * Programming Windows, 2nd Ed., Charles Petzold, Microsoft Press;
20 * initially created from gp_dosfb.c and gp_itbc.c 5th June 1992.
21 */
22
23 /* Modified for Win32 & Microsoft C/C++ 8.0 32-Bit, 26.Okt.1994 */
24 /* by Friedrich Nowak */
25
26 /* Original EXE and GSview specific code removed */
27 /* DLL version must now be used under MS-Windows */
28 /* Russell Lang 16 March 1996 */
29
30 #include "stdio_.h"
31 #include "string_.h"
32 #include "memory_.h"
33 #include "pipe_.h"
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include "ctype_.h"
37 #include <io.h>
38 #include "malloc_.h"
39 #include <fcntl.h>
40 #include <signal.h>
41 #include "gx.h"
42 #include "gp.h"
43 #include "gpcheck.h"
44 #include "gpmisc.h"
45 #include "gserrors.h"
46 #include "gsexit.h"
47
48 #include "windows_.h"
49 #include <stdarg.h>
50 #include <shellapi.h>
51 #include <winspool.h>
52 #include "gp_mswin.h"
53
54 /* Library routines not declared in a standard header */
55 extern char *getenv(const char *);
56
57 /* limits */
58 #define MAXSTR 255
59
60 /* GLOBAL VARIABLE that needs to be removed */
61 char win_prntmp[MAXSTR]; /* filename of PRN temporary file */
62
63 /* GLOBAL VARIABLES - initialised at DLL load time */
64 HINSTANCE phInstance;
65 BOOL is_win32s = FALSE;
66
67 const LPSTR szAppName = "Ghostscript";
68 static int is_printer(const char *name);
69
70
71 /* ====== Generic platform procedures ====== */
72
73 /* ------ Initialization/termination (from gp_itbc.c) ------ */
74
75 /* Do platform-dependent initialization. */
76 void
gp_init(void)77 gp_init(void)
78 {
79 }
80
81 /* Do platform-dependent cleanup. */
82 void
gp_exit(int exit_status,int code)83 gp_exit(int exit_status, int code)
84 {
85 }
86
87 /* Exit the program. */
88 void
gp_do_exit(int exit_status)89 gp_do_exit(int exit_status)
90 {
91 exit(exit_status);
92 }
93
94 /* ------ Persistent data cache ------*/
95
96 /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)97 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
98 {
99 /* not yet implemented */
100 return 0;
101 }
102
103 /* 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)104 int gp_cache_query(int type, byte* key, int keylen, void **buffer,
105 gp_cache_alloc alloc, void *userdata)
106 {
107 /* not yet implemented */
108 return -1;
109 }
110
111 /* ------ Printer accessing ------ */
112
113 /* Forward references */
114 static int gp_printfile(const char *, const char *);
115
116 /* Open a connection to a printer. A null file name means use the */
117 /* standard printer connected to the machine, if any. */
118 /* Return NULL if the connection could not be opened. */
119 FILE *
gp_open_printer(char fname[gp_file_name_sizeof],int binary_mode)120 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
121 {
122 if (is_printer(fname)) {
123 FILE *pfile;
124
125 /* Open a scratch file, which we will send to the */
126 /* actual printer in gp_close_printer. */
127 pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
128 win_prntmp, "wb");
129 return pfile;
130 } else if (fname[0] == '|') /* pipe */
131 return popen(fname + 1, (binary_mode ? "wb" : "w"));
132 else if (strcmp(fname, "LPT1:") == 0)
133 return NULL; /* not supported, use %printer%name instead */
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 static int
is_printer(const char * name)205 is_printer(const char *name)
206 {
207 /* is printer if no name given */
208 if (strlen(name) == 0)
209 return TRUE;
210
211 /* is printer if name prefixed by \\spool\ */
212 if (is_spool(name))
213 return TRUE;
214
215 return FALSE;
216 }
217
218
219 /******************************************************************/
220 /* Print File to port or queue */
221 /* port==NULL means prompt for port or queue with dialog box */
222
223 /* This is messy because of past support for old version of Windows. */
224
225 /* Win95, WinNT: Use OpenPrinter, WritePrinter etc. */
226 static int gp_printfile_win32(const char *filename, char *port);
227
228 /*
229 * Valid values for pmport are:
230 * ""
231 * action: Use default queue
232 * "\\spool\printer name"
233 * action: send to printer using WritePrinter.
234 * Using "%printer%printer name" is preferred
235 * "\\spool"
236 * action: prompt for queue name then send to printer using WritePrinter.
237 * THIS IS CURRENTLY BROKEN
238 */
239 /* Print File */
240 static int
gp_printfile(const char * filename,const char * pmport)241 gp_printfile(const char *filename, const char *pmport)
242 {
243 if (strlen(pmport) == 0) { /* get default printer */
244 char buf[256];
245 char *p;
246
247 /* WinNT stores default printer in registry and win.ini */
248 /* Win95 stores default printer in win.ini */
249 GetProfileString("windows", "device", "", buf, sizeof(buf));
250 if ((p = strchr(buf, ',')) != NULL)
251 *p = '\0';
252 return gp_printfile_win32(filename, buf);
253 } else if (is_spool(pmport)) {
254 if (strlen(pmport) >= 8)
255 return gp_printfile_win32(filename, (char *)pmport + 8);
256 else
257 return gp_printfile_win32(filename, (char *)NULL);
258 } else
259 return gs_error_undefinedfilename;
260 }
261
262 #define PRINT_BUF_SIZE 16384u
263 #define PORT_BUF_SIZE 4096
264
265 char *
get_queues(void)266 get_queues(void)
267 {
268 int i;
269 DWORD count, needed;
270 PRINTER_INFO_1 *prinfo;
271 char *enumbuffer;
272 char *buffer;
273 char *p;
274
275 /* enumerate all available printers */
276 EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, NULL, 0, &needed, &count);
277 if (needed == 0) {
278 /* no printers */
279 enumbuffer = malloc(4);
280 if (enumbuffer == (char *)NULL)
281 return NULL;
282 memset(enumbuffer, 0, 4);
283 return enumbuffer;
284 }
285 enumbuffer = malloc(needed);
286 if (enumbuffer == (char *)NULL)
287 return NULL;
288 if (!EnumPrinters(PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL, NULL, 1, (LPBYTE) enumbuffer, needed, &needed, &count)) {
289 char buf[256];
290
291 free(enumbuffer);
292 sprintf(buf, "EnumPrinters() failed, error code = %d", GetLastError());
293 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
294 return NULL;
295 }
296 prinfo = (PRINTER_INFO_1 *) enumbuffer;
297 if ((buffer = malloc(PORT_BUF_SIZE)) == (char *)NULL) {
298 free(enumbuffer);
299 return NULL;
300 }
301 /* copy printer names to single buffer */
302 p = buffer;
303 for (i = 0; i < count; i++) {
304 if (strlen(prinfo[i].pName) + 1 < (PORT_BUF_SIZE - (p - buffer))) {
305 strcpy(p, prinfo[i].pName);
306 p += strlen(p) + 1;
307 }
308 }
309 *p = '\0'; /* double null at end */
310 free(enumbuffer);
311 return buffer;
312 }
313
314 /* return TRUE if queuename available */
315 /* return FALSE if cancelled or error */
316 /* if queue non-NULL, use as suggested queue */
317 BOOL
get_queuename(char * portname,const char * queue)318 get_queuename(char *portname, const char *queue)
319 {
320 char *buffer;
321 char *p;
322 int i, iport;
323
324 buffer = get_queues();
325 if (buffer == NULL)
326 return FALSE;
327 if ((queue == (char *)NULL) || (strlen(queue) == 0)) {
328 /* PROMPTING FOR A QUEUE IS CURRENTLY BROKEN */
329 /* select a queue */
330 iport = DialogBoxParam(phInstance, "QueueDlgBox", (HWND) NULL, SpoolDlgProc, (LPARAM) buffer);
331 if (!iport) {
332 free(buffer);
333 return FALSE;
334 }
335 p = buffer;
336 for (i = 1; i < iport && strlen(p) != 0; i++)
337 p += lstrlen(p) + 1;
338 /* prepend \\spool\ which is used by Ghostscript to distinguish */
339 /* real files from queues */
340 strcpy(portname, "\\\\spool\\");
341 strcat(portname, p);
342 } else {
343 strcpy(portname, "\\\\spool\\");
344 strcat(portname, queue);
345 }
346
347 free(buffer);
348 return TRUE;
349 }
350
351 /* True Win32 method, using OpenPrinter, WritePrinter etc. */
352 static int
gp_printfile_win32(const char * filename,char * port)353 gp_printfile_win32(const char *filename, char *port)
354 {
355 DWORD count;
356 char *buffer;
357 char portname[MAXSTR];
358 FILE *f;
359 HANDLE printer;
360 DOC_INFO_1 di;
361 DWORD written;
362
363 if (!get_queuename(portname, port))
364 return FALSE;
365 port = portname + 8; /* skip over \\spool\ */
366
367 if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL)
368 return FALSE;
369
370 if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
371 free(buffer);
372 return FALSE;
373 }
374 /* open a printer */
375 if (!OpenPrinter(port, &printer, NULL)) {
376 char buf[256];
377
378 sprintf(buf, "OpenPrinter() failed for \042%s\042, error code = %d", port, GetLastError());
379 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
380 free(buffer);
381 return FALSE;
382 }
383 /* from here until ClosePrinter, should AbortPrinter on error */
384
385 di.pDocName = szAppName;
386 di.pOutputFile = NULL;
387 di.pDatatype = "RAW"; /* for available types see EnumPrintProcessorDatatypes */
388 if (!StartDocPrinter(printer, 1, (LPBYTE) & di)) {
389 char buf[256];
390
391 sprintf(buf, "StartDocPrinter() failed, error code = %d", GetLastError());
392 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
393 AbortPrinter(printer);
394 free(buffer);
395 return FALSE;
396 }
397 /* copy file to printer */
398 while ((count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
399 if (!WritePrinter(printer, (LPVOID) buffer, count, &written)) {
400 free(buffer);
401 fclose(f);
402 AbortPrinter(printer);
403 return FALSE;
404 }
405 }
406 fclose(f);
407 free(buffer);
408
409 if (!EndDocPrinter(printer)) {
410 char buf[256];
411
412 sprintf(buf, "EndDocPrinter() failed, error code = %d", GetLastError());
413 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
414 AbortPrinter(printer);
415 return FALSE;
416 }
417 if (!ClosePrinter(printer)) {
418 char buf[256];
419
420 sprintf(buf, "ClosePrinter() failed, error code = %d", GetLastError());
421 MessageBox((HWND) NULL, buf, szAppName, MB_OK | MB_ICONSTOP);
422 return FALSE;
423 }
424 return TRUE;
425 }
426
427
428
429
430 /******************************************************************/
431 /* MS Windows has popen and pclose in stdio.h, but under different names.
432 * Unfortunately MSVC5 and 6 have a broken implementation of _popen,
433 * so we use own. Our implementation only supports mode "wb".
434 */
mswin_popen(const char * cmd,const char * mode)435 FILE *mswin_popen(const char *cmd, const char *mode)
436 {
437 SECURITY_ATTRIBUTES saAttr;
438 STARTUPINFO siStartInfo;
439 PROCESS_INFORMATION piProcInfo;
440 HANDLE hPipeTemp = INVALID_HANDLE_VALUE;
441 HANDLE hChildStdinRd = INVALID_HANDLE_VALUE;
442 HANDLE hChildStdinWr = INVALID_HANDLE_VALUE;
443 HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;
444 HANDLE hChildStderrWr = INVALID_HANDLE_VALUE;
445 HANDLE hProcess = GetCurrentProcess();
446 int handle = 0;
447 char *command = NULL;
448 FILE *pipe = NULL;
449
450 if (strcmp(mode, "wb") != 0)
451 return NULL;
452
453 /* Set the bInheritHandle flag so pipe handles are inherited. */
454 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
455 saAttr.bInheritHandle = TRUE;
456 saAttr.lpSecurityDescriptor = NULL;
457
458 /* Create anonymous inheritable pipes for STDIN for child.
459 * First create a noninheritable duplicate handle of our end of
460 * the pipe, then close the inheritable handle.
461 */
462 if (handle == 0)
463 if (!CreatePipe(&hChildStdinRd, &hPipeTemp, &saAttr, 0))
464 handle = -1;
465 if (handle == 0) {
466 if (!DuplicateHandle(hProcess, hPipeTemp,
467 hProcess, &hChildStdinWr, 0, FALSE /* not inherited */,
468 DUPLICATE_SAME_ACCESS))
469 handle = -1;
470 CloseHandle(hPipeTemp);
471 }
472 /* Create inheritable duplicate handles for our stdout/err */
473 if (handle == 0)
474 if (!DuplicateHandle(hProcess, GetStdHandle(STD_OUTPUT_HANDLE),
475 hProcess, &hChildStdoutWr, 0, TRUE /* inherited */,
476 DUPLICATE_SAME_ACCESS))
477 handle = -1;
478 if (handle == 0)
479 if (!DuplicateHandle(hProcess, GetStdHandle(STD_ERROR_HANDLE),
480 hProcess, &hChildStderrWr, 0, TRUE /* inherited */,
481 DUPLICATE_SAME_ACCESS))
482 handle = -1;
483
484 /* Set up members of STARTUPINFO structure. */
485 memset(&siStartInfo, 0, sizeof(STARTUPINFO));
486 siStartInfo.cb = sizeof(STARTUPINFO);
487 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
488 siStartInfo.hStdInput = hChildStdinRd;
489 siStartInfo.hStdOutput = hChildStdoutWr;
490 siStartInfo.hStdError = hChildStderrWr;
491
492 if (handle == 0) {
493 command = (char *)malloc(strlen(cmd)+1);
494 if (command)
495 strcpy(command, cmd);
496 else
497 handle = -1;
498 }
499
500 if (handle == 0)
501 if (!CreateProcess(NULL,
502 command, /* command line */
503 NULL, /* process security attributes */
504 NULL, /* primary thread security attributes */
505 TRUE, /* handles are inherited */
506 0, /* creation flags */
507 NULL, /* environment */
508 NULL, /* use parent's current directory */
509 &siStartInfo, /* STARTUPINFO pointer */
510 &piProcInfo)) /* receives PROCESS_INFORMATION */
511 {
512 handle = -1;
513 }
514 else {
515 CloseHandle(piProcInfo.hProcess);
516 CloseHandle(piProcInfo.hThread);
517 handle = _open_osfhandle((long)hChildStdinWr, 0);
518 }
519
520 if (hChildStdinRd != INVALID_HANDLE_VALUE)
521 CloseHandle(hChildStdinRd); /* close our copy */
522 if (hChildStdoutWr != INVALID_HANDLE_VALUE)
523 CloseHandle(hChildStdoutWr); /* close our copy */
524 if (hChildStderrWr != INVALID_HANDLE_VALUE)
525 CloseHandle(hChildStderrWr); /* close our copy */
526 if (command)
527 free(command);
528
529 if (handle < 0) {
530 if (hChildStdinWr != INVALID_HANDLE_VALUE)
531 CloseHandle(hChildStdinWr);
532 }
533 else {
534 pipe = _fdopen(handle, "wb");
535 if (pipe == NULL)
536 _close(handle);
537 }
538 return pipe;
539 }
540
541
542 /* ------ File naming and accessing ------ */
543
544 /* Create and open a scratch file with a given name prefix. */
545 /* Write the actual file name at fname. */
546 FILE *
gp_open_scratch_file(const char * prefix,char * fname,const char * mode)547 gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
548 {
549 UINT n;
550 DWORD l;
551 HANDLE hfile = INVALID_HANDLE_VALUE;
552 int fd = -1;
553 FILE *f = NULL;
554 char sTempDir[_MAX_PATH];
555 char sTempFileName[_MAX_PATH];
556
557 memset(fname, 0, gp_file_name_sizeof);
558 if (!gp_file_name_is_absolute(prefix, strlen(prefix))) {
559 int plen = sizeof(sTempDir);
560
561 if (gp_gettmpdir(sTempDir, &plen) != 0)
562 l = GetTempPath(sizeof(sTempDir), sTempDir);
563 else
564 l = strlen(sTempDir);
565 } else {
566 strncpy(sTempDir, prefix, sizeof(sTempDir));
567 prefix = "";
568 l = strlen(sTempDir);
569 }
570 /* Fix the trailing terminator so GetTempFileName doesn't get confused */
571 if (sTempDir[l-1] == '/')
572 sTempDir[l-1] = '\\'; /* What Windoze prefers */
573
574 if (l <= sizeof(sTempDir)) {
575 n = GetTempFileName(sTempDir, prefix, 0, sTempFileName);
576 if (n == 0) {
577 /* If 'prefix' is not a directory, it is a path prefix. */
578 int l = strlen(sTempDir), i;
579
580 for (i = l - 1; i > 0; i--) {
581 uint slen = gs_file_name_check_separator(sTempDir + i, l, sTempDir + l);
582
583 if (slen > 0) {
584 sTempDir[i] = 0;
585 i += slen;
586 break;
587 }
588 }
589 if (i > 0)
590 n = GetTempFileName(sTempDir, sTempDir + i, 0, sTempFileName);
591 }
592 if (n != 0) {
593 hfile = CreateFile(sTempFileName,
594 GENERIC_READ | GENERIC_WRITE | DELETE,
595 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
596 FILE_ATTRIBUTE_NORMAL /* | FILE_FLAG_DELETE_ON_CLOSE */,
597 NULL);
598 /*
599 * Can't apply FILE_FLAG_DELETE_ON_CLOSE due to
600 * the logics of clist_fclose. Also note that
601 * gdev_prn_render_pages requires multiple temporary files
602 * to exist simultaneousely, so that keeping all them opened
603 * may exceed available CRTL file handles.
604 */
605 }
606 }
607 if (hfile != INVALID_HANDLE_VALUE) {
608 /* Associate a C file handle with an OS file handle. */
609 fd = _open_osfhandle((long)hfile, 0);
610 if (fd == -1)
611 CloseHandle(hfile);
612 else {
613 /* Associate a C file stream with C file handle. */
614 f = fdopen(fd, mode);
615 if (f == NULL)
616 _close(fd);
617 }
618 }
619 if (f != NULL) {
620 if ((strlen(sTempFileName) < gp_file_name_sizeof))
621 strncpy(fname, sTempFileName, gp_file_name_sizeof - 1);
622 else {
623 /* The file name is too long. */
624 fclose(f);
625 f = NULL;
626 }
627 }
628 if (f == NULL)
629 eprintf1("**** Could not open temporary file '%s'\n", fname);
630 return f;
631 }
632
633 /* Open a file with the given name, as a stream of uninterpreted bytes. */
634 FILE *
gp_fopen(const char * fname,const char * mode)635 gp_fopen(const char *fname, const char *mode)
636 {
637 return fopen(fname, mode);
638 }
639
640 /* ------ Font enumeration ------ */
641
642 /* This is used to query the native os for a list of font names and
643 * corresponding paths. The general idea is to save the hassle of
644 * building a custom fontmap file.
645 */
646
gp_enumerate_fonts_init(gs_memory_t * mem)647 void *gp_enumerate_fonts_init(gs_memory_t *mem)
648 {
649 return NULL;
650 }
651
gp_enumerate_fonts_next(void * enum_state,char ** fontname,char ** path)652 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
653 {
654 return 0;
655 }
656
gp_enumerate_fonts_free(void * enum_state)657 void gp_enumerate_fonts_free(void *enum_state)
658 {
659 }
660
661 /* --------- 64 bit file access ----------- */
662 /* MSVC versions before 8 doen't provide big files.
663 MSVC 8 doesn't distinguish big and small files,
664 but provide special positioning functions
665 to access data behind 4GB.
666 Currently we support 64 bits file access with MSVC only.
667 */
668
gp_fopen_64(const char * filename,const char * mode)669 FILE *gp_fopen_64(const char *filename, const char *mode)
670 {
671 return fopen(filename, mode);
672 }
673
gp_open_scratch_file_64(const char * prefix,char fname[gp_file_name_sizeof],const char * mode)674 FILE *gp_open_scratch_file_64(const char *prefix,
675 char fname[gp_file_name_sizeof],
676 const char *mode)
677 {
678 return gp_open_scratch_file(prefix, fname, mode);
679 }
680
gp_open_printer_64(char fname[gp_file_name_sizeof],int binary_mode)681 FILE *gp_open_printer_64(char fname[gp_file_name_sizeof], int binary_mode)
682 {
683 /* Assuming gp_open_scratch_file_64 is same as gp_open_scratch_file -
684 see the body of gp_open_printer. */
685 return gp_open_printer(fname, binary_mode);
686 }
687
688 #if defined(_MSC_VER) && _MSC_VER < 1400
689 int64_t _ftelli64( FILE *);
690 int _fseeki64( FILE *, int64_t, int);
691 #endif
692
gp_ftell_64(FILE * strm)693 int64_t gp_ftell_64(FILE *strm)
694 {
695 #if !defined(_MSC_VER)
696 return ftell(strm);
697 #elif _MSC_VER < 1200
698 return ftell(strm);
699 #else
700 return (int64_t)_ftelli64(strm);
701 #endif
702 }
703
gp_fseek_64(FILE * strm,int64_t offset,int origin)704 int gp_fseek_64(FILE *strm, int64_t offset, int origin)
705 {
706 #if !defined(_MSC_VER)
707 return fseek(strm, offset, origin);
708 #elif _MSC_VER < 1200
709 long offset1 = (long)offset;
710
711 if (offset != offset1)
712 return -1;
713 return fseek(strm, offset1, origin);
714 #else
715 return _fseeki64(strm, offset, origin);
716 #endif
717 }
718
719 /* ------------------------- _snprintf -----------------------------*/
720
721 /* Microsoft Visual C++ 2005 doesn't properly define snprintf,
722 which is defined in the C standard ISO/IEC 9899:1999 (E) */
723
snprintf(char * buffer,size_t count,const char * format,...)724 int snprintf(char *buffer, size_t count, const char *format, ...)
725 {
726 if (count > 0) {
727 va_list args;
728 int n;
729
730 va_start(args, format);
731 n = _vsnprintf(buffer, count, format, args);
732 buffer[count - 1] = 0;
733 va_end(args);
734 return n;
735 } else
736 return 0;
737 }
738