/* msgno - managing error codes and associated messages across
* separate C libraries
* Copyright (c) 2001 Michael B. Allen <mba2000 ioplex.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include "mba/msgno.h"
#ifndef MSGNO_NUM_LISTS
#define MSGNO_NUM_LISTS 16
#endif
#ifndef MSGNO_BUFSIZ
#define MSGNO_BUFSIZ 1024
#endif
struct msgno_entry msgno_builtin_codes[2] = {
{ (1 << 16), "A parameter was NULL" },
{ 0, NULL }
};
static struct tbl_entry {
struct msgno_entry *list;
unsigned int num_msgs;
} list_tbl[MSGNO_NUM_LISTS] = {
{ msgno_builtin_codes, 1 }
};
static unsigned int next_tbl_idx = 1;
int msgno_buf_idx = 0;
char msgno_buf[MSGNO_BUFSIZ] = { 0 };
int
msgno_add_codes(struct msgno_entry *list)
{
struct tbl_entry *te;
int next_msgno = 0, hi_bits;
if (list == NULL || list->msg == NULL) {
errno = EINVAL;
return -1;
}
if (next_tbl_idx == MSGNO_NUM_LISTS) {
errno = ERANGE;
return -1;
}
for (te = list_tbl + 1; te->list; te++) {
if (te->list == list) {
return 0; /* already in list_tbl */
}
}
hi_bits = (next_tbl_idx + 1) << 16;
te->list = list;
while (list->msg) {
if ((list->msgno & 0xFFFF0000)) {
te->list = NULL;
errno = ERANGE;
return -1;
}
if (list->msgno == 0) {
list->msgno = hi_bits | next_msgno++;
} else if (list->msgno >= next_msgno) {
next_msgno = list->msgno + 1;
list->msgno = hi_bits | list->msgno;
} else {
te->list = NULL;
errno = ERANGE;
return -1;
}
te->num_msgs++;
list++;
}
next_tbl_idx++;
return 0;
}
const char *
msgno_msg(int msgno)
{
struct tbl_entry *te;
unsigned int i;
i = msgno >> 16;
if (i == 0) {
return strerror(msgno);
} else if (i >= MSGNO_NUM_LISTS || (te = list_tbl + (i - 1)) == NULL) {
return "No such msgno list";
}
for (i = 0; i < te->num_msgs; i++) {
if (te->list[i].msgno == msgno) {
return te->list[i].msg;
}
}
return "No such message in msgno list";
}
int
msgno_hdlr_stderr(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
fflush(stderr);
return 0;
}
int (*msgno_hdlr)(const char *fmt, ...) = msgno_hdlr_stderr;
int
msgno_append(const char *src, int n)
{
unsigned char *dst = (unsigned char *)msgno_buf + msgno_buf_idx;
unsigned char *dlim = (unsigned char *)msgno_buf + MSGNO_BUFSIZ;
unsigned char *start = dst;
if (src == NULL || n < 1 || dst >= dlim) {
return 0;
}
while (n-- && *src) {
*dst++ = *src++;
if (dst == dlim) {
dst--;
break;
}
}
*dst = '\0';
msgno_buf_idx += dst - start;
return dst - start;
}
int
msgno_vsprintf(const char *fmt, va_list ap)
{
size_t size = MSGNO_BUFSIZ - msgno_buf_idx;
int n;
#if (__STDC_VERSION__ >= 199901L)
if ((n = vsnprintf(msgno_buf + msgno_buf_idx, size, fmt, ap)) < 0 ||
#else
if ((n = vsprintf(msgno_buf + msgno_buf_idx, fmt, ap)) < 0 ||
#endif
(size_t)n >= size || msgno_buf_idx > MSGNO_BUFSIZ) {
*msgno_buf = '\0';
msgno_buf_idx = 0;
n = msgno_append("vsnprintf error", 15);
}
msgno_buf_idx += n;
return n;
}
int
msgno_loc0(const char *loc0, const char *loc1)
{
if (*loc0 == '!') {
loc0++;
*msgno_buf = '\0';
msgno_buf_idx = 0;
} else if (*msgno_buf) {
msgno_buf[msgno_buf_idx++] = ' ';
msgno_buf[msgno_buf_idx++] = ' ';
}
return msgno_append(loc0, 128) + msgno_append(loc1, 128) + msgno_append(": ", 2);
}
int
msgno_mmsg0(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
msgno_vsprintf(fmt, ap);
msgno_hdlr("%s", msgno_buf);
*msgno_buf = '\0';
msgno_buf_idx = 0;
va_end(ap);
return 0;
}
int
msgno_mmno0(int msgno)
{
msgno_append(msgno_msg(msgno), 255);
msgno_hdlr(msgno_buf);
*msgno_buf = '\0';
msgno_buf_idx = 0;
return 0;
}
int
msgno_mmnf0(int msgno, const char *fmt, ...)
{
va_list ap;
msgno_append(msgno_msg(msgno), 255);
va_start(ap, fmt);
msgno_vsprintf(fmt, ap);
msgno_hdlr("%s", msgno_buf);
*msgno_buf = '\0';
msgno_buf_idx = 0;
va_end(ap);
return 0;
}
int
msgno_amsg0(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
msgno_vsprintf(fmt, ap);
msgno_buf[msgno_buf_idx++] = '\n';
va_end(ap);
return 0;
}
int
msgno_amno0(int msgno)
{
msgno_append(msgno_msg(msgno), 255);
msgno_buf[msgno_buf_idx++] = '\n';
return 0;
}
int
msgno_amnf0(int msgno, const char *fmt, ...)
{
va_list ap;
msgno_append(msgno_msg(msgno), 255);
va_start(ap, fmt);
msgno_vsprintf(fmt, ap);
msgno_buf[msgno_buf_idx++] = '\n';
va_end(ap);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1