| 1 | .\" -*-nroff-*- |
| 2 | .de VS |
| 3 | .sp 1 |
| 4 | .in +5n |
| 5 | .ft B |
| 6 | .nf |
| 7 | .. |
| 8 | .de VE |
| 9 | .ft R |
| 10 | .in -5n |
| 11 | .sp 1 |
| 12 | .fi |
| 13 | .. |
| 14 | .TH exc 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library" |
| 15 | .SH NAME |
| 16 | exc \- exception handling for C programs |
| 17 | .\" @TRY |
| 18 | .\" @CATCH |
| 19 | .\" @END_TRY |
| 20 | .\" @THROW |
| 21 | .\" @RETHROW |
| 22 | .\" |
| 23 | .\" @exc_uncaught |
| 24 | .\" |
| 25 | .\" @EXC_PAIR |
| 26 | .\" @EXC_ALLOC |
| 27 | .\" @EXC_ALLOCN |
| 28 | .\" @EXC_ALLOCI |
| 29 | .\" @EXC_ALLOCP |
| 30 | .\" @EXC_ALLOCS |
| 31 | .\" |
| 32 | .SH SYNOPSIS |
| 33 | .B "#include <mLib/exc.h>" |
| 34 | .sp 1 |
| 35 | .B TRY |
| 36 | .I statement |
| 37 | .B CATCH |
| 38 | .I statement |
| 39 | .B END_TRY; |
| 40 | .br |
| 41 | .B EXIT_TRY; |
| 42 | .sp 1 |
| 43 | .BI "THROW(exc_extype " type |
| 44 | .RB [ , |
| 45 | .IR data ]\fB); |
| 46 | .br |
| 47 | .B RETHROW; |
| 48 | .sp 1 |
| 49 | .nf |
| 50 | .B "typedef void (*exc__uncaught)(exc_extype, exc_exval);" |
| 51 | .BI "exc__uncaught exc_uncaught(exc__uncaught " proc ); |
| 52 | |
| 53 | .BI "exc_extype EXC_PAIR(unsigned char " x ", unsigned char " y ); |
| 54 | .BI "exc_extype EXC_ALLOC(exc_extype " owner ", exc_extype " type ); |
| 55 | .BI "exc_extype EXC_ALLOCN(exc_extype " owner ", exc_extype " type ); |
| 56 | .BI "exc_extype EXC_ALLOCI(exc_extype " owner ", exc_extype " type ); |
| 57 | .BI "exc_extype EXC_ALLOCP(exc_extype " owner ", exc_extype " type ); |
| 58 | .BI "exc_extype EXC_ALLOCS(exc_extype " owner ", exc_extype " type ); |
| 59 | .fi |
| 60 | .SH DESCRIPTION |
| 61 | The header file |
| 62 | .B <mLib/exc.h> |
| 63 | introduces some new syntax and definitions to support exception handling |
| 64 | in C. The marriage is not particularly successful, although it works |
| 65 | well enough in practice. |
| 66 | .PP |
| 67 | The syntax introduced consists of new |
| 68 | .B TRY |
| 69 | and |
| 70 | .B EXIT_TRY |
| 71 | statements and a pair of new expression types |
| 72 | .B THROW |
| 73 | and |
| 74 | .BR RETHROW . |
| 75 | It's unfortunately important to remember that the syntax is provided |
| 76 | using macro expansion and standard C facilities; some of the |
| 77 | restrictions of these features show through. |
| 78 | .SS "The TRY statement" |
| 79 | The |
| 80 | .B TRY |
| 81 | statement associates an exception handler with a piece of code. The |
| 82 | second statement is an |
| 83 | .IR "exception handler" . |
| 84 | Its |
| 85 | .I "dynamic scope" |
| 86 | is the duration of the first statement's execution, together with the |
| 87 | duration of any functions called within the dynamic scope. (Note in |
| 88 | particular that an exception handler is not within its own dynamic |
| 89 | scope.) A thrown exception causes the exception handler with |
| 90 | dynamically innermost scope to be executed. |
| 91 | .PP |
| 92 | Two special variables are provided to the exception handler: |
| 93 | .TP |
| 94 | .B exc_type |
| 95 | The |
| 96 | .I type |
| 97 | of the exception caught. This is value of type |
| 98 | .B exc_extype |
| 99 | (described below). |
| 100 | .TP |
| 101 | .B exc_val |
| 102 | The |
| 103 | .I value |
| 104 | of the exception. This has a union type, with members |
| 105 | .BR "int i", |
| 106 | .B "void *p" |
| 107 | and |
| 108 | .BR "char *s" . |
| 109 | Only one of the members is valid; you should be able to work out which |
| 110 | from the exception type. There are abbreviations |
| 111 | .BR "exc_i", |
| 112 | .B exc_p |
| 113 | and |
| 114 | .B exc_s |
| 115 | which refer to members of |
| 116 | .B exc_val |
| 117 | directly. |
| 118 | .SS "The EXIT_TRY statement" |
| 119 | It is not safe to leave the dynamic scope of an exception handler early |
| 120 | (e.g., by a |
| 121 | .B goto |
| 122 | statement). You can force a safe exit from a dynamic scope using the |
| 123 | .B EXIT_TRY |
| 124 | statement from within the |
| 125 | .I lexical |
| 126 | scope of the |
| 127 | .B TRY |
| 128 | statement. |
| 129 | .SS "The THROW and RETHROW statements" |
| 130 | The |
| 131 | .B THROW |
| 132 | expression throws an exception. The first argument is the type of |
| 133 | exception; the second is some data to attach to the exception. The type |
| 134 | of data, integer, string or pointer, is determined from the exception |
| 135 | type. |
| 136 | .PP |
| 137 | Control is immediately passed to the exception handler with the |
| 138 | innermost enclosing dynamic scope. |
| 139 | .PP |
| 140 | The |
| 141 | .B RETHROW |
| 142 | expression is only valid within an exception handler. It rethrows the |
| 143 | last exception caught by the handler. |
| 144 | .PP |
| 145 | Neither |
| 146 | .B THROW |
| 147 | nor |
| 148 | .B RETHROW |
| 149 | yields any value. |
| 150 | .SS "Exception type allocation" |
| 151 | Exception types are 32-bit values. The top 16 bits are an |
| 152 | .IR "owner identifier" . |
| 153 | The idea is that each library can have an owner identifier, and it can |
| 154 | then allocate exceptions for its own use from the remaining space. Two |
| 155 | special owner codes are defined: |
| 156 | .TP |
| 157 | .B "EXC_GLOBAL (0x0000)" |
| 158 | The global space defined for everyone's benefit. Don't define your own |
| 159 | exceptions in this space. |
| 160 | .TP |
| 161 | .B "EXC_SHARED (0xffff)" |
| 162 | A shared space. You can use this for any exceptions which won't be seen |
| 163 | by anyone else. |
| 164 | .PP |
| 165 | Other owner codes may be allocated by choosing two characters (probably |
| 166 | letters) which best suit your application and applying the |
| 167 | .B EXC_PAIR |
| 168 | macro to them. For example, the owner code for |
| 169 | .B mLib |
| 170 | would probably be |
| 171 | .BR "EXC_PAIR('m', 'L')" , |
| 172 | if |
| 173 | .B mLib |
| 174 | defined any exceptions other then the global ones. |
| 175 | .PP |
| 176 | The bottom 16 bits are the actual exception type, and the data type |
| 177 | which gets passed around with the exception. The data type is |
| 178 | (bizarrely) in bits 6 and 7 of the type word. The data type code is one |
| 179 | of the following: |
| 180 | .TP |
| 181 | .B EXC_NOVAL |
| 182 | There is no data associated with this exception. |
| 183 | .TP |
| 184 | .B EXC_INTVAL |
| 185 | The data is an integer, with type |
| 186 | .BR int . |
| 187 | .TP |
| 188 | .B EXC_PTRVAL |
| 189 | The data is a pointer to some data structure, with type |
| 190 | .BR "void *" . |
| 191 | Note that you probably have to do an explicit cast to |
| 192 | .B "void *" |
| 193 | in the |
| 194 | .B THROW |
| 195 | expression. |
| 196 | .TP |
| 197 | .B EXC_STRVAL |
| 198 | The data is a pointer to a string of characters, of type |
| 199 | .BR "char *" . |
| 200 | .PP |
| 201 | If the data to be thrown is a pointer, make sure that the object pointed |
| 202 | to has a long enough lifetime for it to actually get to its exception |
| 203 | handler intact. In particular, don't pass pointers to automatic |
| 204 | variables unless you're |
| 205 | .I sure |
| 206 | they were allocated outside the handler's dynamic scope. |
| 207 | .PP |
| 208 | Individual exceptions are allocated by the macros |
| 209 | .BI EXC_ALLOC t\fR, |
| 210 | where |
| 211 | .I t |
| 212 | is one of: |
| 213 | .TP |
| 214 | .B N |
| 215 | The exception has no data |
| 216 | .TP |
| 217 | .B I |
| 218 | The exception data is an integer. |
| 219 | .TP |
| 220 | .B P |
| 221 | The exception data is a pointer. |
| 222 | .TP |
| 223 | .B S |
| 224 | The exception data is a character string. |
| 225 | .PP |
| 226 | The |
| 227 | .BI EXC_ALLOC t |
| 228 | macros take two arguments: the owner code (usually allocated with |
| 229 | .B EXC_PAIR |
| 230 | as described above), and the type code. The data type is encoded into |
| 231 | the exception type by the allocation macro. |
| 232 | .SS "Predefined exceptions" |
| 233 | The following exceptions are predefined: |
| 234 | .TP |
| 235 | .B EXC_NOMEM |
| 236 | No data. Signals an out-of-memory condition. |
| 237 | .TP |
| 238 | .B EXC_ERRNO |
| 239 | Integer data. Signals an operating system error. The data is the value |
| 240 | of |
| 241 | .B errno |
| 242 | associated with the error. |
| 243 | .TP |
| 244 | .B EXC_OSERROR |
| 245 | Pointer data. Signals a RISC\ OS error. The data is a pointer to the |
| 246 | RISC\ OS error block. (Non RISC\ OS programmers don't need to worry |
| 247 | about this.) |
| 248 | .TP |
| 249 | .B EXC_SIGNAL |
| 250 | Integer data. Signals a raised operating system signal. The data is |
| 251 | the signal number. |
| 252 | .TP |
| 253 | .B EXC_FAIL |
| 254 | String data. Signals a miscellaneous failure. The data is a pointer to |
| 255 | an explanatory string. |
| 256 | .SH BUGS |
| 257 | The call to an exception handler is achieved using |
| 258 | .BR longjmp (3). |
| 259 | Therefore all the caveats about |
| 260 | .B longjmp |
| 261 | and automatic data apply. Also, note that status such as the signal |
| 262 | mask is not reset, so you might have to do that manually in order to |
| 263 | recover from a signal. |
| 264 | .SH "SEE ALSO" |
| 265 | .BR mLib (3). |
| 266 | .SH AUTHOR |
| 267 | Mark Wooding, <mdw@distorted.org.uk> |