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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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