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))
18 static agerrlevel_t agerrno;		/* Last error level */
19 static agerrlevel_t agerrlevel = AGWARN;	/* Report errors >= agerrlevel */
20 static int agmaxerr;
21 
22 static long aglast;		/* Last message */
23 static FILE *agerrout;		/* Message file */
24 static agusererrf usererrf;     /* User-set error function */
25 
26 agusererrf
agseterrf(agusererrf newf)27 agseterrf (agusererrf newf)
28 {
29     agusererrf oldf = usererrf;
30     usererrf = newf;
31     return oldf;
32 }
33 
agseterr(agerrlevel_t lvl)34 agerrlevel_t agseterr(agerrlevel_t lvl)
35 {
36     agerrlevel_t oldv = agerrlevel;
37     agerrlevel = lvl;
38     return oldv;
39 }
40 
aglasterr()41 char *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  */
64 static void
userout(agerrlevel_t level,const char * fmt,va_list args)65 userout (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 
agerr_va(agerrlevel_t level,const char * fmt,va_list args)102 static 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 
agerr(agerrlevel_t level,const char * fmt,...)143 int 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 
agerrorf(const char * fmt,...)154 void 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 
agwarningf(const char * fmt,...)163 void 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 
agerrors()172 int agerrors() { return agmaxerr; }
173 
agreseterrors()174 int agreseterrors()
175 {
176     int rc = agmaxerr;
177     agmaxerr = 0;
178     return rc;
179 }
180 
181