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_vms.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* VAX/VMS specific routines for Ghostscript */
16 
17 #include "string_.h"
18 #include "memory_.h"
19 #include "gx.h"
20 #include "gp.h"
21 #include "gpmisc.h"
22 #include "gsstruct.h"
23 #include <stat.h>
24 #include <stdlib.h>		/* for exit() with some compiler versions */
25 #include <errno.h>		/* for exit() with other compiler versions */
26 #include <unixio.h>
27 
28 extern char *getenv(const char *);
29 
30 /* Apparently gcc doesn't allow extra arguments for fopen: */
31 #ifdef VMS			/* DEC C */
32 #  define fopen_VMS fopen
33 #else /* gcc */
34 #  define fopen_VMS(name, mode, m1, m2) fopen(name, mode)
35 #endif
36 
37 
38 /* VMS string descriptor structure */
39 #define DSC$K_DTYPE_T 14
40 #define DSC$K_CLASS_S  1
41 struct dsc$descriptor_s {
42     unsigned short dsc$w_length;
43     unsigned char dsc$b_dtype;
44     unsigned char dsc$b_class;
45     char *dsc$a_pointer;
46 };
47 typedef struct dsc$descriptor_s descrip;
48 
49 /* VMS RMS constants */
50 #define RMS_IS_ERROR_OR_NMF(rmsv) (((rmsv) & 1) == 0)
51 #define RMS$_NMF    99018
52 #define RMS$_NORMAL 65537
53 #define NAM$C_MAXRSS  255
54 
55 struct file_enum_s {
56     uint context, length;
57     descrip pattern;
58     gs_memory_t *memory;
59 };
60 gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
61 	  file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern.dsc$a_pointer);
62 
63 extern uint
64     LIB$FIND_FILE(descrip *, descrip *, uint *, descrip *, descrip *,
65 		  uint *, uint *),
66     LIB$FIND_FILE_END(uint *),
67     SYS$FILESCAN(descrip *, uint *, uint *),
68     SYS$PUTMSG(uint *, int (*)(), descrip *, uint);
69 
70 static uint
strlength(char * str,uint maxlen,char term)71 strlength(char *str, uint maxlen, char term)
72 {
73     uint i = 0;
74 
75     while (i < maxlen && str[i] != term)
76 	i++;
77     return i;
78 }
79 
80 /* Do platform-dependent initialization. */
81 void
gp_init(void)82 gp_init(void)
83 {
84 }
85 
86 /* Do platform-dependent cleanup. */
87 void
gp_exit(int exit_status,int code)88 gp_exit(int exit_status, int code)
89 {
90 }
91 
92 /* Exit the program. */
93 void
gp_do_exit(int exit_status)94 gp_do_exit(int exit_status)
95 {				/* The program returns exit_status = 0 for OK, 1 for failure; */
96     /* VMS has different conventions. */
97     switch (exit_status) {
98 	case 0:
99 	    exit(exit_OK);
100 	case 1:
101 	    exit(exit_FAILED);
102     }
103     exit(exit_status);
104 }
105 
106 /* ------ Date and time ------ */
107 
108 /* Read the current time (in seconds since Jan. 1, 1980) */
109 /* and fraction (in nanoseconds). */
110 void
gp_get_realtime(long * pdt)111 gp_get_realtime(long *pdt)
112 {
113     struct {
114 	uint _l0, _l1;
115     } binary_date, now, difference;
116     long LIB$EDIV(), LIB$SUBX(), SYS$BINTIM(), SYS$GETTIM();
117     long units_per_second = 10000000;
118     char *jan_1_1980 = "1-JAN-1980 00:00:00.00";
119     descrip str_desc;
120 
121     /* For those interested, Wednesday, November 17, 1858 is the base
122        of the Modified Julian Day system adopted by the Smithsonian
123        Astrophysical Observatory in 1957 for satellite tracking.  (The
124        year 1858 preceded the oldest star catalog in use at the
125        observatory.)  VMS uses quadword time stamps which are offsets
126        in 100 nanosecond units from November 17, 1858.  With a 63-bit
127        absolute time representation (sign bit must be clear), VMS will
128        have no trouble with time until 31-JUL-31086 02:48:05.47. */
129 
130     /* Convert January 1, 1980 into a binary absolute time */
131     str_desc.dsc$w_length = strlen(jan_1_1980);
132     str_desc.dsc$a_pointer = jan_1_1980;
133     (void)SYS$BINTIM(&str_desc, &binary_date);
134 
135     /* Compute number of 100 nanosecond units since January 1, 1980.  */
136     (void)SYS$GETTIM(&now);
137     (void)LIB$SUBX(&now, &binary_date, &difference);
138 
139     /* Convert to seconds and nanoseconds.  */
140     (void)LIB$EDIV(&units_per_second, &difference, &pdt[0], &pdt[1]);
141     pdt[1] *= 100;
142 }
143 
144 /* Read the current user CPU time (in seconds) */
145 /* and fraction (in nanoseconds).  */
146 void
gp_get_usertime(long * pdt)147 gp_get_usertime(long *pdt)
148 {
149     gp_get_realtime(pdt);	/* Use an approximation for now.  */
150 }
151 
152 
153 /* ------ Persistent data cache ------*/
154 
155 /* insert a buffer under a (type, key) pair */
gp_cache_insert(int type,byte * key,int keylen,void * buffer,int buflen)156 int gp_cache_insert(int type, byte *key, int keylen, void *buffer, int buflen)
157 {
158     /* not yet implemented */
159     return 0;
160 }
161 
162 /* 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)163 int gp_cache_query(int type, byte* key, int keylen, void **buffer,
164     gp_cache_alloc alloc, void *userdata)
165 {
166     /* not yet implemented */
167     return -1;
168 }
169 
170 /* ------ Screen management ------ */
171 
172 /* Get the environment variable that specifies the display to use. */
173 const char *
gp_getenv_display(void)174 gp_getenv_display(void)
175 {
176     return getenv("DECW$DISPLAY");
177 }
178 
179 /* ------ Printer accessing ------ */
180 
181 /* Open a connection to a printer.  A null file name means use the */
182 /* standard printer connected to the machine, if any. */
183 /* Return NULL if the connection could not be opened. */
184 FILE *
gp_open_printer(char fname[gp_file_name_sizeof],int binary_mode)185 gp_open_printer(char fname[gp_file_name_sizeof], int binary_mode)
186 {
187     if (strlen(fname) == 0)
188 	return 0;
189     if (binary_mode) {		/*
190 				 * Printing must be done exactly byte to byte,
191 				 * using "passall".  However the standard VMS symbiont
192 				 * does not treat stream-LF files correctly in this respect,
193 				 * but throws away \n characters.  Giving the file
194 				 * the record type "undefined", but accessing it as a
195 				 * normal stream-LF file does the trick.
196 				 */
197 	return fopen_VMS(fname, "w", "rfm = udf", "ctx = stm");
198     } else {			/* Open as a normal text stream file. */
199 	return fopen_VMS(fname, "w", "rfm = var", "rat = cr");
200     }
201 }
202 
203 /* Close the connection to the printer. */
204 void
gp_close_printer(FILE * pfile,const char * fname)205 gp_close_printer(FILE * pfile, const char *fname)
206 {
207     fclose(pfile);
208 }
209 
210 /* ------ File naming and accessing ------ */
211 
212 /* Define the character used for separating file names in a list. */
213 const char gp_file_name_list_separator = ',';
214 
215 /* Define the default scratch file name prefix. */
216 const char gp_scratch_file_name_prefix[] = "_temp_";
217 
218 /* Define the name of the null output file. */
219 const char gp_null_file_name[] = "NLA0:";
220 
221 /* Define the name that designates the current directory. */
222 const char gp_current_directory_name[] = "[]";
223 
224 /* Define the string to be concatenated with the file mode */
225 /* for opening files without end-of-line conversion. */
226 const char gp_fmode_binary_suffix[] = "";
227 
228 /* Define the file modes for binary reading or writing. */
229 const char gp_fmode_rb[] = "r";
230 const char gp_fmode_wb[] = "w";
231 
232 /* Create and open a scratch file with a given name prefix. */
233 /* Write the actual file name at fname. */
234 FILE *
gp_open_scratch_file(const char * prefix,char fname[gp_file_name_sizeof],const char * mode)235 gp_open_scratch_file(const char *prefix, char fname[gp_file_name_sizeof],
236 		     const char *mode)
237 {
238     FILE *f;
239     char tmpdir[gp_file_name_sizeof];
240     int tdlen = gp_file_name_sizeof;
241     int flen[1];
242 
243     if (!gp_file_name_is_absolute(prefix, strlen(prefix)) &&
244 	gp_gettmpdir(tmpdir, &tdlen) == 0) {
245       flen[0] = gp_file_name_sizeof;
246 	if (gp_file_name_combine(tmpdir, tdlen, prefix, strlen(prefix),
247 			     false, fname, flen ) != gp_combine_success ) {
248 	    return NULL;
249 	}
250        fname[ *flen ] = 0;
251     } else {
252 	strcpy(fname, prefix);
253     }
254     if (strlen(fname) + 6 >= gp_file_name_sizeof)
255 	return 0;		/* file name too long */
256     strcat(fname, "XXXXXX");
257     mktemp(fname);
258     f = fopen(fname, mode);
259 
260     if (f == NULL)
261 	eprintf1("**** Could not open temporary file %s\n", fname);
262    return f;
263 }
264 
265 /* Open a file with the given name, as a stream of uninterpreted bytes. */
266 /* We have to do something special if the file was FTP'ed in binary mode. */
267 /* Unfortunately, only DEC C supports the extra arguments to fopen. */
268 FILE *
gp_fopen(const char * fname,const char * mode)269 gp_fopen(const char *fname, const char *mode)
270 {
271 #ifdef __DECC
272 #define FAB$C_FIX 1
273     stat_t buffer;
274 
275     if (stat((char *)fname, &buffer) == 0)
276 	if (buffer.st_fab_rfm == FAB$C_FIX)
277 	    return fopen(fname, mode, "rfm=stmlf", "ctx=stm");
278 #endif
279     return fopen(fname, mode);
280 }
281 
282 /* Set a file into binary or text mode. */
283 int
gp_setmode_binary(FILE * pfile,bool binary)284 gp_setmode_binary(FILE * pfile, bool binary)
285 {
286     return 0;			/* Noop under VMS */
287 }
288 
289 /* ------ Wild card file search procedures ------ */
290 
291 static void
gp_free_enumeration(file_enum * pfen)292 gp_free_enumeration(file_enum * pfen)
293 {
294     if (pfen) {
295 	LIB$FIND_FILE_END(&pfen->context);
296 	gs_free_object(pfen->memory, pfen->pattern.dsc$a_pointer,
297 		       "GP_ENUM(pattern)");
298 	gs_free_object(pfen->memory, pfen,
299 		       "GP_ENUM(file_enum)");
300     }
301 }
302 
303 /* Begin an enumeration.  See gp.h for details. */
304 
305 file_enum *
gp_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)306 gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
307 {
308     file_enum *pfen;
309     uint i, len;
310     char *c, *newpat;
311     bool dot_in_filename = false;
312 
313     pfen = gs_alloc_struct(mem, file_enum, &st_file_enum,
314 			   "GP_ENUM(file_enum)");
315     newpat = (char *)gs_alloc_bytes(mem, patlen + 2, "GP_ENUM(pattern)");
316     if (pfen == 0 || newpat == 0) {
317 	gs_free_object(mem, newpat, "GP_ENUM(pattern)");
318 	gs_free_object(mem, pfen, "GP_ENUM(file_enum)");
319 	return (file_enum *) 0;
320     }
321     /*  Copy the pattern removing backslash quoting characters and
322      *  transforming unquoted question marks, '?', to percent signs, '%'.
323      *  (VAX/VMS uses the wildcard '%' to represent exactly one character
324      *  and '*' to represent zero or more characters.  Any combination and
325      *  number of interspersed wildcards is permitted.)
326      *
327      *  Since VMS requires "*.*" to actually return all files, we add a
328      *  special check for a path ending in "*" and change it into "*.*"
329      *  if a "." wasn't part of the file spec. Thus "[P.A.T.H]*" becomes
330      *  "[P.A.T.H]*.*" but "[P.A.T.H]*.*" or "[P.A.T.H]*.X*" are unmodified.
331      */
332     c = newpat;
333     for (i = 0; i < patlen; pat++, i++)
334 	switch (*pat) {
335 	    case '?':
336 		*c++ = '%';
337 		break;
338 	    case '\\':
339 		i++;
340 		if (i < patlen)
341 		    *c++ = *++pat;
342 		break;
343 	    case '.':
344 	    case ']':
345 		dot_in_filename = *pat == '.';
346 	    default:
347 		*c++ = *pat;
348 		break;
349 	}
350     /* Check for trailing "*" and see if we need to add ".*" */
351     if (pat[-1] == '*' && !dot_in_filename) {
352 	*c++ = '.';
353 	*c++ = '*';
354     }
355     len = c - newpat;
356 
357     /* Pattern may not exceed 255 characters */
358     if (len > 255) {
359 	gs_free_object(mem, newpat, "GP_ENUM(pattern)");
360 	gs_free_object(mem, pfen, "GP_ENUM(file_enum)");
361 	return (file_enum *) 0;
362     }
363     pfen->context = 0;
364     pfen->length = patlen;
365     pfen->pattern.dsc$w_length = len;
366     pfen->pattern.dsc$b_dtype = DSC$K_DTYPE_T;
367     pfen->pattern.dsc$b_class = DSC$K_CLASS_S;
368     pfen->pattern.dsc$a_pointer = newpat;
369     pfen->memory = mem;
370 
371     return pfen;
372 }
373 
374 /* Return the next file name in the enumeration.  The client passes in */
375 /* a scratch string and a max length.  If the name of the next file fits, */
376 /* the procedure returns the length.  If it doesn't fit, the procedure */
377 /* returns max length +1.  If there are no more files, the procedure */
378 /* returns -1. */
379 
380 uint
gp_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)381 gp_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
382 {
383     char *c, filnam[NAM$C_MAXRSS];
384     descrip result =
385     {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
386     uint i, len;
387 
388     result.dsc$a_pointer = filnam;
389 
390     /* Find the next file which matches the pattern */
391     i = LIB$FIND_FILE(&pfen->pattern, &result, &pfen->context,
392 		      (descrip *) 0, (descrip *) 0, (uint *) 0, (uint *) 0);
393 
394     /* Check the return status */
395     if (RMS_IS_ERROR_OR_NMF(i)) {
396 	gp_free_enumeration(pfen);
397 	return (uint)(-1);
398     } else if ((len = strlength(filnam, NAM$C_MAXRSS, ' ')) > maxlen)
399 	return maxlen + 1;
400 
401     /* Copy the returned filename over to the input string ptr */
402     c = ptr;
403     for (i = 0; i < len; i++)
404 	*c++ = filnam[i];
405 
406     return len;
407 }
408 
409 /* Clean up a file enumeration.  This is only called to abandon */
410 /* an enumeration partway through: ...next should do it if there are */
411 /* no more files to enumerate.  This should deallocate the file_enum */
412 /* structure and any subsidiary structures, strings, buffers, etc. */
413 
414 void
gp_enumerate_files_close(file_enum * pfen)415 gp_enumerate_files_close(file_enum * pfen)
416 {
417     gp_free_enumeration(pfen);
418 }
419 
420 const char *
gp_strerror(int errnum)421 gp_strerror(int errnum)
422 {
423     return NULL;
424 }
425 
426 /* -------------- Helpers for gp_file_name_combine_generic ------------- */
427 
gp_file_name_root(const char * fname,uint len)428 uint gp_file_name_root(const char *fname, uint len)
429 {
430     /*
431      *    The root for device:[root.][directory.subdirectory]filename.extension;version
432      *	    is device:[root.][
433      *    The root for device:[directory.subdirectory]filename.extension;version
434      *	    is device:[
435      *    The root for logical:filename.extension;version
436      *	    is logical:
437      */
438     int i, j;
439 
440     if (len == 0)
441 	return 0;
442     /* Search for ':' */
443     for (i = 0; i < len; i++)
444 	if (fname[i] == ':')
445 	    break;
446     if (i == len)
447 	return 0; /* No root. */
448     if (fname[i] == ':')
449 	i++;
450     if (i == len || fname[i] != '[')
451 	return i;
452     /* Search for ']' */
453     i++;
454     for (j = i; j < len; j++)
455 	if (fname[j] == ']')
456 	    break;
457     if (j == len)
458 	return i; /* No ']'. Allowed as a Ghostscript specifics. */
459     j++;
460     if (j == len)
461 	return i; /* Appending "device:[directory.subdirectory]" with "filename.extension;version". */
462     if (fname[j] != '[')
463 	return i; /* Can't append anything, but pass through for checking an absolute path. */
464     return j + 1; /* device:[root.][ */
465 }
466 
gs_file_name_check_separator(const char * fname,int len,const char * item)467 uint gs_file_name_check_separator(const char *fname, int len, const char *item)
468 {
469     if (len > 0) {
470 	/*
471 	 * Ghostscript specifics : an extended syntax like Mac OS.
472 	 * We intentionally don't consider ':' and '[' as separators
473 	 * in forward search, see gp_file_name_combine.
474 	 */
475 	if (fname[0] == ']')
476 	    return 1; /* It is a file separator. */
477 	if (fname[0] == '.')
478 	    return 1; /* It is a directory separator. */
479 	if (fname[0] == '-') {
480 	    if (fname == item + 1 && item[0] == '-')
481 		return 1; /* Two or more parents, cut the first one. */
482 	    return 1;
483 	}
484     } else if (len < 0) {
485 	if (fname[-1] == '.' || fname[-1] == ':' || fname[-1] == '[')
486 	    return 1;
487     }
488     return 0;
489 }
490 
gp_file_name_is_parent(const char * fname,uint len)491 bool gp_file_name_is_parent(const char *fname, uint len)
492 {   /* Ghostscript specifics : an extended syntax like Mac OS. */
493     return len == 1 && fname[0] == '-';
494 }
495 
gp_file_name_is_current(const char * fname,uint len)496 bool gp_file_name_is_current(const char *fname, uint len)
497 {   /* Ghostscript specifics : an extended syntax like Mac OS. */
498     return len == 0;
499 }
500 
gp_file_name_separator(void)501 const char *gp_file_name_separator(void)
502 {   return "]";
503 }
504 
gp_file_name_directory_separator(void)505 const char *gp_file_name_directory_separator(void)
506 {   return ".";
507 }
508 
gp_file_name_parent(void)509 const char *gp_file_name_parent(void)
510 {   return "-";
511 }
512 
gp_file_name_current(void)513 const char *gp_file_name_current(void)
514 {   return "";
515 }
516 
gp_file_name_is_partent_allowed(void)517 bool gp_file_name_is_partent_allowed(void)
518 {   return false;
519 }
520 
gp_file_name_is_empty_item_meanful(void)521 bool gp_file_name_is_empty_item_meanful(void)
522 {   return true;
523 }
524 
525 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)526 gp_file_name_combine(const char *prefix, uint plen, const char *fname, uint flen,
527 		    bool no_sibling, char *buffer, uint *blen)
528 {
529     /*
530      * Reduce it to the general case.
531      *
532      * Implementation restriction : fname must not contain a part of
533      * "device:[root.]["
534      */
535     uint rlen, flen1 = flen, plen1 = plen;
536     const char *fname1 = fname;
537 
538    if ( plen > 0 && prefix[plen-1] == '\0' )
539      plen--;
540 
541     if (plen == 0 && flen == 0) {
542 	/* Not sure that we need this case. */
543 	if (*blen == 0)
544 	    return gp_combine_small_buffer;
545 	buffer[0] = '.';
546 	*blen = 1;
547     }
548     rlen = gp_file_name_root(fname, flen);
549     if (rlen > 0 || plen == 0 || flen == 0) {
550 	if (rlen == 0 && plen != 0) {
551 	    fname1 = prefix;
552 	    flen1 = plen;
553 	}
554 	if (flen1 + 1 > *blen)
555 	    return gp_combine_small_buffer;
556 	memcpy(buffer, fname1, flen1);
557 	buffer[flen1] = 0;
558 	*blen = flen1;
559 	return gp_combine_success;
560     }
561 
562    if ( prefix[plen - 1] == ']' && fname[ 0 ] == '-' )
563      {
564 	memcpy(buffer, prefix, plen - 1 );
565 	fname1 = fname + 1;
566 	flen1 = flen - 1;
567 	memcpy(buffer + plen - 1 , fname1, flen1);
568 	memcpy(buffer + plen + flen1 - 1 , "]" , 1 );
569 	buffer[plen + flen1] = 0;
570 	*blen = plen + flen1;
571 	return gp_combine_success;
572      }
573 
574    if ( prefix[plen - 1] == ':' || (prefix[plen - 1] == ']' &&
575 				     memchr(fname, ']', flen) == 0) )
576        {
577 	/* Just concatenate. */
578 	if (plen + flen + 1 > *blen)
579 	    return gp_combine_small_buffer;
580 	memcpy(buffer, prefix, plen);
581 	memcpy(buffer + plen, fname, flen);
582 	buffer[plen + flen] = 0;
583 	*blen = plen + flen;
584 	return gp_combine_success;
585     }
586    if ( memchr( prefix , '[' , plen ) == 0 &&
587 	memchr( prefix , '.' , plen ) == 0 )
588      {
589 	char* tmp_prefix;
590 	int tmp_plen;
591 
592 	if ( prefix[0] == '/' )
593 	  {
594 	     tmp_prefix = prefix + 1;
595 	     tmp_plen = plen - 1;
596 	  }
597 	else
598 	  {
599 	     tmp_prefix = prefix;
600 	     tmp_plen = plen;
601 	  }
602 	if ( tmp_plen + flen + 2 > *blen)
603 	    return gp_combine_small_buffer;
604 	memcpy(buffer, tmp_prefix, tmp_plen);
605 	memcpy(buffer + tmp_plen , ":" , 1 );
606 	memcpy(buffer + tmp_plen + 1, fname, flen);
607 	if ( memchr( fname , '.' , flen ) != 0 )
608 	  {
609 	     buffer[ tmp_plen + flen + 1] = 0;
610 	     *blen = tmp_plen + flen + 1;
611 	  }
612 	else
613 	  {
614 	     memcpy(buffer + tmp_plen + flen + 1 , "." , 1 );
615 	     buffer[ tmp_plen + flen + 2] = 0;
616 	     *blen = tmp_plen + flen + 2;
617 	  }
618 	return gp_combine_success;
619      }
620     if (prefix[plen - 1] != ']' && fname[0] == '[')
621         return gp_combine_cant_handle;
622     /* Unclose "][" :*/
623     if (fname[0] == '[') {
624 	fname1 = fname + 1;
625 	flen1 = flen - 1;
626     }
627     if (prefix[plen - 1] == ']')
628         plen1 = plen - 1;
629     return gp_file_name_combine_generic(prefix, plen1,
630 	    fname1, flen1, no_sibling, buffer, blen);
631 }
632 
633 /* ------ Font enumeration ------ */
634 
635  /* This is used to query the native os for a list of font names and
636   * corresponding paths. The general idea is to save the hassle of
637   * building a custom fontmap file.
638   */
639 
gp_enumerate_fonts_init(gs_memory_t * mem)640 void *gp_enumerate_fonts_init(gs_memory_t *mem)
641 {
642     return NULL;
643 }
644 
gp_enumerate_fonts_next(void * enum_state,char ** fontname,char ** path)645 int gp_enumerate_fonts_next(void *enum_state, char **fontname, char **path)
646 {
647     return 0;
648 }
649 
gp_enumerate_fonts_free(void * enum_state)650 void gp_enumerate_fonts_free(void *enum_state)
651 {
652 }
653 
654 /* --------- 64 bit file access ----------- */
655 /* fixme: Not implemented yet.
656  * Currently we stub it with 32 bits access.
657  */
658 
gp_fopen_64(const char * filename,const char * mode)659 FILE *gp_fopen_64(const char *filename, const char *mode)
660 {
661     return fopen(filename, mode);
662 }
663 
gp_open_scratch_file_64(const char * prefix,char fname[gp_file_name_sizeof],const char * mode)664 FILE *gp_open_scratch_file_64(const char *prefix,
665 			   char fname[gp_file_name_sizeof],
666 			   const char *mode)
667 {
668     return gp_open_scratch_file(prefix, fname, mode);
669 }
670 
gp_open_printer_64(char fname[gp_file_name_sizeof],int binary_mode)671 FILE *gp_open_printer_64(char fname[gp_file_name_sizeof], int binary_mode)
672 {
673     return gp_open_printer(fname, binary_mode);
674 }
675 
gp_ftell_64(FILE * strm)676 int64_t gp_ftell_64(FILE *strm)
677 {
678     return ftell(strm);
679 }
680 
gp_fseek_64(FILE * strm,int64_t offset,int origin)681 int gp_fseek_64(FILE *strm, int64_t offset, int origin)
682 {
683     long offset1 = (long)offset;
684 
685     if (offset != offset1)
686 	return -1;
687     return fseek(strm, offset1, origin);
688 }
689