blob: 9536288efc4ff61907397ed4b6a1be241ec976c8 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/errno.h>
20#include <pj/string.h>
Benny Prijonodcc29522006-02-02 19:15:03 +000021#include <pj/assert.h>
Benny Prijono9033e312005-11-21 02:08:39 +000022#include <pj/compat/sprintf.h>
23
24/* Prototype for platform specific error message, which will be defined
25 * in separate file.
26 */
27extern int platform_strerror( pj_os_err_type code,
28 char *buf, pj_size_t bufsize );
29
Benny Prijonodcc29522006-02-02 19:15:03 +000030#define PJLIB_MAX_ERR_MSG_HANDLER 8
31
32/* Error message handler. */
33static unsigned err_msg_hnd_cnt;
34static struct err_msg_hnd
35{
36 pj_status_t begin;
37 pj_status_t end;
38 pj_str_t (*strerror)(pj_status_t, char*, pj_size_t);
39
40} err_msg_hnd[PJLIB_MAX_ERR_MSG_HANDLER];
41
Benny Prijono9033e312005-11-21 02:08:39 +000042/* PJLIB's own error codes/messages */
43static const struct
44{
45 int code;
46 const char *msg;
47} err_str[] =
48{
49 { PJ_EUNKNOWN, "Unknown Error" },
50 { PJ_EPENDING, "Pending operation" },
51 { PJ_ETOOMANYCONN, "Too many connecting sockets" },
52 { PJ_EINVAL, "Invalid value or argument" },
53 { PJ_ENAMETOOLONG, "Name too long" },
54 { PJ_ENOTFOUND, "Not found" },
55 { PJ_ENOMEM, "Not enough memory" },
56 { PJ_EBUG, "BUG DETECTED!" },
57 { PJ_ETIMEDOUT, "Operation timed out" },
58 { PJ_ETOOMANY, "Too many objects of the specified type"},
59 { PJ_EBUSY, "Object is busy"},
60 { PJ_ENOTSUP, "Option/operation is not supported"},
61 { PJ_EINVALIDOP, "Invalid operation"},
62 { PJ_ECANCELLED, "Operation cancelled"},
Benny Prijono6aa5c2a2006-03-05 13:37:41 +000063 { PJ_EEXISTS, "Object already exists" },
64 { PJ_EEOF, "End of file" },
Benny Prijono9033e312005-11-21 02:08:39 +000065};
66
67/*
68 * pjlib_error()
69 *
70 * Retrieve message string for PJLIB's own error code.
71 */
72static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
73{
74 unsigned i;
75
76 for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
77 if (err_str[i].code == code) {
78 pj_size_t len = strlen(err_str[i].msg);
79 if (len >= size) len = size-1;
80 pj_memcpy(buf, err_str[i].msg, len);
81 buf[len] = '\0';
82 return len;
83 }
84 }
85
86 *buf++ = '?';
87 *buf++ = '?';
88 *buf++ = '?';
89 *buf++ = '\0';
90 return 3;
91}
92
Benny Prijonodcc29522006-02-02 19:15:03 +000093#define IN_RANGE(val,start,end) ((val)>=(start) && (val)<(end))
94
95/* Register strerror handle. */
96PJ_DECL(pj_status_t) pj_register_strerror(pj_status_t start,
97 pj_status_t space,
98 pj_str_t (*f)(pj_status_t,char*,
99 pj_size_t))
100{
101 unsigned i;
102
103 /* Check arguments. */
104 PJ_ASSERT_RETURN(start && space && f, PJ_EINVAL);
105
106 /* Check if there aren't too many handlers registered. */
107 PJ_ASSERT_RETURN(err_msg_hnd_cnt < PJ_ARRAY_SIZE(err_msg_hnd),
108 PJ_ETOOMANY);
109
110 /* Start error must be greater than PJ_ERRNO_START_USER */
111 PJ_ASSERT_RETURN(start >= PJ_ERRNO_START_USER, PJ_EEXISTS);
112
113 /* Check that no existing handler has covered the specified range. */
114 for (i=0; i<err_msg_hnd_cnt; ++i) {
115 if (IN_RANGE(start, err_msg_hnd[i].begin, err_msg_hnd[i].end) ||
116 IN_RANGE(start+space-1, err_msg_hnd[i].begin, err_msg_hnd[i].end))
117 {
118 return PJ_EEXISTS;
119 }
120 }
121
122 /* Register the handler. */
123 err_msg_hnd[err_msg_hnd_cnt].begin = start;
124 err_msg_hnd[err_msg_hnd_cnt].end = start + space;
125 err_msg_hnd[err_msg_hnd_cnt].strerror = f;
126
127 ++err_msg_hnd_cnt;
128
129 return PJ_SUCCESS;
130}
131
Benny Prijono9033e312005-11-21 02:08:39 +0000132/*
133 * pj_strerror()
134 */
135PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode,
136 char *buf, pj_size_t bufsize )
137{
138 int len = -1;
139 pj_str_t errstr;
140
Benny Prijonodcc29522006-02-02 19:15:03 +0000141 pj_assert(buf && bufsize);
142
Benny Prijono9033e312005-11-21 02:08:39 +0000143 if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
144 len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);
145
146 } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
147 len = pjlib_error(statcode, buf, bufsize);
148
149 } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
150 len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
151
Benny Prijono9033e312005-11-21 02:08:39 +0000152 } else {
Benny Prijonodcc29522006-02-02 19:15:03 +0000153 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000154
Benny Prijonodcc29522006-02-02 19:15:03 +0000155 /* Find user handler to get the error message. */
156 for (i=0; i<err_msg_hnd_cnt; ++i) {
157 if (IN_RANGE(statcode, err_msg_hnd[i].begin, err_msg_hnd[i].end)) {
158 return (*err_msg_hnd[i].strerror)(statcode, buf, bufsize);
159 }
160 }
Benny Prijono9033e312005-11-21 02:08:39 +0000161 }
162
163 if (len < 1) {
164 *buf = '\0';
165 len = 0;
166 }
167
168 errstr.ptr = buf;
169 errstr.slen = len;
170
171 return errstr;
172}
173