xref: /plan9/sys/src/cmd/gs/src/gp_os2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises.  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_os2.c,v 1.32 2004/09/27 21:14:00 ghostgum Exp $ */
18 /* Common platform-specific routines for OS/2 and MS-DOS */
19 /* compiled with GCC/EMX */
20 
21 #define INCL_DOS
22 #define INCL_SPL
23 #define INCL_SPLDOSPRINT
24 #define INCL_SPLERRORS
25 #define INCL_BASE
26 #define INCL_ERRORS
27 #define INCL_WIN
28 #include <os2.h>
29 
30 #include "pipe_.h"
31 #include "stdio_.h"
32 #include "string_.h"
33 #include <fcntl.h>
34 
35 #ifdef __IBMC__
36 #define popen fopen		/* doesn't support popen */
37 #define pclose fclose		/* doesn't support pclose */
38 #else
39 #include <dos.h>
40 #endif
41 /* Define the regs union tag for short registers. */
42 #  define rshort x
43 #define intdos(a,b) _int86(0x21, a, b)
44 
45 #include "memory_.h"
46 #include "string_.h"
47 #include "gx.h"
48 #include "gsexit.h"
49 #include "gsmemory.h"
50 #include "gsstruct.h"
51 #include "gp.h"
52 #include "gpmisc.h"
53 #include "gsutil.h"
54 #include "stdlib.h"		/* need _osmode, exit */
55 #include "time_.h"
56 #include <time.h>		/* should this be in time_.h? */
57 #include "gp_os2.h"
58 #include "gdevpm.h"
59 #ifdef __EMX__
60 #include <sys/emxload.h>
61 #endif
62 
63 #if defined(__DLL__) && defined( __EMX__)
64 /* This isn't provided in any of the libraries */
65 /* We set this to the process environment in gp_init */
66 char *fake_environ[3] =
67 {"", NULL, NULL};
68 char **environ = fake_environ;
69 char **_environ = fake_environ;
70 HWND hwndtext = (HWND) NULL;
71 
72 #endif
73 
74 #ifdef __DLL__
75 /* use longjmp instead of exit when using DLL */
76 #include <setjmp.h>
77 extern jmp_buf gsdll_env;
78 
79 #endif
80 
81 #ifdef __DLL__
82 #define isos2 TRUE
83 #else
84 #define isos2 (_osmode == OS2_MODE)
85 #endif
86 char pm_prntmp[256];		/* filename of printer spool temporary file */
87 
88 
89 /* ------ Miscellaneous ------ */
90 
91 /* Get the string corresponding to an OS error number. */
92 /* All reasonable compilers support it. */
93 const char *
gp_strerror(int errnum)94 gp_strerror(int errnum)
95 {
96     return strerror(errnum);
97 }
98 
99 /* use Unix version for date and time */
100 /* ------ Date and time ------ */
101 
102 /* Read the current time (in seconds since Jan. 1, 1970) */
103 /* and fraction (in nanoseconds since midnight). */
104 void
gp_get_realtime(long * pdt)105 gp_get_realtime(long *pdt)
106 {
107     struct timeval tp;
108     struct timezone tzp;
109 
110     if (gettimeofday(&tp, &tzp) == -1) {
111 	lprintf("Ghostscript: gettimeofday failed!\n");
112 	tp.tv_sec = tp.tv_usec = 0;
113     }
114     /* tp.tv_sec is #secs since Jan 1, 1970 */
115     pdt[0] = tp.tv_sec;
116     pdt[1] = tp.tv_usec * 1000;
117 
118 #ifdef DEBUG_CLOCK
119     printf("tp.tv_sec = %d  tp.tv_usec = %d  pdt[0] = %ld  pdt[1] = %ld\n",
120 	   tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]);
121 #endif
122 }
123 
124 /* Read the current user CPU time (in seconds) */
125 /* and fraction (in nanoseconds).  */
126 void
gp_get_usertime(long * pdt)127 gp_get_usertime(long *pdt)
128 {
129     gp_get_realtime(pdt);	/* Use an approximation for now.  */
130 }
131 
132 
133 /* ------ Console management ------ */
134 
135 /* Answer whether a given file is the console (input or output). */
136 /* This is not a standard gp procedure, */
137 /* but the MS Windows configuration needs it, */
138 /* and other MS-DOS configurations might need it someday. */
139 /* Don't know if it is needed for OS/2. */
140 bool
gp_file_is_console(FILE * f)141 gp_file_is_console(FILE * f)
142 {
143 #ifndef __DLL__
144     if (!isos2) {
145 	union REGS regs;
146 
147 	if (f == NULL)
148 	    return false;
149 	regs.h.ah = 0x44;	/* ioctl */
150 	regs.h.al = 0;		/* get device info */
151 	regs.rshort.bx = fileno(f);
152 	intdos(&regs, &regs);
153 	return ((regs.h.dl & 0x80) != 0 && (regs.h.dl & 3) != 0);
154     }
155 #endif
156     if (fileno(f) <= 2)
157 	return true;
158     return false;
159 }
160 
161 /* ------ Persistent data cache ------*/
162 
163 /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)164 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
165 {
166     /* not yet implemented */
167     return 0;
168 }
169 
170 /* 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)171 int gp_cache_query(int type, byte* key, int keylen, void **buffer,
172     gp_cache_alloc alloc, void *userdata)
173 {
174     /* not yet implemented */
175     return -1;
176 }
177 
178 /* ------ File naming and accessing ------ */
179 
180 /* Define the character used for separating file names in a list. */
181 const char gp_file_name_list_separator = ';';
182 
183 /* Define the default scratch file name prefix. */
184 const char gp_scratch_file_name_prefix[] = "gs";
185 
186 /* Define the name of the null output file. */
187 const char gp_null_file_name[] = "nul";
188 
189 /* Define the name that designates the current directory. */
190 const char gp_current_directory_name[] = ".";
191 
192 /* Define the string to be concatenated with the file mode */
193 /* for opening files without end-of-line conversion. */
194 const char gp_fmode_binary_suffix[] = "b";
195 
196 /* Define the file modes for binary reading or writing. */
197 const char gp_fmode_rb[] = "rb";
198 const char gp_fmode_wb[] = "wb";
199 
200 /* ------ File enumeration ------ */
201 
202 
203 struct file_enum_s {
204     FILEFINDBUF3 findbuf;
205     HDIR hdir;
206     char *pattern;
207     int patlen;			/* orig pattern length */
208     int pat_size;		/* allocate space for pattern */
209     int head_size;		/* pattern length through last */
210     /* :, / or \ */
211     int first_time;
212     gs_memory_t *memory;
213 };
214 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
215 		    file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
216 
217 /* Initialize an enumeration.  may NEED WORK ON HANDLING * ? \. */
218 file_enum *
gp_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)219 gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
220 {
221     file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
222     int pat_size = 2 * patlen + 1;
223     char *pattern;
224     int hsize = 0;
225     int i;
226 
227     if (pfen == 0)
228 	return 0;
229 
230     /* pattern could be allocated as a string, */
231     /* but it's simpler for GC and freeing to allocate it as bytes. */
232 
233     pattern = (char *)gs_alloc_bytes(mem, pat_size,
234 				     "gp_enumerate_files(pattern)");
235     if (pattern == 0)
236 	return 0;
237     memcpy(pattern, pat, patlen);
238     /* find directory name = header */
239     for (i = 0; i < patlen; i++) {
240 	switch (pat[i]) {
241 	    case '\\':
242 		if (i + 1 < patlen && pat[i + 1] == '\\')
243 		    i++;
244 		/* falls through */
245 	    case ':':
246 	    case '/':
247 		hsize = i + 1;
248 	}
249     }
250     pattern[patlen] = 0;
251     pfen->pattern = pattern;
252     pfen->patlen = patlen;
253     pfen->pat_size = pat_size;
254     pfen->head_size = hsize;
255     pfen->memory = mem;
256     pfen->first_time = 1;
257     pfen->hdir = HDIR_CREATE;
258     return pfen;
259 }
260 
261 /* Enumerate the next file. */
262 uint
gp_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)263 gp_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
264 {
265     APIRET rc;
266     ULONG cFilenames = 1;
267 
268     if (!isos2) {
269 	/* CAN'T DO IT SO JUST RETURN THE PATTERN. */
270 	if (pfen->first_time) {
271 	    char *pattern = pfen->pattern;
272 	    uint len = strlen(pattern);
273 
274 	    pfen->first_time = 0;
275 	    if (len > maxlen)
276 		return maxlen + 1;
277 	    strcpy(ptr, pattern);
278 	    return len;
279 	}
280 	return -1;
281     }
282     /* else OS/2 */
283     if (pfen->first_time) {
284 	rc = DosFindFirst(pfen->pattern, &pfen->hdir, FILE_NORMAL,
285 			  &pfen->findbuf, sizeof(pfen->findbuf),
286 			  &cFilenames, FIL_STANDARD);
287 	pfen->first_time = 0;
288     } else {
289 	rc = DosFindNext(pfen->hdir, &pfen->findbuf, sizeof(pfen->findbuf),
290 			 &cFilenames);
291     }
292     if (rc)
293 	return -1;
294 
295     if (pfen->head_size + pfen->findbuf.cchName < maxlen) {
296 	memcpy(ptr, pfen->pattern, pfen->head_size);
297 	strcpy(ptr + pfen->head_size, pfen->findbuf.achName);
298 	return pfen->head_size + pfen->findbuf.cchName;
299     }
300     if (pfen->head_size >= maxlen)
301 	return 0;		/* no hope at all */
302 
303     memcpy(ptr, pfen->pattern, pfen->head_size);
304     strncpy(ptr + pfen->head_size, pfen->findbuf.achName,
305 	    maxlen - pfen->head_size - 1);
306     return maxlen;
307 }
308 
309 /* Clean up the file enumeration. */
310 void
gp_enumerate_files_close(file_enum * pfen)311 gp_enumerate_files_close(file_enum * pfen)
312 {
313     gs_memory_t *mem = pfen->memory;
314 
315     if (isos2)
316 	DosFindClose(pfen->hdir);
317     gs_free_object(mem, pfen->pattern,
318 		   "gp_enumerate_files_close(pattern)");
319     gs_free_object(mem, pfen, "gp_enumerate_files_close");
320 }
321 
322 /*************************************************************/
323 /* from gp_iwatc.c and gp_itbc.c */
324 
325 /* Intel processor, EMX/GCC specific routines for Ghostscript */
326 #include <signal.h>
327 #include "stat_.h"
328 #include "string_.h"
329 
330 /* Library routines not declared in a standard header */
331 /* extern char *getenv(const char *); */
332 
333 /* Forward declarations */
334 private void handle_FPE(int);
335 
336 /* Do platform-dependent initialization. */
337 void
gp_init(void)338 gp_init(void)
339 {
340 #if defined(__DLL__) && defined(__EMX__)
341     PTIB pptib;
342     PPIB pppib;
343     int i;
344     char *p;
345 
346     /* get environment of EXE */
347     DosGetInfoBlocks(&pptib, &pppib);
348     for (i = 0, p = pppib->pib_pchenv; *p; p += strlen(p) + 1)
349 	i++;
350     _environ = environ = (char **)malloc((i + 2) * sizeof(char *));
351 
352     for (i = 0, p = pppib->pib_pchenv; *p; p += strlen(p) + 1) {
353 	environ[i] = p;
354 	i++;
355     }
356     environ[i] = p;
357     i++;
358     environ[i] = NULL;
359 #endif
360 
361     /* keep gsos2.exe in memory for number of minutes specified in */
362     /* environment variable GS_LOAD */
363 #ifdef __EMX__
364     _emxload_env("GS_LOAD");
365 #endif
366 
367     /* Set up the handler for numeric exceptions. */
368     signal(SIGFPE, handle_FPE);
369 }
370 
371 
372 /* Trap numeric exceptions.  Someday we will do something */
373 /* more appropriate with these. */
374 private void
handle_FPE(int sig)375 handle_FPE(int sig)
376 {
377     eprintf("Numeric exception:\n");
378     exit(1);
379 }
380 
381 /* Do platform-dependent cleanup. */
382 void
gp_exit(int exit_status,int code)383 gp_exit(int exit_status, int code)
384 {
385 #if defined(__DLL__) && defined(__EMX__)
386     if (environ != fake_environ) {
387 	free(environ);
388 	environ = _environ = fake_environ;
389     }
390 #endif
391 }
392 
393 /* Exit the program. */
394 void
gp_do_exit(int exit_status)395 gp_do_exit(int exit_status)
396 {
397     exit(exit_status);
398 }
399 
400 /* ------ Printer accessing ------ */
401 private int is_os2_spool(const char *queue);
402 
403 /* Put a printer file (which might be stdout) into binary or text mode. */
404 /* This is not a standard gp procedure, */
405 /* but all MS-DOS configurations need it. */
406 void
gp_set_file_binary(int prnfno,int binary)407 gp_set_file_binary(int prnfno, int binary)
408 {
409 #ifndef __IBMC__
410     union REGS regs;
411 
412     regs.h.ah = 0x44;		/* ioctl */
413     regs.h.al = 0;		/* get device info */
414     regs.rshort.bx = prnfno;
415     intdos(&regs, &regs);
416     if (((regs.rshort.flags) & 1) != 0 || !(regs.h.dl & 0x80))
417 	return;			/* error, or not a device */
418     if (binary)
419 	regs.h.dl |= 0x20;	/* binary (no ^Z intervention) */
420     else
421 	regs.h.dl &= ~0x20;	/* text */
422     regs.h.dh = 0;
423     regs.h.ah = 0x44;		/* ioctl */
424     regs.h.al = 1;		/* set device info */
425     intdos(&regs, &regs);
426 #endif
427 }
428 
429 /* Open a connection to a printer.  A null file name means use the */
430 /* standard printer connected to the machine, if any. */
431 /* Return NULL if the connection could not be opened. */
432 /* filename can be one of the following values
433  *   ""                Spool in default queue
434  *   "\\spool\queue"   Spool in "queue"
435  *   "|command"        open an output pipe using popen()
436  *   "filename"        open filename using fopen()
437  *   "port"            open port using fopen()
438  */
439 FILE *
gp_open_printer(char fname[gp_file_name_sizeof],int binary_mode)440 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
441 {
442     FILE *pfile;
443 
444     if ((strlen(fname) == 0) || is_os2_spool(fname)) {
445 	if (isos2) {
446 	    /* default or spool */
447 	    if (pm_spool(NULL, fname))	/* check if spool queue valid */
448 		return NULL;
449 	    pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
450 				     pm_prntmp, (binary_mode ? "wb" : "w"));
451 	} else
452 	    pfile = fopen("PRN", (binary_mode ? "wb" : "w"));
453     } else if ((isos2) && (fname[0] == '|'))
454 	/* pipe */
455 	pfile = popen(fname + 1, (binary_mode ? "wb" : "w"));
456     else
457 	/* normal file or port */
458 	pfile = fopen(fname, (binary_mode ? "wb" : "w"));
459 
460     if (pfile == (FILE *) NULL)
461 	return (FILE *) NULL;
462     if (!isos2)
463 	gp_set_file_binary(fileno(pfile), binary_mode);
464     return pfile;
465 }
466 
467 /* Close the connection to the printer. */
468 void
gp_close_printer(FILE * pfile,const char * fname)469 gp_close_printer(FILE * pfile, const char *fname)
470 {
471     if (isos2 && (fname[0] == '|'))
472 	pclose(pfile);
473     else
474 	fclose(pfile);
475 
476     if ((strlen(fname) == 0) || is_os2_spool(fname)) {
477 	/* spool temporary file */
478 	pm_spool(pm_prntmp, fname);
479 	unlink(pm_prntmp);
480     }
481 }
482 
483 /* ------ File accessing -------- */
484 
485 /* Set a file into binary or text mode. */
486 int
gp_setmode_binary(FILE * pfile,bool binary)487 gp_setmode_binary(FILE * pfile, bool binary)
488 {
489     gp_set_file_binary(fileno(pfile), binary);
490     return 0;
491 }
492 
493 /* ------ Printer Spooling ------ */
494 #ifndef NERR_BufTooSmall
495 #define NERR_BufTooSmall 2123	/* For SplEnumQueue */
496 #endif
497 
498 /* If queue_name is NULL, list available queues */
499 /* If strlen(queue_name)==0, return default queue and driver name */
500 /* If queue_name supplied, return driver_name */
501 /* returns 0 if OK, non-zero for error */
502 int
pm_find_queue(char * queue_name,char * driver_name)503 pm_find_queue(char *queue_name, char *driver_name)
504 {
505     SPLERR splerr;
506     USHORT jobCount;
507     ULONG cbBuf;
508     ULONG cTotal;
509     ULONG cReturned;
510     ULONG cbNeeded;
511     ULONG ulLevel;
512     ULONG i;
513     PSZ pszComputerName;
514     PBYTE pBuf;
515     PPRQINFO3 prq;
516 
517     ulLevel = 3L;
518     pszComputerName = (PSZ) NULL;
519     splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L,	/* cbBuf */
520 			  &cReturned, &cTotal,
521 			  &cbNeeded, NULL);
522     if (splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall) {
523 	if (!DosAllocMem((PVOID) & pBuf, cbNeeded,
524 			 PAG_READ | PAG_WRITE | PAG_COMMIT)) {
525 	    cbBuf = cbNeeded;
526 	    splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
527 				  &cReturned, &cTotal,
528 				  &cbNeeded, NULL);
529 	    if (splerr == NO_ERROR) {
530 		/* Set pointer to point to the beginning of the buffer.           */
531 		prq = (PPRQINFO3) pBuf;
532 
533 		/* cReturned has the count of the number of PRQINFO3 structures.  */
534 		for (i = 0; i < cReturned; i++) {
535 		    if (queue_name) {
536 			/* find queue name and return driver name */
537 			if (strlen(queue_name) == 0) {	/* use default queue */
538 			    if (prq->fsType & PRQ3_TYPE_APPDEFAULT)
539 				strcpy(queue_name, prq->pszName);
540 			}
541 			if (strcmp(prq->pszName, queue_name) == 0) {
542 			    char *p;
543 
544 			    for (p = prq->pszDriverName; *p && (*p != '.'); p++)
545 				/* do nothing */ ;
546 			    *p = '\0';	/* truncate at '.' */
547 			    if (driver_name != NULL)
548 				strcpy(driver_name, prq->pszDriverName);
549 			    DosFreeMem((PVOID) pBuf);
550 			    return 0;
551 			}
552 		    } else {
553 			/* list queue details */
554 			if (prq->fsType & PRQ3_TYPE_APPDEFAULT)
555 			    eprintf1("  \042%s\042  (DEFAULT)\n", prq->pszName);
556 			else
557 			    eprintf1("  \042%s\042\n", prq->pszName);
558 		    }
559 		    prq++;
560 		}		/*endfor cReturned */
561 	    }
562 	    DosFreeMem((PVOID) pBuf);
563 	}
564     }
565     /* end if Q level given */
566     else {
567 	/* If we are here we had a bad error code. Print it and some other info. */
568 	eprintf4("SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
569 		splerr, cTotal, cReturned, cbNeeded);
570     }
571     if (splerr)
572 	return splerr;
573     if (queue_name)
574 	return -1;
575     return 0;
576 }
577 
578 
579 /* return TRUE if queue looks like a valid OS/2 queue name */
580 private int
is_os2_spool(const char * queue)581 is_os2_spool(const char *queue)
582 {
583     char *prefix = "\\\\spool\\";	/* 8 characters long */
584     int i;
585 
586     for (i = 0; i < 8; i++) {
587 	if (prefix[i] == '\\') {
588 	    if ((*queue != '\\') && (*queue != '/'))
589 		return FALSE;
590 	} else if (tolower(*queue) != prefix[i])
591 	    return FALSE;
592 	queue++;
593     }
594     return TRUE;
595 }
596 
597 #define PRINT_BUF_SIZE 16384
598 
599 /* Spool file to queue */
600 /* return 0 if successful, non-zero if error */
601 /* if filename is NULL, return 0 if spool queue is valid, non-zero if error */
602 int
pm_spool(char * filename,const char * queue)603 pm_spool(char *filename, const char *queue)
604 {
605     HSPL hspl;
606     PDEVOPENSTRUC pdata;
607     PSZ pszToken = "*";
608     ULONG jobid;
609     BOOL rc;
610     char queue_name[256];
611     char driver_name[256];
612     char *buffer;
613     FILE *f;
614     int count;
615 
616     if (strlen(queue) != 0) {
617 	/* queue specified */
618 	strcpy(queue_name, queue + 8);	/* skip over \\spool\ */
619     } else {
620 	/* get default queue */
621 	queue_name[0] = '\0';
622     }
623     if (pm_find_queue(queue_name, driver_name)) {
624 	/* error, list valid queue names */
625 	eprintf("Invalid queue name.  Use one of:\n");
626 	pm_find_queue(NULL, NULL);
627 	return 1;
628     }
629     if (!filename)
630 	return 0;		/* we were only asked to check the queue */
631 
632 
633     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL) {
634 	eprintf("Out of memory in pm_spool\n");
635 	return 1;
636     }
637     if ((f = fopen(filename, "rb")) == (FILE *) NULL) {
638 	free(buffer);
639 	eprintf1("Can't open temporary file %s\n", filename);
640 	return 1;
641     }
642     /* Allocate memory for pdata */
643     if (!DosAllocMem((PVOID) & pdata, sizeof(DEVOPENSTRUC),
644 		     (PAG_READ | PAG_WRITE | PAG_COMMIT))) {
645 	/* Initialize elements of pdata */
646 	pdata->pszLogAddress = queue_name;
647 	pdata->pszDriverName = driver_name;
648 	pdata->pdriv = NULL;
649 	pdata->pszDataType = "PM_Q_RAW";
650 	pdata->pszComment = "Ghostscript";
651 	pdata->pszQueueProcName = NULL;
652 	pdata->pszQueueProcParams = NULL;
653 	pdata->pszSpoolerParams = NULL;
654 	pdata->pszNetworkParams = NULL;
655 
656 	hspl = SplQmOpen(pszToken, 4L, (PQMOPENDATA) pdata);
657 	if (hspl == SPL_ERROR) {
658 	    eprintf("SplQmOpen failed.\n");
659 	    DosFreeMem((PVOID) pdata);
660 	    free(buffer);
661 	    fclose(f);
662 	    return 1;		/* failed */
663 	}
664 	rc = SplQmStartDoc(hspl, "Ghostscript");
665 	if (!rc) {
666 	    eprintf("SplQmStartDoc failed.\n");
667 	    DosFreeMem((PVOID) pdata);
668 	    free(buffer);
669 	    fclose(f);
670 	    return 1;
671 	}
672 	/* loop, copying file to queue */
673 	while (rc && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0) {
674 	    rc = SplQmWrite(hspl, count, buffer);
675 	    if (!rc)
676 		eprintf("SplQmWrite failed.\n");
677 	}
678 	free(buffer);
679 	fclose(f);
680 
681 	if (!rc) {
682 	    eprintf("Aborting Spooling.\n");
683 	    SplQmAbort(hspl);
684 	} else {
685 	    SplQmEndDoc(hspl);
686 	    rc = SplQmClose(hspl);
687 	    if (!rc)
688 		eprintf("SplQmClose failed.\n");
689 	}
690     } else
691 	rc = 0;			/* no memory */
692     return !rc;
693 }
694 
695 /* ------ File naming and accessing ------ */
696 
697 /* Create and open a scratch file with a given name prefix. */
698 /* Write the actual file name at fname. */
699 FILE *
gp_open_scratch_file(const char * prefix,char fname[gp_file_name_sizeof],const char * mode)700 gp_open_scratch_file(const char *prefix, char fname[gp_file_name_sizeof],
701 		     const char *mode)
702 {
703     FILE *f;
704 #ifdef __IBMC__
705     char *temp = 0;
706     char *tname;
707     int prefix_length = strlen(prefix);
708 
709     if (!gp_file_name_is_absolute(prefix, prefix_length)) {
710 	temp = getenv("TMPDIR");
711 	if (temp == 0)
712 	    temp = getenv("TEMP");
713     }
714     *fname = 0;
715     tname = _tempnam(temp, (char *)prefix);
716     if (tname) {
717 	if (strlen(tname) > gp_file_name_sizeof - 1) {
718 	    free(tname);
719 	    return 0;		/* file name too long */
720 	}
721 	strcpy(fname, tname);
722 	free(tname);
723     }
724 #else
725     /* The -7 is for XXXXXX plus a possible final \. */
726     int prefix_length = strlen(prefix);
727     int len = gp_file_name_sizeof - prefix_length - 7;
728 
729     if (gp_file_name_is_absolute(prefix, prefix_length) ||
730 	gp_gettmpdir(fname, &len) != 0)
731 	*fname = 0;
732     else {
733 	char last = '\\';
734 	char *temp;
735 
736 	/* Prevent X's in path from being converted by mktemp. */
737 	for (temp = fname; *temp; temp++)
738 	    *temp = last = tolower(*temp);
739 	switch (last) {
740 	default:
741 	    strcat(fname, "\\");
742 	case ':':
743 	case '\\':
744 	    ;
745 	}
746     }
747     if (strlen(fname) + prefix_length + 7 >= gp_file_name_sizeof)
748 	return 0;		/* file name too long */
749     strcat(fname, prefix);
750     strcat(fname, "XXXXXX");
751     mktemp(fname);
752 #endif
753     f = gp_fopentemp(fname, mode);
754     if (f == NULL)
755 	eprintf1("**** Could not open temporary file %s\n", fname);
756     return f;
757 }
758 
759 /* Open a file with the given name, as a stream of uninterpreted bytes. */
760 FILE *
gp_fopen(const char * fname,const char * mode)761 gp_fopen(const char *fname, const char *mode)
762 {
763     return fopen(fname, mode);
764 }
765 
766 /* -------------- Helpers for gp_file_name_combine_generic ------------- */
767 
gp_file_name_root(const char * fname,uint len)768 uint gp_file_name_root(const char *fname, uint len)
769 {   int i = 0;
770 
771     if (len == 0)
772 	return 0;
773     if (len > 1 && fname[0] == '\\' && fname[1] == '\\') {
774 	/* A network path: "\\server\share\" */
775 	int k = 0;
776 
777 	for (i = 2; i < len; i++)
778 	    if (fname[i] == '\\' || fname[i] == '/')
779 		if (k++) {
780 		    i++;
781 		    break;
782 		}
783     } else if (fname[0] == '/' || fname[0] == '\\') {
784 	/* Absolute with no drive. */
785 	i = 1;
786     } else if (len > 1 && fname[1] == ':') {
787 	/* Absolute with a drive. */
788 	i = (len > 2 && (fname[2] == '/' || fname[2] == '\\') ? 3 : 2);
789     }
790     return i;
791 }
792 
gs_file_name_check_separator(const char * fname,int len,const char * item)793 uint gs_file_name_check_separator(const char *fname, int len, const char *item)
794 {   if (len > 0) {
795 	if (fname[0] == '/' || fname[0] == '\\')
796 	    return 1;
797     } else if (len < 0) {
798 	if (fname[-1] == '/' || fname[-1] == '\\')
799 	    return 1;
800     }
801     return 0;
802 }
803 
gp_file_name_is_parent(const char * fname,uint len)804 bool gp_file_name_is_parent(const char *fname, uint len)
805 {   return len == 2 && fname[0] == '.' && fname[1] == '.';
806 }
807 
gp_file_name_is_current(const char * fname,uint len)808 bool gp_file_name_is_current(const char *fname, uint len)
809 {   return len == 1 && fname[0] == '.';
810 }
811 
gp_file_name_separator(void)812 const char *gp_file_name_separator(void)
813 {   return "/";
814 }
815 
gp_file_name_directory_separator(void)816 const char *gp_file_name_directory_separator(void)
817 {   return "/";
818 }
819 
gp_file_name_parent(void)820 const char *gp_file_name_parent(void)
821 {   return "..";
822 }
823 
gp_file_name_current(void)824 const char *gp_file_name_current(void)
825 {   return ".";
826 }
827 
gp_file_name_is_partent_allowed(void)828 bool gp_file_name_is_partent_allowed(void)
829 {   return true;
830 }
831 
gp_file_name_is_empty_item_meanful(void)832 bool gp_file_name_is_empty_item_meanful(void)
833 {   return false;
834 }
835 
836 gp_file_name_combine_result
gp_file_name_combine(const char * prefix,uint plen,const char * fname,uint flen,bool no_sibling,char * buffer,uint * blen)837 gp_file_name_combine(const char *prefix, uint plen, const char *fname, uint flen,
838 		    bool no_sibling, char *buffer, uint *blen)
839 {
840     return gp_file_name_combine_generic(prefix, plen,
841 	    fname, flen, no_sibling, buffer, blen);
842 }
843 
844 /* ------ Font enumeration ------ */
845 
846  /* This is used to query the native os for a list of font names and
847   * corresponding paths. The general idea is to save the hassle of
848   * building a custom fontmap file.
849   */
850 
gp_enumerate_fonts_init(gs_memory_t * mem)851 void *gp_enumerate_fonts_init(gs_memory_t *mem)
852 {
853     return NULL;
854 }
855 
gp_enumerate_fonts_next(void * enum_state,char ** fontname,char ** path)856 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
857 {
858     return 0;
859 }
860 
gp_enumerate_fonts_free(void * enum_state)861 void gp_enumerate_fonts_free(void *enum_state)
862 {
863 }
864