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/*
16 * Written by Emden Gansner
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21
22#define FREE_STATE 1
23
24typedef struct {
25 char *dummy;
26} Agraph_t;
27
28extern void agsetfile(char *);
29
30#include "ingraphs.h"
31
32/* nextFile:
33 * Set next available file.
34 * If Files is NULL, we just read from stdin.
35 */
36static void nextFile(ingraph_state * sp)
37{
38 void *rv = NULL;
39 char *fname;
40
41 if (sp->u.Files == NULL) {
42 if (sp->ctr++ == 0) {
43 rv = sp->fns->dflt;
44 }
45 } else {
46 while ((fname = sp->u.Files[sp->ctr++])) {
47 if (*fname == '-') {
48 rv = sp->fns->dflt;
49 break;
50 } else if ((rv = sp->fns->openf(fname)) != 0)
51 break;
52 else {
53 fprintf(stderr, "Can't open %s\n", sp->u.Files[sp->ctr - 1]);
54 sp->errors++;
55 }
56 }
57 }
58 if (rv)
59 agsetfile(fileName(sp));
60 sp->fp = rv;
61}
62
63/* nextGraph:
64 * Read and return next graph; return NULL if done.
65 * Read graph from currently open file. If none, open next file.
66 */
67Agraph_t *nextGraph(ingraph_state * sp)
68{
69 Agraph_t *g;
70
71 if (sp->ingraphs) {
72 g = (Agraph_t*)(sp->u.Graphs[sp->ctr]);
73 if (g) sp->ctr++;
74 return g;
75 }
76 if (sp->fp == NULL)
77 nextFile(sp);
78 g = NULL;
79
80 while (sp->fp != NULL) {
81 if ((g = sp->fns->readf(sp->fp)) != 0)
82 break;
83 if (sp->u.Files) /* Only close if not using stdin */
84 sp->fns->closef(sp->fp);
85 nextFile(sp);
86 }
87 return g;
88}
89
90/* new_ing:
91 * Create new ingraph state. If sp is non-NULL, we
92 * assume user is supplying memory.
93 */
94static ingraph_state*
95new_ing(ingraph_state * sp, char **files, Agraph_t** graphs, ingdisc * disc)
96{
97 if (!sp) {
98 sp = (ingraph_state *) malloc(sizeof(ingraph_state));
99 if (!sp) {
100 fprintf(stderr, "ingraphs: out of memory\n");
101 return 0;
102 }
103 sp->heap = 1;
104 } else
105 sp->heap = 0;
106 if (graphs) {
107 sp->ingraphs = 1;
108 sp->u.Graphs = graphs;
109 }
110 else {
111 sp->ingraphs = 0;
112 sp->u.Files = files;
113 }
114 sp->ctr = 0;
115 sp->errors = 0;
116 sp->fp = NULL;
117 sp->fns = (ingdisc *) malloc(sizeof(ingdisc));
118 if (!sp->fns) {
119 fprintf(stderr, "ingraphs: out of memory\n");
120 if (sp->heap)
121 free(sp);
122 return 0;
123 }
124 if (!disc->openf || !disc->readf || !disc->closef || !disc->dflt) {
125 free(sp->fns);
126 if (sp->heap)
127 free(sp);
128 fprintf(stderr, "ingraphs: NULL field in ingdisc argument\n");
129 return 0;
130 }
131 *sp->fns = *disc;
132 return sp;
133}
134
135ingraph_state*
136newIng(ingraph_state * sp, char **files, ingdisc * disc)
137{
138 return new_ing(sp, files, 0, disc);
139}
140
141/* newIngGraphs:
142 * Create new ingraph state using supplied graphs. If sp is non-NULL, we
143 * assume user is supplying memory.
144 */
145ingraph_state*
146newIngGraphs(ingraph_state * sp , Agraph_t** graphs, ingdisc *disc)
147{
148 return new_ing(sp, 0, graphs, disc);
149}
150
151static void *dflt_open(char *f)
152{
153 return fopen(f, "r");
154}
155
156static int dflt_close(void *fp)
157{
158 return fclose((FILE *) fp);
159}
160
161typedef Agraph_t *(*xopengfn) (void *);
162
163static ingdisc dflt_disc = { dflt_open, 0, dflt_close, 0 };
164
165/* newIngraph:
166 * At present, we require opf to be non-NULL. In
167 * theory, we could assume a function agread(FILE*,void*)
168 */
169ingraph_state *newIngraph(ingraph_state * sp, char **files, opengfn opf)
170{
171 if (!dflt_disc.dflt)
172 dflt_disc.dflt = stdin;
173 if (opf)
174 dflt_disc.readf = (xopengfn) opf;
175 else {
176 fprintf(stderr, "ingraphs: NULL graph reader\n");
177 return 0;
178 }
179 return newIng(sp, files, &dflt_disc);
180}
181
182/* closeIngraph:
183 * Close any open files and free discipline
184 * Free sp if necessary.
185 */
186void closeIngraph(ingraph_state * sp)
187{
188 if (!sp->ingraphs && sp->u.Files && sp->fp)
189 sp->fns->closef(sp->fp);
190 free(sp->fns);
191 if (sp->heap)
192 free(sp);
193}
194
195/* fileName:
196 * Return name of current file being processed.
197 */
198char *fileName(ingraph_state * sp)
199{
200 char *fname;
201
202 if (sp->ingraphs) {
203 return "<>";
204 }
205 else if (sp->u.Files) {
206 if (sp->ctr) {
207 fname = sp->u.Files[sp->ctr - 1];
208 if (*fname == '-')
209 return "<stdin>";
210 else
211 return fname;
212 } else
213 return "<>";
214 } else
215 return "<stdin>";
216}
217
218#include "config.h"
219