1 /*
2  *    (c) Copyright 2001  Uwe Steinmann.
3  *    All rights reserved.
4  *
5  *    This library is free software; you can redistribute it and/or
6  *    modify it under the terms of the GNU Lesser General Public
7  *    License as published by the Free Software Foundation; either
8  *    version 2 of the License, or (at your option) any later version.
9  *
10  *    This library is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *    Lesser General Public License for more details.
14  *
15  *    You should have received a copy of the GNU Lesser General Public
16  *    License along with this library; if not, write to the
17  *    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  *    Boston, MA 02111-1307, USA.
19  */
20 
21 /* $Id$ */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <stdio.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include "ps_intern.h"
32 #include "ps_memory.h"
33 #include "ps_fontenc.h"
34 #include "ps_inputenc.h"
35 #include "ps_error.h"
36 
37 /* ps_write() {{{
38  * Output data using the current writeprocedure
39  */
40 void
ps_write(PSDoc * p,const void * data,size_t size)41 ps_write(PSDoc *p, const void *data, size_t size) {
42 	(void) p->writeproc(p, (void *) data, size);
43 }
44 /* }}} */
45 
46 /* ps_putc() {{{
47  * Output char
48  */
49 void
ps_putc(PSDoc * p,char c)50 ps_putc(PSDoc *p, char c)
51 {
52 	ps_write(p, (void *) &c, (size_t) 1);
53 }
54 /* }}} */
55 
56 /* ps_puts() {{{
57  * Output string
58  */
59 void
ps_puts(PSDoc * p,const char * s)60 ps_puts(PSDoc *p, const char *s)
61 {
62 	ps_write(p, (void *) s, strlen(s));
63 }
64 /* }}} */
65 
66 /* ps_printf() {{{
67  * Output formated string
68  */
69 void
ps_printf(PSDoc * p,const char * fmt,...)70 ps_printf(PSDoc *p, const char *fmt, ...)
71 {
72 	char buf[LINEBUFLEN];  /* formatting buffer */
73 	va_list ap;
74 
75 	va_start(ap, fmt);
76 
77 	setlocale(LC_NUMERIC, "C");
78 	(void) vsnprintf(buf, LINEBUFLEN, fmt, ap);
79 	setlocale(LC_NUMERIC, "");
80 	ps_puts(p, buf);
81 
82 	va_end(ap);
83 }
84 /* }}} */
85 
86 /* ps_ght_malloc() {{{
87  *
88  * malloc routine which is passed to the hash table functions.
89  */
ps_ght_malloc(size_t size,void * data)90 void* ps_ght_malloc(size_t size, void *data) {
91 	PSDoc *psdoc = data;
92 	return(psdoc->malloc(psdoc, size, _("Allocate memory for hash table of char metrics")));
93 }
94 /* }}} */
95 
96 /* ps_ght_free() {{{
97  *
98  * free routine which is passed to the hash table functions.
99  */
ps_ght_free(void * ptr,void * data)100 void ps_ght_free(void *ptr, void *data) {
101 	PSDoc *psdoc = data;
102 	psdoc->free(psdoc, ptr);
103 }
104 /* }}} */
105 
106 /* ps_enter_scope() {{{
107  */
ps_enter_scope(PSDoc * psdoc,int scope)108 void ps_enter_scope(PSDoc *psdoc, int scope) {
109 	if(psdoc->scopecount == (MAX_SCOPES-1)) {
110 		ps_error(psdoc, PS_RuntimeError, _("Maximum number of scopes reached."));
111 	} else {
112 		psdoc->scopecount++;
113 		psdoc->scopes[psdoc->scopecount] = scope;
114 	}
115 }
116 /* }}} */
117 
118 /* ps_leave_scope() {{{
119  */
ps_leave_scope(PSDoc * psdoc,int scope)120 void ps_leave_scope(PSDoc *psdoc, int scope) {
121 	if(scope != psdoc->scopes[psdoc->scopecount])
122 		ps_error(psdoc, PS_RuntimeError, _("Trying to leave scope %d but you are in %d."), scope, psdoc->scopes[psdoc->scopecount]);
123 	else
124 		psdoc->scopecount--;
125 }
126 /* }}} */
127 
128 /* ps_current_scope() {{{
129  */
ps_current_scope(PSDoc * psdoc)130 int ps_current_scope(PSDoc *psdoc) {
131 	return(psdoc->scopes[psdoc->scopecount]);
132 }
133 /* }}} */
134 
135 /* ps_check_scope() {{{
136  */
ps_check_scope(PSDoc * psdoc,int scope)137 ps_bool ps_check_scope(PSDoc *psdoc, int scope) {
138 	return(scope & psdoc->scopes[psdoc->scopecount]);
139 }
140 /* }}} */
141 
142 /* ps_get_resources() {{{
143  * Returns an array of pointers to all resources of a category.
144  */
ps_get_resources(PSDoc * psdoc,const char * category,int * count)145 PS_RESOURCE **ps_get_resources(PSDoc *psdoc, const char *category, int *count) {
146 	PS_CATEGORY *cat;
147 	PS_RESOURCE *res;
148 	PS_RESOURCE **ress = NULL;
149 	int i;
150 
151 	*count = 0;
152 	for(cat = dlst_first(psdoc->categories); cat != NULL; cat = dlst_next(cat)) {
153 		if (!strcmp(cat->name, category)) {
154 			ress = psdoc->malloc(psdoc, cat->resources->count * sizeof(PS_RESOURCE *), _("Allocate Memory for list of resources."));
155 			*count = cat->resources->count;
156 			for(i=0, res = dlst_first(cat->resources); res != NULL; res = dlst_next(res), i++) {
157 				ress[i] = res;
158 			}
159 		}
160 	}
161 	return(ress);
162 }
163 /* }}} */
164 
165 /* ps_find_resource() {{{
166  */
ps_find_resource(PSDoc * psdoc,const char * category,const char * resource)167 char *ps_find_resource(PSDoc *psdoc, const char *category, const char *resource) {
168 	PS_CATEGORY *cat;
169 	PS_RESOURCE *res;
170 
171 	for(cat = dlst_first(psdoc->categories); cat != NULL; cat = dlst_next(cat)) {
172 		if (!strcmp(cat->name, category)) {
173 			for(res = dlst_first(cat->resources); res != NULL; res = dlst_next(res)) {
174 				if (!strcmp(res->name, resource))
175 					return(res->value);
176 			}
177 		}
178 	}
179 	return(NULL);
180 }
181 /* }}} */
182 
183 /* ps_add_resource() {{{
184  */
ps_add_resource(PSDoc * psdoc,const char * category,const char * resource,const char * filename,const char * prefix)185 PS_RESOURCE * ps_add_resource(PSDoc *psdoc, const char *category, const char *resource, const char *filename, const char *prefix) {
186 	PS_CATEGORY *cat;
187 	PS_RESOURCE *res;
188 
189 	/* Right and LeftMarginKerning are set in PS_set_paramter. They manipulate
190 	 * the ADOBEINFO struct of the affected char directly.
191 	 */
192 	if (strcmp("SearchPath", category) &&
193 	    strcmp("FontAFM", category) &&
194 			strcmp("FontEncoding", category) &&
195 			strcmp("FontProtusion", category) &&
196 			strcmp("FontOutline", category)) {
197 		return(NULL);
198 	}
199 
200 	/* Search for the category */
201 	for(cat = dlst_first(psdoc->categories); cat != NULL; cat = dlst_next(cat)) {
202 		if(!strcmp(cat->name, category))
203 			break;
204 	}
205 
206 	/* Create a new category if it does not exist */
207 	if(cat == NULL) {
208 		if(NULL == (cat = (PS_CATEGORY *) dlst_newnode(psdoc->categories, sizeof(PS_CATEGORY)))) {
209 			return(NULL);
210 		}
211 		cat->name = ps_strdup(psdoc, category);
212 		cat->resources = dlst_init(psdoc->malloc, psdoc->realloc, psdoc->free);
213 		dlst_insertafter(psdoc->categories, cat, PS_DLST_HEAD(psdoc->categories));
214 	}
215 
216 	/* Check if resource already available */
217 	if(resource) {
218 		for(res = dlst_first(cat->resources); res != NULL; res = dlst_next(res)) {
219 			if(!strcmp(res->name, resource))
220 				break;
221 		}
222 	} else {
223 		res = NULL;
224 	}
225 	if(res) {
226 		psdoc->free(psdoc, res->name);
227 		res->name = ps_strdup(psdoc, resource);
228 		psdoc->free(psdoc, res->value);
229 		res->value = ps_strdup(psdoc, filename);
230 	} else {
231 		if(NULL == (res = (PS_RESOURCE *) dlst_newnode(cat->resources, sizeof(PS_RESOURCE)))) {
232 			return(NULL);
233 		}
234 		if(resource)
235 			res->name = ps_strdup(psdoc, resource);
236 		else
237 			res->name = NULL;
238 		res->value = ps_strdup(psdoc, filename);
239 		dlst_insertafter(cat->resources, res, PS_DLST_HEAD(cat->resources));
240 	}
241 
242 	return(res);
243 }
244 /* }}} */
245 
246 /* ps_del_resources() {{{
247  */
ps_del_resources(PSDoc * psdoc)248 void ps_del_resources(PSDoc *psdoc) {
249 	PS_CATEGORY *cat, *nextcat;
250 	PS_RESOURCE *res, *nextres;
251 	if(NULL == psdoc->categories)
252 		return;
253 	cat = dlst_first(psdoc->categories);
254 	while(cat != NULL) {
255 		nextcat = dlst_next(cat);
256 		psdoc->free(psdoc, cat->name);
257 		res = dlst_first(cat->resources);
258 		while(res != NULL) {
259 			nextres = dlst_next(res);
260 			if(res->name)
261 				psdoc->free(psdoc, res->name);
262 			if(res->value)
263 				psdoc->free(psdoc, res->value);
264 			res = nextres;
265 		}
266 		dlst_kill(cat->resources, dlst_freenode);
267 		cat = nextcat;
268 	}
269 	dlst_kill(psdoc->categories, dlst_freenode);
270 	psdoc->categories = NULL;
271 }
272 /* }}} */
273 
274 /* ps_del_parameters() {{{
275  */
ps_del_parameters(PSDoc * psdoc)276 void ps_del_parameters(PSDoc *psdoc) {
277 	PS_PARAMETER *param, *nextparam;
278 	if(NULL == psdoc->parameters)
279 		return;
280 	param = dlst_first(psdoc->parameters);
281 	while(param != NULL) {
282 		nextparam = dlst_next(param);
283 		psdoc->free(psdoc, param->name);
284 		psdoc->free(psdoc, param->value);
285 		param = nextparam;
286 	}
287 	dlst_kill(psdoc->parameters, dlst_freenode);
288 	psdoc->parameters = NULL;
289 }
290 /* }}} */
291 
292 /* ps_del_values() {{{
293  */
ps_del_values(PSDoc * psdoc)294 void ps_del_values(PSDoc *psdoc) {
295 	PS_VALUE *param, *nextparam;
296 	if(NULL == psdoc->values)
297 		return;
298 	param = dlst_first(psdoc->values);
299 	while(param != NULL) {
300 		nextparam = dlst_next(param);
301 		psdoc->free(psdoc, param->name);
302 		param = nextparam;
303 	}
304 	dlst_kill(psdoc->values, dlst_freenode);
305 	psdoc->values = NULL;
306 }
307 /* }}} */
308 
309 /* ps_del_bookmarks() {{{
310  */
ps_del_bookmarks(PSDoc * psdoc,DLIST * bookmarks)311 void ps_del_bookmarks(PSDoc *psdoc, DLIST *bookmarks) {
312 	PS_BOOKMARK *bm, *nextbm;
313 	if(NULL == bookmarks)
314 		return;
315 	bm = dlst_first(bookmarks);
316 	while(bm != NULL) {
317 		nextbm = dlst_next(bm);
318 		psdoc->free(psdoc, bm->text);
319 		ps_del_bookmarks(psdoc, bm->children);
320 		bm = nextbm;
321 	}
322 	dlst_kill(bookmarks, dlst_freenode);
323 }
324 /* }}} */
325 
326 /* ps_add_word_spacing() {{{
327  */
ps_add_word_spacing(PSDoc * psdoc,PSFont * psfont,float value)328 void ps_add_word_spacing(PSDoc *psdoc, PSFont *psfont, float value) {
329 	psfont->wordspace += value * 1000.0 / psfont->size;
330 }
331 /* }}} */
332 
333 /* ps_set_word_spacing() {{{
334  */
ps_set_word_spacing(PSDoc * psdoc,PSFont * psfont,float value)335 void ps_set_word_spacing(PSDoc *psdoc, PSFont *psfont, float value) {
336 	ADOBEINFO *ai;
337 
338 	if(value != 0.0) {
339 		psfont->wordspace = value * 1000.0 / psfont->size;
340 	} else {
341 		ai = gfindadobe(psfont->metrics->gadobechars, "space");
342 		if(ai)
343 			psfont->wordspace = ai->width;
344 		else
345 			psfont->wordspace = 500.0;
346 	}
347 }
348 /* }}} */
349 
350 /* ps_get_word_spacing() {{{
351  */
ps_get_word_spacing(PSDoc * psdoc,PSFont * psfont)352 float ps_get_word_spacing(PSDoc *psdoc, PSFont *psfont) {
353 	float ws;
354 	ws = ((float) psfont->wordspace) * psfont->size / 1000.0;
355 	return(ws);
356 }
357 /* }}} */
358 
359 /* ps_check_for_lig() {{{
360  * Checks if the characters in text form a ligature with the character
361  * in ai. If that is the case the number of characters consumed in text
362  * will be returned in offset and the name of the ligature will be returned
363  * in newadobename.
364  * Ligatures can be broken off by a ligdischar. In such a case 1 will be
365  * returned
366  * and offset is set to 1 in order to skip the ligdischar. newadobename is set
367  * to the name of the passed character.
368  */
ps_check_for_lig(PSDoc * psdoc,ADOBEFONTMETRIC * metrics,ADOBEINFO * ai,const char * text,char ligdischar,char ** newadobename,int * offset)369 int ps_check_for_lig(PSDoc *psdoc, ADOBEFONTMETRIC *metrics, ADOBEINFO *ai, const char *text, char ligdischar, char **newadobename, int *offset) {
370 	ADOBEINFO *nextai;
371 	LIG *ligs;
372 	if((NULL == ai) || (NULL == ai->ligs))
373 		return 0;
374 	if(NULL == text || text[0] == '\0')
375 		return 0;
376 
377 	ligs = ai->ligs;
378 	/* ligdischar breaks ligatures. The idea is, that every char followed
379 	 * by a ligdischar
380 	 * forms a ligature which is the char itself. Setting offset to
381 	 * 1 will skip the ligdischar */
382 	if(ligs && text[0] == ligdischar) {
383 		*offset += 1;
384 		*newadobename = ai->adobename;
385 		return 1;
386 	}
387 	if(ligs) {
388 		int _offset = 0;
389 		char *nextadobename;
390 		nextai = gfindadobe(metrics->gadobechars, psdoc->inputenc->vec[(unsigned char) (text[0])]);
391 		if(NULL == nextai)
392 			return 0;
393 
394 		/* check if nextai and the following char form a ligature
395 		 * If that is the case then there is a change that we have a 3 char
396 		 * ligature. First check if current char and ligature of 2nd and 3th
397 		 * char for a ligature.
398 		 */
399 		if(ps_check_for_lig(psdoc, metrics, nextai, &text[1], ligdischar, &nextadobename, &_offset)) {
400 			while(ligs) {
401 				if(0 == strcmp(ligs->succ, nextadobename)) {
402 					*offset += 1+_offset;
403 					*newadobename = ligs->sub;
404 					return 1;
405 				}
406 				ligs = ligs->next;
407 			}
408 		}
409 
410 		/* If we haven't found a three char ligature at this point then check
411 		 * for a 2 char ligatur.
412 		 */
413 		ligs = ai->ligs;
414 		while(ligs) {
415 	//		printf("Ligature for %s is %s\n", ai->adobename, ligs->succ);
416 			if(!strcmp(ligs->succ, nextai->adobename)) {
417 				ADOBEINFO *ligai;
418 				*offset += 1;
419 				/* check if the ligature made of the first two chars form a ligature
420 				 * which the third char
421 				 */
422 				ligai = gfindadobe(metrics->gadobechars, ligs->sub);
423 				if(ligai) {
424 					if(ps_check_for_lig(psdoc, metrics, ligai, &text[1], ligdischar, &nextadobename, offset)) {
425 						*newadobename = nextadobename;
426 						return 1;
427 
428 					}
429 				}
430 				*newadobename = ligs->sub;
431 	//			printf("Found %s followed by %s replaced with %s\n", ai->adobename, nextai->adobename, ligs->sub);
432 				return 1;
433 			}
434 			ligs = ligs->next;
435 		}
436 	}
437 	return 0;
438 }
439 /* }}} */
440 
441 /* ps_build_enc_hash() {{{
442  * Builds the hash table of an encoding vector.
443  * The glyhname is the the key, the position in the vector is the data.
444  * The position of the glyph in the vector starts at 1 because 0 is reserved
445  * by the hash table to indicate the end of the list.
446  * If a glyphname exists more than once, only the first one will be
447  * stored in the hash table. This would be the case for "" as glyphname,
448  * but empty strings are not stored at all.
449  */
ps_build_enc_hash(PSDoc * psdoc,ENCODING * enc)450 ght_hash_table_t *ps_build_enc_hash(PSDoc *psdoc, ENCODING *enc) {
451 	int i;
452 	ght_hash_table_t *hashvec;
453 	hashvec = ght_create(512);
454 	if(hashvec) {
455 		ght_set_alloc(hashvec, ps_ght_malloc, ps_ght_free, psdoc);
456 		for(i=0; i<256; i++) {
457 			if(strlen(enc->vec[i]) > 0)
458 				ght_insert(hashvec, (char *) i+1, strlen(enc->vec[i])+1, enc->vec[i]);
459 		}
460 	}
461 	return(hashvec);
462 }
463 /* }}} */
464 
465 /* ps_build_enc_from_font() {{{
466  * Builds the hash table with a font encoding from the font itself.
467  * This will only include those glyphs which have a number > 0.
468  */
ps_build_enc_from_font(PSDoc * psdoc,ADOBEFONTMETRIC * metrics)469 ght_hash_table_t *ps_build_enc_from_font(PSDoc *psdoc, ADOBEFONTMETRIC *metrics) {
470 	ght_hash_table_t *hashvec;
471 
472 	hashvec = ght_create(512);
473 	if(hashvec) {
474 		ght_iterator_t iterator;
475 		char *p_key;
476 		ADOBEINFO *p_e;
477 
478 		ght_set_alloc(hashvec, ps_ght_malloc, ps_ght_free, psdoc);
479 		for(p_e = ght_first(metrics->gadobechars, &iterator, (void **) &p_key); p_e; p_e = ght_next(metrics->gadobechars, &iterator, (void **) &p_key)) {
480 			/* Do not add glyphs with a number <= 0 */
481 			if(p_e->adobenum > 0) {
482 				if(0 > ght_insert(hashvec, (char *) p_e->adobenum+1, strlen(p_e->adobename)+1, p_e->adobename))
483 				ps_error(psdoc, PS_Warning, _("Could not insert entry %d->%s into font encoding hash table."), p_e->adobenum, p_e->adobename);
484 			}
485 		}
486 	}
487 	return(hashvec);
488 }
489 /* }}} */
490 
491 /* ps_build_enc_vector() {{{
492  * Builds the encoding vector from the hash table
493  */
ps_build_enc_vector(PSDoc * psdoc,ght_hash_table_t * hashvec)494 ENCODING *ps_build_enc_vector(PSDoc *psdoc, ght_hash_table_t *hashvec) {
495 	if(hashvec) {
496 		ght_iterator_t iterator;
497 		char *glyphname;
498 		int i;
499 		ENCODING *enc;
500 
501 		enc = (ENCODING *) psdoc->malloc(psdoc, sizeof(ENCODING), _("Allocate memory for new encoding vector.")) ;
502 		if(NULL == enc) {
503 			ps_error(psdoc, PS_MemoryError, _("Could not allocate memory for encoding vector."));
504 			return NULL;
505 		}
506 		memset(enc, 0, sizeof(ENCODING));
507 
508 		for(i = (int) ght_first(hashvec, &iterator, (void **) &glyphname); i; i = (int) ght_next(hashvec, &iterator, (void **) &glyphname)) {
509 //			printf("got %s = %d\n", glyphname, i-1);
510 			enc->vec[i-1] = ps_strdup(psdoc, glyphname);
511 		}
512 
513 		return(enc);
514 	} else {
515 		return NULL;
516 	}
517 }
518 /* }}} */
519 
520 /* ps_list_fontenc() {{{
521  *
522  */
ps_list_fontenc(PSDoc * psdoc,ght_hash_table_t * hashvec)523 void ps_list_fontenc(PSDoc *psdoc, ght_hash_table_t *hashvec) {
524 	if(hashvec) {
525 		ght_iterator_t iterator;
526 		char *glyphname;
527 		int i;
528 
529 		fprintf(stderr, "---- Font encoding vector -----\n");
530 		fprintf(stderr, "Has %d entries.\n", ght_size(hashvec));
531 		for(i = (int) ght_first(hashvec, &iterator, (void **) &glyphname); i; i = (int) ght_next(hashvec, &iterator, (void **) &glyphname)) {
532 			fprintf(stderr, "%s = %d\n", glyphname, i-1);
533 		}
534 	}
535 }
536 /* }}} */
537 
538 /* ps_free_enc_vector() {{{
539  * Frees all memory allocated for an encoding vector including the vector
540  * itself.
541  */
ps_free_enc_vector(PSDoc * psdoc,ENCODING * enc)542 void ps_free_enc_vector(PSDoc *psdoc, ENCODING *enc) {
543 	int i;
544 	if(!enc)
545 		return;
546 	if(enc->name)
547 		psdoc->free(psdoc, enc->name);
548 	for(i=0; i<256; i++) {
549 		if(enc->vec[i])
550 			psdoc->free(psdoc, enc->vec[i]);
551 	}
552 	psdoc->free(psdoc, enc);
553 }
554 /* }}} */
555 
556 /* ps_fontenc_code() {{{
557  * Returns the index in the fontencoding vector
558  */
ps_fontenc_code(PSDoc * psdoc,ght_hash_table_t * fontenc,char * adobename)559 unsigned char ps_fontenc_code(PSDoc *psdoc, ght_hash_table_t *fontenc, char *adobename) {
560 	if(fontenc) {
561 		int code;
562 		code = (int) ght_get(fontenc, strlen(adobename)+1, (void *) adobename);
563 		if(code)
564 			return((unsigned char) code -1);
565 		else {
566 			ps_error(psdoc, PS_Warning, _("The font encoding vector does not contain the glyph '%s'. Using '?' instead."), adobename);
567 			return '?';
568 		}
569 	} else {
570 		return '?';
571 	}
572 }
573 /* }}} */
574 
575 /* ps_fontenc_has_glpyh() {{{
576  * checks of a glyph is in the fontencoding vector
577  */
ps_fontenc_has_glyph(PSDoc * psdoc,ght_hash_table_t * fontenc,char * adobename)578 int ps_fontenc_has_glyph(PSDoc *psdoc, ght_hash_table_t *fontenc, char *adobename) {
579 	if(fontenc) {
580 		int code;
581 		code = (int) ght_get(fontenc, strlen(adobename)+1, (void *) adobename);
582 		if(code)
583 			return ps_true;
584 		else {
585 			return ps_false;
586 		}
587 	} else {
588 		return ps_false;
589 	}
590 }
591 /* }}} */
592 
593 /* ps_inputenc_name() {{{
594  * Returns the adobe name for a char in the input encoding vector
595  */
ps_inputenc_name(PSDoc * psdoc,unsigned char c)596 char *ps_inputenc_name(PSDoc *psdoc, unsigned char c) {
597 	if(psdoc->inputenc) {
598 		return(psdoc->inputenc->vec[c]);
599 	} else {
600 		return NULL;
601 	}
602 }
603 /* }}} */
604 
605 /* ps_get_bool_parameter() {{{
606  */
ps_get_bool_parameter(PSDoc * psdoc,const char * name,int deflt)607 int ps_get_bool_parameter(PSDoc *psdoc, const char *name, int deflt) {
608 	const char *onoffstr;
609 	onoffstr = PS_get_parameter(psdoc, name, 0);
610 	if(NULL == onoffstr) {
611 		return(deflt);
612 	} else {
613 		if(!strcmp(onoffstr, "true"))
614 			return(1);
615 		else
616 			return(0);
617 	}
618 }
619 /* }}} */
620 
621 /* ps_open_file_in_path() {{{
622  */
ps_open_file_in_path(PSDoc * psdoc,const char * filename)623 FILE *ps_open_file_in_path(PSDoc *psdoc, const char *filename) {
624 	FILE *fp;
625 	PS_RESOURCE **pathres;
626 	int count;
627 	int i;
628 	char buffer[255];
629 
630 	if(fp = fopen(filename, "rb"))
631 		return fp;
632 
633 	if(NULL != (pathres = ps_get_resources(psdoc, "SearchPath", &count))) {
634 		for(i=count-1; i>=0; i--) {
635 #ifdef HAVE_SNPRINTF
636 			snprintf(buffer, 255, "%s/%s", pathres[i]->value, filename);
637 #else
638 			sprintf(buffer, "%s/%s", pathres[i]->value, filename);
639 #endif
640 //			fprintf(stderr, "Searching for %s\n", buffer);
641 			if(fp = fopen(buffer, "rb")) {
642 //				fprintf(stderr, "found %s in %s\n", filename, pathres[i]->value);
643 				break;
644 			}
645 		}
646 		psdoc->free(psdoc, pathres);
647 		if(fp)
648 			return(fp);
649 	}
650 
651 #ifdef PACKAGE_DATA_DIR
652 #ifdef HAVE_SNPRINTF
653 	snprintf(buffer, 255, "%s/%s", PACKAGE_DATA_DIR, filename);
654 #else
655 	sprintf(buffer, "%s/%s", PACKAGE_DATA_DIR, filename);
656 #endif
657 	if(fp = fopen(buffer, "rb"))
658 		return fp;
659 #endif
660 
661 	return NULL;
662 }
663 /* }}} */
664 
665 int pow85[5] = {1, 85, 85*85, 85*85*85, 85*85*85*85};
666 
667 /* ps_ascii85_encode() {{{
668  */
ps_ascii85_encode(PSDoc * psdoc,char * data,size_t len)669 void ps_ascii85_encode(PSDoc *psdoc, char *data, size_t len) {
670 	unsigned long buffer;
671 	unsigned char c;
672 	int i, count, cc;
673 
674 	buffer = 0;
675 	count = 0;
676 	cc = 0;
677 	while(count <= len-4) {
678 //		buffer = ((long) data[count] << 24) + ((long) data[count+1] << 16) + ((long) data[count+2] << 8) + (long) data[count+3];
679 		buffer |= ((unsigned char) data[count] << 24);
680 		buffer |= ((unsigned char) data[count+1] << 16);
681 		buffer |= ((unsigned char) data[count+2] << 8);
682 		buffer |= ((unsigned char) data[count+3]);
683 
684 		if(buffer == 0) {
685 			ps_putc(psdoc, 'z');
686 			cc++;
687 		} else {
688 			for(i=4; i>=0; i--) {
689 				c = (unsigned int) buffer / pow85[i];
690 				ps_putc(psdoc, c+'!');
691 				buffer = (unsigned int) buffer % pow85[i];
692 			}
693 			cc += 4;
694 		}
695 		count += 4;
696 		if(cc > 55) {
697 			ps_putc(psdoc, '\n');
698 			cc = 0;
699 		}
700 	}
701 	if(len-count) {
702 		buffer = 0;
703 		for(i=0; i<len-count; i++)
704 			buffer = (buffer << 8) + (long) data[count+i];
705 		buffer = buffer << ((4-len+count)*8);
706 		for(i=4; i>=4-len+count; i--) {
707 			c = (unsigned int) buffer / pow85[i];
708 			ps_putc(psdoc, c+'!');
709 			buffer = (unsigned int) buffer % pow85[i];
710 		}
711 	}
712 	ps_putc(psdoc, '~');
713 	ps_putc(psdoc, '>');
714 }
715 /* }}} */
716 
717 /* ps_asciihex_encode() {{{
718  */
ps_asciihex_encode(PSDoc * psdoc,char * data,size_t len)719 void ps_asciihex_encode(PSDoc *psdoc, char *data, size_t len) {
720 	int i, cc=0;
721 	unsigned char *dataptr;
722 
723 	dataptr = data;
724 	for(i=0; i<len; i++) {
725 		ps_printf(psdoc, "%02x", *dataptr);
726 		dataptr ++;
727 		cc++;
728 		if(cc > 35 && i < (len-1)) {
729 			ps_printf(psdoc, "\n");
730 			cc = 0;
731 		}
732 	}
733 	ps_putc(psdoc, '\n');
734 	ps_putc(psdoc, '>');
735 }
736 /* }}} */
737 
738 /* ps_parse_optlist() {{{
739  */
ps_parse_optlist(PSDoc * psdoc,const char * optstr)740 ght_hash_table_t *ps_parse_optlist(PSDoc *psdoc, const char *optstr) {
741 	int i, isname;
742 	char name[100], value[100], delim;
743 	const char *optstrptr;
744 	ght_hash_table_t *opthash;
745 
746 	if(optstr == NULL || optstr[0] == '\0')
747 		return(NULL);
748 
749 	opthash = ght_create(30);
750 	if(opthash) {
751 		ght_set_alloc(opthash, ps_ght_malloc, ps_ght_free, psdoc);
752 
753 		isname = 1;
754 		optstrptr = optstr;
755 		name[0] = '\0';
756 		value[0] = '\0';
757 
758 		/* Skip leading spaces */
759 		while(*optstrptr == ' ')
760 			optstrptr++;
761 
762 		while(*optstrptr != '\0') {
763 			if(isname) {
764 				i = 0;
765 				while(*optstrptr != '\0' && *optstrptr != ' ') {
766 					name[i] = *optstrptr;
767 					i++;
768 					optstrptr++;
769 				}
770 				name[i] = '\0';
771 				isname = 0;
772 				optstrptr++;
773 			} else {
774 				if(*optstrptr == '{') {
775 					delim = '}';
776 					optstrptr++;
777 				} else {
778 					delim = ' ';
779 				}
780 				i = 0;
781 				while(*optstrptr != '\0' && *optstrptr != delim) {
782 					value[i] = *optstrptr;
783 					i++;
784 					optstrptr++;
785 				}
786 				value[i] = '\0';
787 				isname = 1;
788 				optstrptr++;
789 
790 				/* Value and Name is read, insert it into hash */
791 				if(name[0]) {
792 					ght_insert(opthash, (char *) ps_strdup(psdoc, value), strlen(name)+1, name);
793 					name[0] = '\0';
794 					value[0] = '\0';
795 				}
796 			}
797 			while(*optstrptr != '\0' && *optstrptr == ' ')
798 				optstrptr++;
799 		}
800 	}
801 	return(opthash);
802 }
803 /* }}} */
804 
805 /* ps_free_optlist() {{{
806  */
ps_free_optlist(PSDoc * psdoc,ght_hash_table_t * opthash)807 void ps_free_optlist(PSDoc *psdoc, ght_hash_table_t *opthash) {
808 	ght_iterator_t iterator;
809 	char *strval, *key;
810 
811 //		fprintf(stderr, "Freeing optlist\n");
812 	for(strval = ght_first(opthash, &iterator, (void **) &key); strval; strval = ght_next(opthash, &iterator, (void **) &key)) {
813 //		fprintf(stderr, "Freeing %s\n", strval);
814 		psdoc->free(psdoc, strval);
815 	}
816 	ght_finalize(opthash);
817 }
818 /* }}} */
819 
820 /* get_optlist_element_as_float() {{{
821  * Retrieves an element from the hash and converts its value into float
822  * Modifies *value only if the conversion was successful.
823  * Returns -1 if the parameter is not available and -2 if it is available
824  * but the value cannot be retrieved.
825  */
get_optlist_element_as_float(PSDoc * psdoc,ght_hash_table_t * opthash,const char * name,float * value)826 int get_optlist_element_as_float(PSDoc *psdoc, ght_hash_table_t *opthash, const char *name, float *value) {
827 	float tmp;
828 	char *strval;
829 	char *endval;
830 
831 	if(NULL == opthash) {
832 		return(-1);
833 	}
834 	if(NULL == (strval = ght_get(opthash, strlen(name)+1, (void *) name))) {
835 		return(-1);
836 	}
837 	tmp = (float) strtod(strval, &endval);
838 	if(endval == strval) {
839 		return(-2);
840 	}
841 	*value = tmp;
842 	return(0);
843 }
844 /* }}} */
845 
846 /* get_optlist_element_as_int() {{{
847  * Retrieves an element from the hash and converts its value into integer
848  * Modifies *value only if the conversion was successful.
849  * Returns -1 if the parameter is not available and -2 if it is available
850  * but the value cannot be retrieved.
851  */
get_optlist_element_as_int(PSDoc * psdoc,ght_hash_table_t * opthash,const char * name,int * value)852 int get_optlist_element_as_int(PSDoc *psdoc, ght_hash_table_t *opthash, const char *name, int *value) {
853 	long tmp;
854 	char *strval;
855 	char *endval;
856 
857 	if(NULL == opthash) {
858 		return(-1);
859 	}
860 	if(NULL == (strval = ght_get(opthash, strlen(name)+1, (void *) name))) {
861 		return(-1);
862 	}
863 	tmp = strtol(strval, &endval, 10);
864 	if(endval == strval) {
865 		return(-2);
866 	}
867 	*value = tmp;
868 	return(0);
869 }
870 /* }}} */
871 
872 /* get_optlist_element_as_bool() {{{
873  * Retrieves an element from the hash and converts its value into boolean
874  * Returns -1 if the parameter is not available and -2 if it is available
875  * but the value cannot be retrieved.
876  */
get_optlist_element_as_bool(PSDoc * psdoc,ght_hash_table_t * opthash,const char * name,ps_bool * value)877 int get_optlist_element_as_bool(PSDoc *psdoc, ght_hash_table_t *opthash, const char *name, ps_bool *value) {
878 	char *strval;
879 
880 	if(NULL == opthash) {
881 		return(-1);
882 	}
883 	if(NULL == (strval = ght_get(opthash, strlen(name)+1, (void *) name))) {
884 		return(-1);
885 	}
886 	if(strcmp(strval, "false") == 0) {
887 		*value = ps_false;
888 	} else if(strcmp(strval, "true") == 0) {
889 		*value = ps_true;
890 	} else {
891 		return(-2);
892 	}
893 	return(0);
894 }
895 /* }}} */
896 
897 /* get_optlist_element_as_string() {{{
898  * Retrieves an element from the hash and converts its value into string
899  * Returns -1 if the parameter is not available
900  */
get_optlist_element_as_string(PSDoc * psdoc,ght_hash_table_t * opthash,const char * name,char ** value)901 int get_optlist_element_as_string(PSDoc *psdoc, ght_hash_table_t *opthash, const char *name, char **value) {
902 	char *strval;
903 
904 	if(NULL == opthash) {
905 		return(-1);
906 	}
907 	if(NULL == (strval = ght_get(opthash, strlen(name)+1, (void *) name))) {
908 		return(-1);
909 	}
910 
911 	*value = strval;
912 
913 	return(0);
914 }
915 /* }}} */
916 
917 /*
918  * Local variables:
919  * tab-width: 4
920  * c-basic-offset: 4
921  * End:
922  * vim600: sw=2 ts=2 fdm=marker
923  * vim<600: sw=2 ts=2
924  */
925