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 
15 #include "tcldot.h"
16 
17 /*
18  * myiodisc_afread - same api as read for libcgraph
19  *
20  * gets one line at a time from a Tcl_Channel and places it in a user buffer
21  *    up to a maximum of n characters
22  *
23  * returns pointer to obtained line in user buffer, or
24  * returns NULL when last line read from memory buffer
25  *
26  * This is probably innefficient because it introduces
27  * one more stage of line buffering during reads (at least)
28  * but it is needed so that we can take full advantage
29  * of the Tcl_Channel mechanism.
30  */
myiodisc_afread(void * channel,char * ubuf,int n)31 int myiodisc_afread(void* channel, char *ubuf, int n)
32 {
33     static Tcl_DString dstr;
34     static int strpos;
35     int nput;
36 
37     if (!n) {			/* a call with n==0 (from aglexinit) resets */
38 	*ubuf = '\0';
39 	strpos = 0;
40 	return 0;
41     }
42 
43     /*
44      * the user buffer might not be big enough to hold the line.
45      */
46     if (strpos) {
47 	nput = Tcl_DStringLength(&dstr) - strpos;
48 	if (nput > n) {
49 	    /* chunk between first and last */
50 	    memcpy(ubuf, (strpos + Tcl_DStringValue(&dstr)), n);
51 	    strpos += n;
52 	    nput = n;
53 	    ubuf[n] = '\0';
54 	} else {
55 	    /* last chunk */
56 	    memcpy(ubuf, (strpos + Tcl_DStringValue(&dstr)), nput);
57 	    strpos = 0;
58 	}
59     } else {
60 	Tcl_DStringFree(&dstr);
61 	Tcl_DStringInit(&dstr);
62 	if (Tcl_Gets((Tcl_Channel) channel, &dstr) < 0) {
63 	    /* probably EOF, but could be other read errors */
64 	    *ubuf = '\0';
65 	    return 0;
66 	}
67 	/* linend char(s) were stripped off by Tcl_Gets,
68 	 * append a canonical linenend. */
69 	Tcl_DStringAppend(&dstr, "\n", 1);
70 	if (Tcl_DStringLength(&dstr) > n) {
71 	    /* first chunk */
72 	    nput = n;
73 	    memcpy(ubuf, Tcl_DStringValue(&dstr), n);
74 	    strpos = n;
75 	} else {
76 	    /* single chunk */
77 	    nput = Tcl_DStringLength(&dstr);
78 	    memcpy(ubuf, Tcl_DStringValue(&dstr),nput);
79 	}
80     }
81     return nput;
82 }
83 
84 
85 /* exact copy from cgraph/io.c - but that one is static */
myiodisc_memiofread(void * chan,char * buf,int bufsize)86 int myiodisc_memiofread(void *chan, char *buf, int bufsize)
87 {
88     const char *ptr;
89     char *optr;
90     char c;
91     int l;
92     rdr_t *s;
93 
94     if (bufsize == 0) return 0;
95     s = (rdr_t *) chan;
96     if (s->cur >= s->len)
97         return 0;
98     l = 0;
99     ptr = s->data + s->cur;
100     optr = buf;
101     do {
102         *optr++ = c = *ptr++;
103         l++;
104     } while (c && (c != '\n') && (l < bufsize));
105     s->cur += l;
106     return l;
107 }
108 
109 #if 0
110 Agraph_t *agread_usergets (ictx_t *ictx, FILE * fp, int (*usergets)(void *chan, char *buf, int bufsize))
111 {
112     Agraph_t* g;
113     Agiodisc_t ioDisc;
114 
115     ioDisc.afread = usergets;
116     ioDisc.putstr = AgIoDisc.putstr;
117     ioDisc.flush = AgIoDisc.flush;
118 
119     ictx->mydisc.io = &ioDisc;
120     g = agread (fp, (Agdisc_t *)ictx);
121     ictx->mydisc.io = &AgIoDisc;   /* restore io */
122     return g;
123 }
124 
125 #endif
126