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
17#define MAX(a,b) ((a)>(b)?(a):(b))
18static agerrlevel_t agerrno; /* Last error level */
19static agerrlevel_t agerrlevel = AGWARN; /* Report errors >= agerrlevel */
20static int agmaxerr;
21
22static long aglast; /* Last message */
23static FILE *agerrout; /* Message file */
24static agusererrf usererrf; /* User-set error function */
25
26agusererrf
27agseterrf (agusererrf newf)
28{
29 agusererrf oldf = usererrf;
30 usererrf = newf;
31 return oldf;
32}
33
34agerrlevel_t agseterr(agerrlevel_t lvl)
35{
36 agerrlevel_t oldv = agerrlevel;
37 agerrlevel = lvl;
38 return oldv;
39}
40
41char *aglasterr()
42{
43 long endpos;
44 long len;
45 char *buf;
46
47 if (!agerrout)
48 return 0;
49 fflush(agerrout);
50 endpos = ftell(agerrout);
51 len = endpos - aglast;
52 buf = (char*)malloc(len + 1);
53 fseek(agerrout, aglast, SEEK_SET);
54 fread(buf, sizeof(char), len, agerrout);
55 buf[len] = '\0';
56 fseek(agerrout, endpos, SEEK_SET);
57
58 return buf;
59}
60
61/* userout:
62 * Report messages using a user-supplied write function
63 */
64static void
65userout (agerrlevel_t level, const char *fmt, va_list args)
66{
67 static char* buf;
68 static int bufsz = 1024;
69 char* np;
70 int n;
71
72 if (!buf) {
73 buf = (char*)malloc(bufsz);
74 if (!buf) {
75 fputs("userout: could not allocate memory\n", stderr );
76 return;
77 }
78 }
79
80 if (level != AGPREV) {
81 usererrf ((level == AGERR) ? "Error" : "Warning");
82 usererrf (": ");
83 }
84
85 while (1) {
86 n = vsnprintf(buf, bufsz, fmt, args);
87 if ((n > -1) && (n < bufsz)) {
88 usererrf (buf);
89 break;
90 }
91 bufsz = MAX(bufsz*2,n+1);
92 if ((np = (char*)realloc(buf, bufsz)) == NULL) {
93 fputs("userout: could not allocate memory\n", stderr );
94 free(buf);
95 return;
96 }
97 buf = np;
98 }
99 va_end(args);
100}
101
102static int agerr_va(agerrlevel_t level, const char *fmt, va_list args)
103{
104 agerrlevel_t lvl;
105
106 /* Use previous error level if continuation message;
107 * Convert AGMAX to AGERROR;
108 * else use input level
109 */
110 lvl = (level == AGPREV ? agerrno : (level == AGMAX) ? AGERR : level);
111
112 /* store this error level */
113 agerrno = lvl;
114 agmaxerr = MAX(agmaxerr, agerrno);
115
116 /* We report all messages whose level is bigger than the user set agerrlevel
117 * Setting agerrlevel to AGMAX turns off immediate error reporting.
118 */
119 if (lvl >= agerrlevel) {
120 if (usererrf)
121 userout (level, fmt, args);
122 else {
123 if (level != AGPREV)
124 fprintf(stderr, "%s: ", (level == AGERR) ? "Error" : "Warning");
125 vfprintf(stderr, fmt, args);
126 va_end(args);
127 }
128 return 0;
129 }
130
131 if (!agerrout) {
132 agerrout = tmpfile();
133 if (!agerrout)
134 return 1;
135 }
136
137 if (level != AGPREV)
138 aglast = ftell(agerrout);
139 vfprintf(agerrout, fmt, args);
140 return 0;
141}
142
143int agerr(agerrlevel_t level, const char *fmt, ...)
144{
145 va_list args;
146 int ret;
147
148 va_start(args, fmt);
149 ret = agerr_va(level, fmt, args);
150 va_end(args);
151 return ret;
152}
153
154void agerrorf(const char *fmt, ...)
155{
156 va_list args;
157
158 va_start(args, fmt);
159 agerr_va(AGERR, fmt, args);
160 va_end(args);
161}
162
163void agwarningf(const char *fmt, ...)
164{
165 va_list args;
166
167 va_start(args, fmt);
168 agerr_va(AGWARN, fmt, args);
169 va_end(args);
170}
171
172int agerrors() { return agmaxerr; }
173
174int agreseterrors()
175{
176 int rc = agmaxerr;
177 agmaxerr = 0;
178 return rc;
179}
180
181