1 /* $NetBSD: error.c,v 1.3 2019/10/28 18:12:54 joerg Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include "baselocl.h" 39 40 struct heim_error { 41 int error_code; 42 heim_string_t msg; 43 struct heim_error *next; 44 }; 45 46 static void 47 error_dealloc(void *ptr) 48 { 49 struct heim_error *p = ptr; 50 heim_release(p->msg); 51 heim_release(p->next); 52 } 53 54 static int 55 error_cmp(void *a, void *b) 56 { 57 struct heim_error *ap = a, *bp = b; 58 if (ap->error_code == bp->error_code) 59 return 0; 60 return heim_cmp(ap->msg, bp->msg); 61 } 62 63 static unsigned long 64 error_hash(void *ptr) 65 { 66 struct heim_error *p = ptr; 67 return p->error_code; 68 } 69 70 struct heim_type_data _heim_error_object = { 71 HEIM_TID_ERROR, 72 "error-object", 73 NULL, 74 error_dealloc, 75 NULL, 76 error_cmp, 77 error_hash, 78 NULL 79 }; 80 81 heim_error_t 82 heim_error_create_enomem(void) 83 { 84 /* This is an immediate object; see heim_number_create() */ 85 return (heim_error_t)heim_number_create(ENOMEM); 86 } 87 88 89 void 90 heim_error_create_opt(heim_error_t *error, int error_code, const char *fmt, ...) 91 { 92 if (error) { 93 va_list ap; 94 va_start(ap, fmt); 95 *error = heim_error_createv(error_code, fmt, ap); 96 va_end(ap); 97 } 98 } 99 100 heim_error_t 101 heim_error_create(int error_code, const char *fmt, ...) 102 { 103 heim_error_t e; 104 va_list ap; 105 106 va_start(ap, fmt); 107 e = heim_error_createv(error_code, fmt, ap); 108 va_end(ap); 109 110 return e; 111 } 112 113 heim_error_t 114 heim_error_createv(int error_code, const char *fmt, va_list ap) 115 { 116 heim_error_t e; 117 char *str; 118 int len; 119 int save_errno = errno; 120 121 str = malloc(1024); 122 errno = save_errno; 123 if (str == NULL) 124 return heim_error_create_enomem(); 125 len = vsnprintf(str, 1024, fmt, ap); 126 errno = save_errno; 127 if (len < 0) { 128 free(str); 129 return NULL; /* XXX We should have a special heim_error_t for this */ 130 } 131 132 e = _heim_alloc_object(&_heim_error_object, sizeof(struct heim_error)); 133 if (e) { 134 e->msg = heim_string_create(str); 135 e->error_code = error_code; 136 } 137 free(str); 138 139 errno = save_errno; 140 return e; 141 } 142 143 heim_string_t 144 heim_error_copy_string(heim_error_t error) 145 { 146 if (heim_get_tid(error) != HEIM_TID_ERROR) { 147 if (heim_get_tid(error) == heim_number_get_type_id()) 148 return __heim_string_constant(strerror(heim_number_get_int((heim_number_t)error))); 149 heim_abort("invalid heim_error_t"); 150 } 151 /* XXX concat all strings */ 152 return heim_retain(error->msg); 153 } 154 155 int 156 heim_error_get_code(heim_error_t error) 157 { 158 if (error == NULL) 159 return -1; 160 if (heim_get_tid(error) != HEIM_TID_ERROR) { 161 if (heim_get_tid(error) == heim_number_get_type_id()) 162 return heim_number_get_int((heim_number_t)error); 163 heim_abort("invalid heim_error_t"); 164 } 165 return error->error_code; 166 } 167 168 heim_error_t 169 heim_error_append(heim_error_t top, heim_error_t append) 170 { 171 if (heim_get_tid(top) != HEIM_TID_ERROR) { 172 if (heim_get_tid(top) == heim_number_get_type_id()) 173 return top; 174 heim_abort("invalid heim_error_t"); 175 } 176 if (top->next) 177 heim_release(top->next); 178 top->next = heim_retain(append); 179 return top; 180 } 181