Browse code

Second version bump after creating 2.14 release branch.

git-svn-id: https://hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/Rgraphviz@88840 bc3139a8-67e5-0310-9ffc-ced21a209358

d.tenenbaum authored on 11/04/2014 21:21:21
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,307 @@
1
+/* $Id: psusershape.c,v 1.34 2011/01/25 16:30:48 ellson Exp $ $Revision: 1.34 $ */
2
+/* vim:set shiftwidth=4 ts=8: */
3
+
4
+/*************************************************************************
5
+ * Copyright (c) 2011 AT&T Intellectual Property 
6
+ * All rights reserved. This program and the accompanying materials
7
+ * are made available under the terms of the Eclipse Public License v1.0
8
+ * which accompanies this distribution, and is available at
9
+ * http://www.eclipse.org/legal/epl-v10.html
10
+ *
11
+ * Contributors: See CVS logs. Details at http://www.graphviz.org/
12
+ *************************************************************************/
13
+
14
+#ifndef WIN32
15
+#include <unistd.h>
16
+#endif
17
+
18
+#include <sys/stat.h>
19
+
20
+#include "render.h"
21
+#include "gvio.h"
22
+
23
+static int N_EPSF_files;
24
+static Dict_t *EPSF_contents;
25
+
26
+static void ps_image_free(Dict_t * dict, usershape_t * p, Dtdisc_t * disc)
27
+{
28
+    free(p->data);
29
+}
30
+
31
+static Dtdisc_t ImageDictDisc = {
32
+    offsetof(usershape_t, name),/* key */
33
+    -1,				/* size */
34
+    0,				/* link offset */
35
+    NIL(Dtmake_f),
36
+    (Dtfree_f) ps_image_free,
37
+    NIL(Dtcompar_f),
38
+    NIL(Dthash_f),
39
+    NIL(Dtmemory_f),
40
+    NIL(Dtevent_f)
41
+};
42
+
43
+static usershape_t *user_init(const char *str)
44
+{
45
+    char *contents;
46
+    char line[BUFSIZ];
47
+    FILE *fp;
48
+    struct stat statbuf;
49
+    int saw_bb, must_inline, rc;
50
+    int lx, ly, ux, uy;
51
+    usershape_t *us;
52
+
53
+    if (!EPSF_contents)
54
+	EPSF_contents = dtopen(&ImageDictDisc, Dtoset);
55
+
56
+    us = dtmatch(EPSF_contents, str);
57
+    if (us)
58
+	return us;
59
+
60
+    if (!(fp = fopen(str, "r"))) {
61
+	agerr(AGWARN, "couldn't open epsf file %s\n", str);
62
+	return NULL;
63
+    }
64
+    /* try to find size */
65
+    saw_bb = must_inline = FALSE;
66
+    while (fgets(line, sizeof(line), fp)) {
67
+	if (sscanf
68
+	    (line, "%%%%BoundingBox: %d %d %d %d", &lx, &ly, &ux, &uy) == 4) {
69
+	    saw_bb = TRUE;
70
+	}
71
+	if ((line[0] != '%') && strstr(line,"read")) must_inline = TRUE;
72
+	if (saw_bb && must_inline) break;
73
+    }
74
+
75
+    if (saw_bb) {
76
+	us = GNEW(usershape_t);
77
+	us->x = lx;
78
+	us->y = ly;
79
+	us->w = ux - lx;
80
+	us->y = uy - ly;
81
+	us->name = str;
82
+	us->macro_id = N_EPSF_files++;
83
+	fstat(fileno(fp), &statbuf);
84
+	contents = us->data = N_GNEW(statbuf.st_size + 1, char);
85
+	fseek(fp, 0, SEEK_SET);
86
+	rc = fread(contents, statbuf.st_size, 1, fp);
87
+	contents[statbuf.st_size] = '\0';
88
+	dtinsert(EPSF_contents, us);
89
+	us->must_inline = must_inline;
90
+    } else {
91
+	agerr(AGWARN, "BoundingBox not found in epsf file %s\n", str);
92
+	us = NULL;
93
+    }
94
+    fclose(fp);
95
+    return us;
96
+}
97
+
98
+void epsf_init(node_t * n)
99
+{
100
+    epsf_t *desc;
101
+    const char *str;
102
+    usershape_t *us;
103
+    int dx, dy;
104
+
105
+    if ((str = safefile(agget(n, "shapefile")))) {
106
+	us = user_init(str);
107
+	if (!us)
108
+	    return;
109
+	dx = us->w;
110
+	dy = us->h;
111
+	ND_width(n) = PS2INCH(dx);
112
+	ND_height(n) = PS2INCH(dy);
113
+	ND_shape_info(n) = desc = NEW(epsf_t);
114
+	desc->macro_id = us->macro_id;
115
+	desc->offset.x = -us->x - (dx) / 2;
116
+	desc->offset.y = -us->y - (dy) / 2;
117
+    } else
118
+	agerr(AGWARN, "shapefile not set or not found for epsf node %s\n", agnameof(n));
119
+}
120
+
121
+void epsf_free(node_t * n)
122
+{
123
+
124
+    if (ND_shape_info(n))
125
+	free(ND_shape_info(n));
126
+}
127
+
128
+
129
+/* cat_libfile:
130
+ * Write library files onto the given file pointer.
131
+ * arglib is an NULL-terminated array of char*
132
+ * Each non-trivial entry should be the name of a file to be included.
133
+ * stdlib is an NULL-terminated array of char*
134
+ * Each of these is a line of a standard library to be included.
135
+ * If any item in arglib is the empty string, the stdlib is not used.
136
+ * The stdlib is printed first, if used, followed by the user libraries.
137
+ * We check that for web-safe file usage.
138
+ */
139
+void cat_libfile(GVJ_t * job, const char **arglib, const char **stdlib)
140
+{
141
+    FILE *fp;
142
+    const char **s, *bp, *p, *path;
143
+    int i;
144
+    boolean use_stdlib = TRUE;
145
+
146
+    /* check for empty string to turn off stdlib */
147
+    if (arglib) {
148
+        for (i = 0; use_stdlib && ((p = arglib[i])); i++) {
149
+            if (*p == '\0')
150
+                use_stdlib = FALSE;
151
+        }
152
+    }
153
+    if (use_stdlib)
154
+        for (s = stdlib; *s; s++) {
155
+            gvputs(job, *s);
156
+            gvputs(job, "\n");
157
+        }
158
+    if (arglib) {
159
+        for (i = 0; (p = arglib[i]) != 0; i++) {
160
+            if (*p == '\0')
161
+                continue;       /* ignore empty string */
162
+            path = safefile(p);    /* make sure filename is okay */
163
+	    if (!path) {
164
+		agerr(AGWARN, "can't find library file %s\n", p);
165
+	    }
166
+            else if ((fp = fopen(path, "r"))) {
167
+                while ((bp = Fgets(fp)))
168
+                    gvputs(job, bp);
169
+                gvputs(job, "\n"); /* append a newline just in case */
170
+		fclose (fp);
171
+            } else
172
+                agerr(AGWARN, "can't open library file %s\n", path);
173
+        }
174
+    }
175
+}
176
+
177
+#define FILTER_EPSF 1
178
+#ifdef FILTER_EPSF
179
+/* this removes EPSF DSC comments that, when nested in another
180
+ * document, cause errors in Ghostview and other Postscript
181
+ * processors (although legal according to the Adobe EPSF spec).
182
+ *
183
+ * N.B. PostScript lines can end with \n, \r or \r\n.
184
+ */
185
+void epsf_emit_body(GVJ_t *job, usershape_t *us)
186
+{
187
+    char *p;
188
+    char c;
189
+    p = us->data;
190
+    while (*p) {
191
+	/* skip %%EOF lines */
192
+	if ((p[0] == '%') && (p[1] == '%')
193
+		&& (!strncasecmp(&p[2], "EOF", 3)
194
+		|| !strncasecmp(&p[2], "BEGIN", 5)
195
+		|| !strncasecmp(&p[2], "END", 3)
196
+		|| !strncasecmp(&p[2], "TRAILER", 7)
197
+	)) {
198
+	    /* check for *p since last line might not end in '\n' */
199
+	    while ((c = *p) && (c != '\r') && (c != '\n')) p++;
200
+	    if ((*p == '\r') && (*(p+1) == '\n')) p += 2;
201
+	    else if (*p) p++;
202
+	    continue;
203
+	}
204
+	/* output line */
205
+	while ((c = *p) && (c != '\r') && (c != '\n')) {
206
+	    gvputc(job, c);
207
+	    p++;
208
+	}
209
+	if ((*p == '\r') && (*(p+1) == '\n')) p += 2;
210
+	else if (*p) p++;
211
+	gvputc(job, '\n');
212
+    }
213
+}
214
+#else
215
+void epsf_emit_body(GVJ_t *job, usershape_t *us)
216
+{
217
+	gvputs(job, us->data);
218
+}
219
+#endif
220
+
221
+void epsf_define(GVJ_t *job)
222
+{
223
+    usershape_t *us;
224
+
225
+    if (!EPSF_contents)
226
+	return;
227
+    for (us = dtfirst(EPSF_contents); us; us = dtnext(EPSF_contents, us)) {
228
+	if (us->must_inline)
229
+	    continue;
230
+	gvprintf(job, "/user_shape_%d {\n", us->macro_id);
231
+	gvputs(job, "%%BeginDocument:\n");
232
+	epsf_emit_body(job, us);
233
+	gvputs(job, "%%EndDocument\n");
234
+	gvputs(job, "} bind def\n");
235
+    }
236
+}
237
+
238
+enum {ASCII, LATIN1, NONLATIN};
239
+
240
+/* charsetOf:
241
+ * Assuming legal utf-8 input, determine if
242
+ * the character value range is ascii, latin-1 or otherwise.
243
+ */
244
+static int
245
+charsetOf (char* s)
246
+{
247
+    int r = ASCII;
248
+    unsigned char c;
249
+
250
+    while ((c = *(unsigned char*)s++)) {
251
+	if (c < 0x7F) 
252
+	    continue;
253
+	else if ((c & 0xFC) == 0xC0) {
254
+	    r = LATIN1;
255
+	    s++; /* eat second byte */
256
+	}
257
+	else return NONLATIN;
258
+    }
259
+    return r;
260
+}
261
+
262
+char *ps_string(char *ins, int latin)
263
+{
264
+    char *s;
265
+    char *base;
266
+    static agxbuf  xb;
267
+    static int warned;
268
+    int rc;
269
+
270
+    if (latin)
271
+        base = utf8ToLatin1 (ins);
272
+    else {
273
+	switch (charsetOf (ins)) {
274
+	case ASCII :
275
+	    base = ins;
276
+	    break;
277
+	case LATIN1 :
278
+	    base = utf8ToLatin1 (ins);
279
+	    break;
280
+	case NONLATIN :
281
+	    if (!warned) {
282
+		agerr (AGWARN, "UTF-8 input uses non-Latin1 characters which cannot be handled by this PostScript driver\n");
283
+		warned = 1;
284
+	    }
285
+	    base = ins;
286
+	    break;
287
+	default:
288
+	    base = ins;
289
+	    break;
290
+	}
291
+    }
292
+
293
+    if (xb.buf == NULL)
294
+        agxbinit (&xb, 0, NULL);
295
+
296
+    rc = agxbputc (&xb, LPAREN);
297
+    s = base;
298
+    while (*s) {
299
+        if ((*s == LPAREN) || (*s == RPAREN) || (*s == '\\'))
300
+            rc = agxbputc (&xb, '\\');
301
+        rc = agxbputc (&xb, *s++);
302
+    }
303
+    agxbputc (&xb, RPAREN);
304
+    if (base != ins) free (base);
305
+    s = agxbuse(&xb);
306
+    return s;
307
+}