1 | /* $Id$ $Revision$ */ |
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 | #include <stdio.h> |
15 | #include <cghdr.h> |
16 | #if defined(_WIN32) |
17 | #include <io.h> |
18 | #endif |
19 | |
20 | /* experimental ICONV code - probably should be removed - JCE */ |
21 | #undef HAVE_ICONV |
22 | |
23 | #ifdef HAVE_ICONV |
24 | #include <iconv.h> |
25 | #include <langinfo.h> |
26 | #include <errno.h> |
27 | #endif |
28 | |
29 | #ifdef HAVE_ICONV |
30 | static int iofreadiconv(void *chan, char *buf, int bufsize) |
31 | { |
32 | #define CHARBUFSIZE 30 |
33 | static char charbuf[CHARBUFSIZE]; |
34 | static iconv_t cd = NULL; |
35 | char *inbuf, *outbuf, *readbuf; |
36 | size_t inbytesleft, outbytesleft, readbytesleft, resbytes, result; |
37 | int fd; |
38 | |
39 | if (!cd) { |
40 | cd = iconv_open(nl_langinfo(CODESET), "UTF-8" ); |
41 | } |
42 | fd = fileno((FILE *) chan); |
43 | readbuf = inbuf = charbuf; |
44 | readbytesleft = CHARBUFSIZE; |
45 | inbytesleft = 0; |
46 | outbuf = buf; |
47 | outbytesleft = bufsize - 1; |
48 | while (1) { |
49 | if ((result = read(fd, readbuf++, 1)) != 1) |
50 | break; |
51 | readbytesleft--; |
52 | inbytesleft++; |
53 | result = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); |
54 | if (result != -1) { |
55 | readbuf = inbuf = charbuf; |
56 | readbytesleft = CHARBUFSIZE; |
57 | inbytesleft = 0; |
58 | } else if (errno != EINVAL) |
59 | break; |
60 | } |
61 | *outbuf = '\0'; |
62 | resbytes = bufsize - 1 - outbytesleft; |
63 | if (resbytes) |
64 | result = resbytes; |
65 | return result; |
66 | } |
67 | #endif |
68 | |
69 | static int iofread(void *chan, char *buf, int bufsize) |
70 | { |
71 | if (fgets(buf, bufsize, (FILE*)chan)) |
72 | return strlen(buf); |
73 | else |
74 | return 0; |
75 | /* return read(fileno((FILE *) chan), buf, bufsize); */ |
76 | /* return fread(buf, 1, bufsize, (FILE*)chan); */ |
77 | } |
78 | |
79 | /* default IO methods */ |
80 | static int ioputstr(void *chan, const char *str) |
81 | { |
82 | return fputs(str, (FILE *) chan); |
83 | } |
84 | |
85 | static int ioflush(void *chan) |
86 | { |
87 | return fflush((FILE *) chan); |
88 | } |
89 | |
90 | /* Agiodisc_t AgIoDisc = { iofreadiconv, ioputstr, ioflush }; */ |
91 | Agiodisc_t AgIoDisc = { iofread, ioputstr, ioflush }; |
92 | |
93 | typedef struct { |
94 | const char *data; |
95 | int len; |
96 | int cur; |
97 | } rdr_t; |
98 | |
99 | static int |
100 | memiofread(void *chan, char *buf, int bufsize) |
101 | { |
102 | const char *ptr; |
103 | char *optr; |
104 | char c; |
105 | int l; |
106 | rdr_t *s; |
107 | |
108 | if (bufsize == 0) return 0; |
109 | s = (rdr_t *) chan; |
110 | if (s->cur >= s->len) |
111 | return 0; |
112 | l = 0; |
113 | ptr = s->data + s->cur; |
114 | optr = buf; |
115 | /* We know we have at least one character */ |
116 | c = *ptr++; |
117 | do { |
118 | *optr++ = c; |
119 | l++; |
120 | /* continue if c is not newline, we have space in buffer, |
121 | * and next character is non-null (we are working with |
122 | * null-terminated strings. |
123 | */ |
124 | } while ((c != '\n') && (l < bufsize) && (c = *ptr++)); |
125 | s->cur += l; |
126 | return l; |
127 | } |
128 | |
129 | static Agiodisc_t memIoDisc = {memiofread, 0, 0}; |
130 | |
131 | Agraph_t *agmemread(const char *cp) |
132 | { |
133 | Agraph_t* g; |
134 | rdr_t rdr; |
135 | Agdisc_t disc; |
136 | |
137 | memIoDisc.putstr = AgIoDisc.putstr; |
138 | memIoDisc.flush = AgIoDisc.flush; |
139 | rdr.data = cp; |
140 | rdr.len = strlen(cp); |
141 | rdr.cur = 0; |
142 | |
143 | disc.mem = &AgMemDisc; |
144 | disc.id = &AgIdDisc; |
145 | disc.io = &memIoDisc; |
146 | g = agread (&rdr, &disc); |
147 | /* Null out filename and reset line number |
148 | * The name may have been set with a ppDirective, and |
149 | * we want to reset line_num. |
150 | */ |
151 | agsetfile(NULL); |
152 | return g; |
153 | } |
154 | |
155 | |