Graphviz 14.1.2~dev.20260120.0924
Loading...
Searching...
No Matches
agerror.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include "config.h"
17
18#include <cgraph/cghdr.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <util/agxbuf.h>
23#include <util/gv_ctype.h>
24#include <util/gv_math.h>
25#include <util/streq.h>
26
27static agerrlevel_t agerrno; /* Last error level */
28static agerrlevel_t agerrlevel = AGWARN; /* Report errors >= agerrlevel */
29static int agmaxerr;
30
31static agxbuf last;
32static agusererrf usererrf; /* User-set error function */
33
35 agusererrf oldf = usererrf;
36 usererrf = newf;
37 return oldf;
38}
39
42 agerrlevel = lvl;
43 return oldv;
44}
45
46char *aglasterr(void) {
47 // Extract a heap-allocated copy of the last message. Note that this resets
48 // `last` to an empty buffer ready to be written to again.
49 char *buf = agxbdisown(&last);
50
51 // store the message back again so multiple calls to `aglasterr` can be made
52 // without losing the last error
53 agxbput(&last, buf);
54
55 // was there no last message?
56 if (streq(buf, "")) {
57 free(buf);
58 return NULL;
59 }
60
61 return buf;
62}
63
65static int default_usererrf(char *message) {
66 // `fputs`, escaping characters that may interfere with a terminal
67 for (const char *p = message; *p != '\0'; ++p) {
68
69 if (gv_iscntrl(*p) && !gv_isspace(*p)) {
70 const int rc = fprintf(stderr, "\\%03o", (unsigned)*p);
71 if (rc < 0) {
72 return rc;
73 }
74 continue;
75 }
76
77 const int rc = putc(*p, stderr);
78 if (rc < 0) {
79 return rc;
80 }
81 }
82 return 0;
83}
84
86static void out(agerrlevel_t level, const char *fmt, va_list args) {
87 // find out how much space we need to construct this string
88 size_t bufsz;
89 {
90 va_list args2;
91 va_copy(args2, args);
92 int rc = vsnprintf(NULL, 0, fmt, args2);
93 va_end(args2);
94 if (rc < 0) {
95 fprintf(stderr, "%s: vsnprintf failure\n", __func__);
96 return;
97 }
98 bufsz = (size_t)rc + 1; // account for NUL terminator
99 }
100
101 // allocate a buffer for the string
102 char *buf = malloc(bufsz);
103 if (buf == NULL) {
104 fprintf(stderr, "%s: could not allocate memory\n", __func__);
105 return;
106 }
107
108 // determine how errors are to be reported
110
111 if (level != AGPREV) {
112 (void)errf(level == AGERR ? "Error" : "Warning");
113 (void)errf(": ");
114 }
115
116 // construct the full error in our buffer
117 int rc = vsnprintf(buf, bufsz, fmt, args);
118 if (rc < 0) {
119 free(buf);
120 fprintf(stderr, "%s: vsnprintf failure\n", __func__);
121 return;
122 }
123
124 // yield our constructed error
125 (void)errf(buf);
126
127 free(buf);
128}
129
130static int agerr_va(agerrlevel_t level, const char *fmt, va_list args) {
131 agerrlevel_t lvl;
132
133 /* Use previous error level if continuation message;
134 * Convert AGMAX to AGERROR;
135 * else use input level
136 */
137 lvl = (level == AGPREV ? agerrno : (level == AGMAX) ? AGERR : level);
138
139 /* store this error level */
140 agerrno = lvl;
141 agmaxerr = imax(agmaxerr, (int)agerrno);
142
143 /* We report all messages whose level is bigger than the user set agerrlevel
144 * Setting agerrlevel to AGMAX turns off immediate error reporting.
145 */
146 if (lvl >= agerrlevel) {
147 out(level, fmt, args);
148 return 0;
149 }
150
151 if (level != AGPREV)
152 agxbclear(&last);
153 vagxbprint(&last, fmt, args);
154 return 0;
155}
156
157int agerr(agerrlevel_t level, const char *fmt, ...) {
158 va_list args;
159 int ret;
160
161 va_start(args, fmt);
162 ret = agerr_va(level, fmt, args);
163 va_end(args);
164 return ret;
165}
166
167void agerrorf(const char *fmt, ...) {
168 va_list args;
169
170 va_start(args, fmt);
171 agerr_va(AGERR, fmt, args);
172 va_end(args);
173}
174
175void agwarningf(const char *fmt, ...) {
176 va_list args;
177
178 va_start(args, fmt);
179 agerr_va(AGWARN, fmt, args);
180 va_end(args);
181}
182
183int agerrors(void) { return agmaxerr; }
184
185int agreseterrors(void) {
186 int rc = agmaxerr;
187 agmaxerr = 0;
188 return rc;
189}
static agusererrf usererrf
Definition agerror.c:32
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:86
static agerrlevel_t agerrlevel
Definition agerror.c:28
static int default_usererrf(char *message)
default error reporting implementation
Definition agerror.c:65
static int agmaxerr
Definition agerror.c:29
static agerrlevel_t agerrno
Definition agerror.c:27
static agxbuf last
last message
Definition agerror.c:31
static int agerr_va(agerrlevel_t level, const char *fmt, va_list args)
Definition agerror.c:130
Dynamically expanding string buffers.
static void agxbclear(agxbuf *xb)
resets pointer to data
Definition agxbuf.h:312
static int vagxbprint(agxbuf *xb, const char *fmt, va_list ap)
vprintf-style output to an agxbuf
Definition agxbuf.h:181
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:345
cgraph.h additions
void * malloc(YYSIZE_T)
void free(void *)
node NULL
Definition grammar.y:181
agerrlevel_t
Definition cgraph.h:946
int agreseterrors(void)
Definition agerror.c:185
void agwarningf(const char *fmt,...)
Definition agerror.c:175
void agerrorf(const char *fmt,...)
Definition agerror.c:167
agerrlevel_t agseterr(agerrlevel_t lvl)
Definition agerror.c:40
char * aglasterr(void)
Definition agerror.c:46
agusererrf agseterrf(agusererrf newf)
Definition agerror.c:34
int agerr(agerrlevel_t level, const char *fmt,...)
Definition agerror.c:157
int agerrors(void)
Definition agerror.c:183
int(* agusererrf)(char *)
Definition cgraph.h:947
@ AGWARN
Definition cgraph.h:946
@ AGMAX
Definition cgraph.h:946
@ AGERR
Definition cgraph.h:946
@ AGPREV
Definition cgraph.h:946
replacements for ctype.h functions
static bool gv_iscntrl(int c)
Definition gv_ctype.h:33
static bool gv_isspace(int c)
Definition gv_ctype.h:55
Arithmetic helper functions.
static int imax(int a, int b)
maximum of two integers
Definition gv_math.h:26
agxbput(xb, staging)
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11