1 /*
2  * $Id$
3  *
4  * Copyright (C) 2009 Rutger Hofman, VU Amsterdam
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19  * 02111-1307, USA.
20  *
21  * Written by Rutger Hofman
22  */
23 
24 #include <sysdep.h>
25 
26 #include <stdarg.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdbool.h>
30 
31 #include <urjtag/log.h>
32 #include <urjtag/error.h>
33 #include <urjtag/jtag.h>
34 
35 urj_error_state_t urj_error_state;
36 
37 static int stderr_vprintf (const char *fmt, va_list ap);
38 static int stdout_vprintf (const char *fmt, va_list ap);
39 
40 urj_log_state_t urj_log_state =
41     {
42         .level = URJ_LOG_LEVEL_NORMAL,
43         .out_vprintf = stdout_vprintf,
44         .err_vprintf = stderr_vprintf,
45     };
46 
47 static int
stderr_vprintf(const char * fmt,va_list ap)48 stderr_vprintf(const char *fmt, va_list ap)
49 {
50     return vfprintf (stderr, fmt, ap);
51 }
52 
53 static int
stdout_vprintf(const char * fmt,va_list ap)54 stdout_vprintf(const char *fmt, va_list ap)
55 {
56     int r = vfprintf (stdout, fmt, ap);
57 
58     fflush (stdout);
59 
60     return r;
61 }
62 
63 static int
log_printf(int (* p)(const char *,va_list),const char * fmt,...)64 log_printf (int (*p) (const char *, va_list), const char *fmt, ...)
65 {
66     va_list ap;
67     int r;
68 
69     va_start (ap, fmt);
70     r = (*p) (fmt, ap);
71     va_end (ap);
72 
73     return r;
74 }
75 
76 int
urj_do_log(urj_log_level_t level,const char * file,size_t line,const char * func,const char * fmt,...)77 urj_do_log (urj_log_level_t level, const char *file, size_t line,
78             const char *func, const char *fmt, ...)
79 {
80     int (*p) (const char *fmt, va_list ap);
81     va_list ap;
82     int r = 0;
83 
84     if (level < urj_log_state.level)
85         return 0;
86 
87     if (level < URJ_LOG_LEVEL_WARNING)
88         p = urj_log_state.out_vprintf;
89     else
90         p = urj_log_state.err_vprintf;
91 
92     if (level == URJ_LOG_LEVEL_WARNING || level == URJ_LOG_LEVEL_ERROR
93         || level <= URJ_LOG_LEVEL_DETAIL)
94         r += log_printf (p, "%s: ", urj_log_level_string (level));
95 
96     if (urj_log_state.level <= URJ_LOG_LEVEL_DEBUG)
97         r += log_printf (p, "%s:%i %s(): ", file, line, func);
98 
99     va_start (ap, fmt);
100     r += (*p) (fmt, ap);
101     va_end (ap);
102 
103     return r;
104 }
105 
106 urj_error_t
urj_error_get(void)107 urj_error_get (void)
108 {
109     return urj_error_state.errnum;
110 }
111 
112 void
urj_error_reset(void)113 urj_error_reset (void)
114 {
115     urj_error_state.errnum = URJ_ERROR_OK;
116 }
117 
118 static const struct {
119     const urj_log_level_t level;
120     const char *name;
121 } levels[] = {
122 #define L(LVL, lvl) { URJ_LOG_LEVEL_##LVL, #lvl, }
123     L(ALL, all),
124     L(COMM, comm),
125     L(DEBUG, debug),
126     L(DETAIL, detail),
127     L(NORMAL, normal),
128     L(WARNING, warning),
129     L(ERROR, error),
130     L(SILENT, silent),
131 #undef L
132 };
133 
134 const char *
urj_log_level_string(urj_log_level_t level)135 urj_log_level_string (urj_log_level_t level)
136 {
137     size_t i;
138 
139     for (i = 0; i < ARRAY_SIZE (levels); ++i)
140         if (levels[i].level == level)
141             return levels[i].name;
142 
143     return "unknown";
144 }
145 
146 urj_log_level_t
urj_string_log_level(const char * slevel)147 urj_string_log_level (const char *slevel)
148 {
149     size_t i;
150 
151     for (i = 0; i < ARRAY_SIZE (levels); ++i)
152         if (!strcmp (levels[i].name, slevel))
153             return levels[i].level;
154 
155     return -1;
156 }
157 
158 const char *
urj_error_string(urj_error_t err)159 urj_error_string (urj_error_t err)
160 {
161     switch (err)
162     {
163     case URJ_ERROR_OK:                  return "no error";
164     case URJ_ERROR_ALREADY:             return "already defined";
165     case URJ_ERROR_OUT_OF_MEMORY:       return "out of memory";
166     case URJ_ERROR_NO_CHAIN:            return "no chain";
167     case URJ_ERROR_NO_PART:             return "no part";
168     case URJ_ERROR_NO_ACTIVE_INSTRUCTION: return "no active instruction";
169     case URJ_ERROR_NO_DATA_REGISTER:    return "no data register";
170     case URJ_ERROR_INVALID:             return "invalid parameter";
171     case URJ_ERROR_NOTFOUND:            return "not found";
172     case URJ_ERROR_NO_BUS_DRIVER:       return "no bus driver";
173     case URJ_ERROR_BUFFER_EXHAUSTED:    return "buffer exhausted";
174     case URJ_ERROR_ILLEGAL_STATE:       return "illegal state";
175     case URJ_ERROR_ILLEGAL_TRANSITION:  return "illegal state transition";
176     case URJ_ERROR_OUT_OF_BOUNDS:       return "out of bounds";
177     case URJ_ERROR_TIMEOUT:             return "timeout";
178     case URJ_ERROR_UNSUPPORTED:         return "unsupported";
179     case URJ_ERROR_SYNTAX:              return "syntax";
180     case URJ_ERROR_FILEIO:              return "file I/O";
181 
182     case URJ_ERROR_IO:                  return "I/O error from OS";
183     case URJ_ERROR_FTD:                 return "ftdi/ftd2xx error";
184     case URJ_ERROR_USB:                 return "libusb error";
185 
186     case URJ_ERROR_BUS:                 return "bus";
187     case URJ_ERROR_BUS_DMA:             return "bus DMA";
188 
189     case URJ_ERROR_FLASH:               return "flash";
190     case URJ_ERROR_FLASH_DETECT:        return "flash detect";
191     case URJ_ERROR_FLASH_PROGRAM:       return "flash program";
192     case URJ_ERROR_FLASH_ERASE:         return "flash erase";
193     case URJ_ERROR_FLASH_LOCK:          return "flash lock";
194     case URJ_ERROR_FLASH_UNLOCK:        return "flash unlock";
195 
196     case URJ_ERROR_BSDL_VHDL:           return "vhdl subsystem";
197     case URJ_ERROR_BSDL_BSDL:           return "bsdl subsystem";
198 
199     case URJ_ERROR_BFIN:                return "blackfin";
200 
201     case URJ_ERROR_PLD:                 return "pld subsystem";
202 
203     case URJ_ERROR_UNIMPLEMENTED:       return "unimplemented";
204 
205     case URJ_ERROR_FIRMWARE:            return "firmware";
206     }
207 
208     return "UNDEFINED ERROR";
209 }
210 
211 const char *
urj_error_describe(void)212 urj_error_describe (void)
213 {
214     static char msg[URJ_ERROR_MSG_LEN + 1024 + 256 + 20];
215 
216     if (urj_error_state.errnum == URJ_ERROR_IO)
217     {
218         snprintf (msg, sizeof msg, "%s: %s %s",
219                   "system error", strerror(urj_error_state.sys_errno),
220                   urj_error_state.msg);
221     }
222     else
223     {
224         snprintf (msg, sizeof msg, "%s: %s",
225                   urj_error_string (urj_error_state.errnum),
226                   urj_error_state.msg);
227     }
228 
229     return msg;
230 }
231 
232 void
urj_log_error_describe(urj_log_level_t level)233 urj_log_error_describe (urj_log_level_t level)
234 {
235     if (urj_error_get () == URJ_ERROR_OK)
236         return;
237 
238     urj_do_log (level,
239                 urj_error_state.file, urj_error_state.line,
240                 urj_error_state.function,
241                 "%s\n", urj_error_describe ());
242 
243     urj_error_reset ();
244 }
245