1 /* 2 * Error reporting 3 * 4 * Copyright (C) 2010 Red Hat Inc. 5 * 6 * Authors: 7 * Markus Armbruster <armbru (at) redhat.com>, 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include <stdio.h> 14 #include "monitor.h" 15 16 /* 17 * Print to current monitor if we have one, else to stderr. 18 * TODO should return int, so callers can calculate width, but that 19 * requires surgery to monitor_vprintf(). Left for another day. 20 */ 21 void error_vprintf(const char *fmt, va_list ap) 22 { 23 if (cur_mon) { 24 monitor_vprintf(cur_mon, fmt, ap); 25 } else { 26 vfprintf(stderr, fmt, ap); 27 } 28 } 29 30 /* 31 * Print to current monitor if we have one, else to stderr. 32 * TODO just like error_vprintf() 33 */ 34 void error_printf(const char *fmt, ...) 35 { 36 va_list ap; 37 38 va_start(ap, fmt); 39 error_vprintf(fmt, ap); 40 va_end(ap); 41 } 42 43 void error_printf_unless_qmp(const char *fmt, ...) 44 { 45 va_list ap; 46 47 if (!monitor_cur_is_qmp()) { 48 va_start(ap, fmt); 49 error_vprintf(fmt, ap); 50 va_end(ap); 51 } 52 } 53 54 static Location std_loc = { 55 .kind = LOC_NONE 56 }; 57 static Location *cur_loc = &std_loc; 58 59 /* 60 * Push location saved in LOC onto the location stack, return it. 61 * The top of that stack is the current location. 62 * Needs a matching loc_pop(). 63 */ 64 Location *loc_push_restore(Location *loc) 65 { 66 assert(!loc->prev); 67 loc->prev = cur_loc; 68 cur_loc = loc; 69 return loc; 70 } 71 72 /* 73 * Initialize *LOC to "nowhere", push it onto the location stack. 74 * The top of that stack is the current location. 75 * Needs a matching loc_pop(). 76 * Return LOC. 77 */ 78 Location *loc_push_none(Location *loc) 79 { 80 loc->kind = LOC_NONE; 81 loc->prev = NULL; 82 return loc_push_restore(loc); 83 } 84 85 /* 86 * Pop the location stack. 87 * LOC must be the current location, i.e. the top of the stack. 88 */ 89 Location *loc_pop(Location *loc) 90 { 91 assert(cur_loc == loc && loc->prev); 92 cur_loc = loc->prev; 93 loc->prev = NULL; 94 return loc; 95 } 96 97 /* 98 * Save the current location in LOC, return LOC. 99 */ 100 Location *loc_save(Location *loc) 101 { 102 *loc = *cur_loc; 103 loc->prev = NULL; 104 return loc; 105 } 106 107 /* 108 * Change the current location to the one saved in LOC. 109 */ 110 void loc_restore(Location *loc) 111 { 112 Location *prev = cur_loc->prev; 113 assert(!loc->prev); 114 *cur_loc = *loc; 115 cur_loc->prev = prev; 116 } 117 118 /* 119 * Change the current location to "nowhere in particular". 120 */ 121 void loc_set_none(void) 122 { 123 cur_loc->kind = LOC_NONE; 124 } 125 126 /* 127 * Change the current location to argument ARGV[IDX..IDX+CNT-1]. 128 */ 129 void loc_set_cmdline(char **argv, int idx, int cnt) 130 { 131 cur_loc->kind = LOC_CMDLINE; 132 cur_loc->num = cnt; 133 cur_loc->ptr = argv + idx; 134 } 135 136 /* 137 * Change the current location to file FNAME, line LNO. 138 */ 139 void loc_set_file(const char *fname, int lno) 140 { 141 assert (fname || cur_loc->kind == LOC_FILE); 142 cur_loc->kind = LOC_FILE; 143 cur_loc->num = lno; 144 if (fname) { 145 cur_loc->ptr = fname; 146 } 147 } 148 149 static const char *progname; 150 151 /* 152 * Set the program name for error_print_loc(). 153 */ 154 void error_set_progname(const char *argv0) 155 { 156 const char *p = strrchr(argv0, '/'); 157 progname = p ? p + 1 : argv0; 158 } 159 160 /* 161 * Print current location to current monitor if we have one, else to stderr. 162 */ 163 void error_print_loc(void) 164 { 165 const char *sep = ""; 166 int i; 167 const char *const *argp; 168 169 if (!cur_mon && progname) { 170 fprintf(stderr, "%s:", progname); 171 sep = " "; 172 } 173 switch (cur_loc->kind) { 174 case LOC_CMDLINE: 175 argp = cur_loc->ptr; 176 for (i = 0; i < cur_loc->num; i++) { 177 error_printf("%s%s", sep, argp[i]); 178 sep = " "; 179 } 180 error_printf(": "); 181 break; 182 case LOC_FILE: 183 error_printf("%s:", (const char *)cur_loc->ptr); 184 if (cur_loc->num) { 185 error_printf("%d:", cur_loc->num); 186 } 187 error_printf(" "); 188 break; 189 default: 190 error_printf("%s", sep); 191 } 192 } 193 194 /* 195 * Print an error message to current monitor if we have one, else to stderr. 196 * Prepend the current location and append a newline. 197 * It's wrong to call this in a QMP monitor. Use qerror_report() there. 198 */ 199 void error_report(const char *fmt, ...) 200 { 201 va_list ap; 202 203 error_print_loc(); 204 va_start(ap, fmt); 205 error_vprintf(fmt, ap); 206 va_end(ap); 207 error_printf("\n"); 208 } 209