Add header.
[amitay/samba.git] / source4 / lib / appweb / ejs-2.0 / mpr / mprLog.c
1 /**
2  *      @file           mprLog.c
3  *      @brief          Mbedthis Portable Runtime (MPR) Logging and error reporting.
4  *      @remarks        We always provide these routines.
5  */
6
7 /*********************************** License **********************************/
8 /*
9  *      @copy   default
10  *      
11  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
12  *      
13  *      This software is distributed under commercial and open source licenses.
14  *      You may use the GPL open source license described below or you may acquire 
15  *      a commercial license from Mbedthis Software. You agree to be fully bound 
16  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
17  *      this software for full details.
18  *      
19  *      This software is open source; you can redistribute it and/or modify it 
20  *      under the terms of the GNU General Public License as published by the 
21  *      Free Software Foundation; either version 2 of the License, or (at your 
22  *      option) any later version. See the GNU General Public License for more 
23  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
24  *      
25  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
26  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
27  *      
28  *      This GPL license does NOT permit incorporating this software into 
29  *      proprietary programs. If you are unable to comply with the GPL, you must
30  *      acquire a commercial license to use this software. Commercial licenses 
31  *      for this software and support services are available from Mbedthis 
32  *      Software at http://www.mbedthis.com 
33  *      
34  *      @end
35  */
36
37 #include        "mpr.h"
38
39 /****************************** Forward Declarations **************************/
40
41 static void     defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags, 
42                                 int level, const char *msg);
43 static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level, 
44                                 const char *msg);
45
46 /************************************ Code ************************************/
47
48 void mprLog(MprCtx ctx, int level, const char *fmt, ...)
49 {
50         va_list         args;
51         char            *buf;
52
53         if (level > mprGetLogLevel(ctx)) {
54                 return;
55         }
56
57         va_start(args, fmt);
58         mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
59         va_end(args);
60
61         logOutput(MPR_LOC_ARGS(ctx), MPR_LOG_SRC, level, buf);
62
63         va_end(args);
64         mprFree(buf);
65 }
66
67 /*****************************************************************************/
68 /*
69  *      Do raw output
70  */
71
72 void mprRawLog(MprCtx ctx, const char *fmt, ...)
73 {
74         va_list         args;
75         char            *buf;
76         int                     len;
77
78         va_start(args, fmt);
79         len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
80         va_end(args);
81         
82         logOutput(MPR_LOC_ARGS(ctx), MPR_RAW, 0, buf);
83         mprFree(buf);
84 }
85
86 /*****************************************************************************/
87 /*
88  *      Handle an error
89  */
90
91 void mprError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
92 {
93         va_list         args;
94         char            *buf;
95         int                     len;
96
97         va_start(args, fmt);
98         len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
99         va_end(args);
100         
101         logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf);
102
103         mprFree(buf);
104 }
105
106 /*****************************************************************************/
107 /*
108  *      Handle an error that should be displayed to the user
109  */
110
111 void mprUserError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
112 {
113         va_list         args;
114         char            *buf;
115         int                     len;
116
117         va_start(args, fmt);
118         len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
119         va_end(args);
120         
121         logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_ERROR_SRC, 0, buf);
122
123         mprFree(buf);
124 }
125
126 /*****************************************************************************/
127 /*
128  *      Handle a fatal error. Forcibly shutdown the application.
129  */
130
131 void mprFatalError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
132 {
133         va_list         args;
134         char            *buf;
135         int                     len;
136
137         va_start(args, fmt);
138         len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
139         va_end(args);
140         
141         logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_FATAL_SRC, 0, buf);
142
143         mprFree(buf);
144
145 #if BREW
146         mprSignalExit(ctx);
147 #else
148         exit(2);
149 #endif
150 }
151
152 /*****************************************************************************/
153 /*
154  *      Handle a program assertion
155  */
156
157 void mprAssertError(MPR_LOC_DEC(ctx, loc), const char *msg)
158 {
159         logOutput(MPR_LOC_PASS(ctx, loc), MPR_ASSERT_MSG | MPR_ASSERT_SRC, 0, msg);
160 }
161
162 /*****************************************************************************/
163 /*
164  *      Handle an error
165  */
166
167 void mprStaticError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
168 {
169         va_list         args;
170         int                     len;
171         char            buf[MPR_MAX_STRING];
172
173         va_start(args, fmt);
174         len = mprVsprintf(buf, sizeof(buf), fmt, args);
175         va_end(args);
176
177         logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf);
178 }
179
180 /*****************************************************************************/
181 /*
182  *      Direct output to the standard output. Does not hook into the logging 
183  *      system and does not allocate memory.
184  */
185
186 void mprStaticAssert(const char *loc, const char *msg)
187 {
188 #if BLD_DEBUG
189         char    buf[MPR_MAX_STRING];
190         int             len;
191
192         len = mprSprintf(buf, sizeof(buf), "Assertion %s, failed at %s\n", 
193                 msg, loc);
194         mprBreakpoint(loc, buf);
195         
196 #if BLD_HOST_UNIX
197         /*
198          *      MOB -- but is stdout always okay to use
199          */
200         write(1, buf, len);
201 #elif BREW || WIN
202         /*
203          *      Only time we use printf. We can't get an alloc context so we have
204          *      to use real print
205          */
206 #if BREW && !BREW_SIMULATOR
207         printf(" MP: %s\n", buf);
208 #else
209         printf("%s\n", buf);
210 #endif
211
212 #endif
213 #endif
214 }
215
216 /*****************************************************************************/
217
218 int mprGetLogLevel(MprCtx ctx)
219 {
220         return mprGetApp(ctx)->logLevel;
221 }
222
223 /******************************************************************************/
224
225 void mprSetLogLevel(MprCtx ctx, int level)
226 {
227         mprGetApp(ctx)->logLevel = level;
228 }
229
230 /*****************************************************************************/
231 /*
232  *      Output a log message to the log handler
233  */
234
235 static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level, 
236         const char *msg)
237 {
238         MprLogHandler   handler;
239
240         if (flags & (MPR_ERROR_SRC | MPR_FATAL_SRC | MPR_ASSERT_SRC)) {
241                 mprBreakpoint(MPR_LOC, 0);
242         }
243
244         mprAssert(ctx != 0);
245         handler = mprGetApp(ctx)->logHandler;
246         if (handler != 0) {
247                 (handler)(MPR_LOC_PASS(ctx, loc), flags, level, msg);
248                 return;
249         }
250         defaultLogHandler(MPR_LOC_PASS(ctx, loc), flags, level, msg);
251 }
252
253 /*****************************************************************************/
254 /*
255  *      Default log output is just to the console
256  */
257
258 static void defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags, 
259         int level, const char *msg)
260 {
261         MprApp  *app;
262         char    *prefix;
263
264         app = mprGetApp(ctx);
265         prefix = app->name;
266
267         while (*msg == '\n') {
268                 mprPrintf(ctx, "\n");
269                 msg++;
270         }
271
272         if (flags & MPR_LOG_SRC) {
273 #if BREW && !BREW_SIMULATOR
274                 mprPrintf(ctx, "%s\n", msg);
275 #else
276                 mprPrintf(ctx, "%s: %d: %s\n", prefix, level, msg);
277 #endif
278
279         } else if (flags & MPR_ERROR_SRC) {
280                 /*
281                  *      Use static printing to avoid malloc when the messages are small.
282                  *      This is important for memory allocation errors.
283                  */
284                 if (strlen(msg) < (MPR_MAX_STRING - 32)) {
285                         mprStaticPrintf(ctx, "%s: Error: %s\n", prefix, msg);
286                 } else {
287                         mprPrintf(ctx, "%s: Error: %s\n", prefix, msg);
288                 }
289
290         } else if (flags & MPR_FATAL_SRC) {
291                 mprPrintf(ctx, "%s: Fatal: %s\n", prefix, msg);
292                 
293         } else if (flags & MPR_ASSERT_SRC) {
294 #if BLD_FEATURE_ALLOC_LEAK_TRACK
295                 mprPrintf(ctx, "%s: Assertion %s, failed at %s\n", prefix, msg, loc);
296 #else
297                 mprPrintf(ctx, "%s: Assertion %s, failed\n", prefix, msg);
298 #endif
299
300         } else if (flags & MPR_RAW) {
301                 mprPrintf(ctx, "%s", msg);
302
303         } else {
304                 return;
305         }
306 }
307
308 /*****************************************************************************/
309 /*
310  *      Map the O/S error code to portable error codes.
311  */
312
313 int mprGetOsError()
314 {
315 #if WIN
316         int             rc;
317         rc = GetLastError();
318
319         /*
320          *      Client has closed the pipe
321          */
322         if (rc == ERROR_NO_DATA) {
323                 return EPIPE;
324         }
325         return rc;
326 #endif
327 #if LINUX || VXWORKS || SOLARIS
328         return errno;
329 #endif
330 #if BREW
331         /*
332          *      No such thing on Brew. Errors are per class
333          */
334         return 0;
335 #endif
336 }
337
338 /******************************************************************************/
339 #if UNUSED
340
341 const char *mprGetErrorMsg(int err)
342 {
343         /*
344          *      MPR error messages. Declare here so we don't have any globals.
345          */
346         char *mprErrMessages[] = {
347                 /*    0 MPR_ERR_OK                              */  "Success", 
348                 /* -201 MPR_ERR_GENERAL                 */  "General error", 
349                 /* -202 MPR_ERR_ABORTED                 */  "Aborted", 
350                 /* -203 MPR_ERR_ALREADY_EXISTS  */  "Already exists", 
351                 /* -204 MPR_ERR_BAD_ARGS                */  "Bad args", 
352                 /* -205 MPR_ERR_BAD_FORMAT              */  "Bad format", 
353                 /* -206 MPR_ERR_BAD_HANDLE              */  "Bad handle", 
354                 /* -207 MPR_ERR_BAD_STATE               */  "Bad state", 
355                 /* -208 MPR_ERR_BAD_SYNTAX              */  "Bad syntax", 
356                 /* -209 MPR_ERR_BAD_TYPE                */  "Bad type", 
357                 /* -210 MPR_ERR_BAD_VALUE               */  "Bad value", 
358                 /* -211 MPR_ERR_BUSY                    */  "Busy", 
359                 /* -212 MPR_ERR_CANT_ACCESS             */  "Can't access", 
360                 /* -213 MPR_ERR_CANT_COMPLETE   */  "Can't complete", 
361                 /* -214 MPR_ERR_CANT_CREATE             */  "Can't create", 
362                 /* -215 MPR_ERR_CANT_INITIALIZE */  "Can't initialize", 
363                 /* -216 MPR_ERR_CANT_OPEN               */  "Can't open", 
364                 /* -217 MPR_ERR_CANT_READ               */  "Can't read", 
365                 /* -218 MPR_ERR_CANT_WRITE              */  "Can't write", 
366                 /* -219 MPR_ERR_DELETED                 */  "Already deleted", 
367                 /* -220 MPR_ERR_NETWORK                 */  "Network error", 
368                 /* -221 MPR_ERR_NOT_FOUND               */  "Not found", 
369                 /* -222 MPR_ERR_NOT_INITIALIZED */  "Not initialized", 
370                 /* -223 MPR_ERR_NOT_READY               */  "Not ready", 
371                 /* -224 MPR_ERR_READ_ONLY               */  "Read only", 
372                 /* -225 MPR_ERR_TIMEOUT                 */  "Timeout", 
373                 /* -226 MPR_ERR_TOO_MANY                */  "Too many", 
374                 /* -227 MPR_ERR_WONT_FIT                */  "Won't fit", 
375                 /* -228 MPR_ERR_WOULD_BLOCK             */  "Would block", 
376                 /* -229 MPR_ERR_CANT_ALLOCATE   */  "Can't allocate", 
377         };
378         int mprNumErr = sizeof(mprErrMessages) / sizeof(char*);
379
380 /*
381  *      Operating system error messages
382  */
383 #if WIN
384 char *osErrMessages[] =
385 {
386     /*  0              */  "No error",
387     /*  1 EPERM        */  "Operation not permitted",
388     /*  2 ENOENT       */  "No such file or directory",
389     /*  3 ESRCH        */  "No such process",
390     /*  4 EINTR        */  "Interrupted function call",
391     /*  5 EIO          */  "I/O error",
392     /*  6 ENXIO        */  "No such device or address",
393     /*  7 E2BIG        */  "Arg list too long",
394     /*  8 ENOEXEC      */  "Exec format error",
395     /*  9 EBADF        */  "Bad file number",
396     /* 10 ECHILD       */  "No child processes",
397     /* 11 EAGAIN       */  "Try again",
398     /* 12 ENOMEM       */  "Out of memory",
399     /* 13 EACCES       */  "Permission denied",
400     /* 14 EFAULT       */  "Bad address",
401     /* 15 ENOTBLK      */  "Unknown error",
402     /* 16 EBUSY        */  "Resource busy",
403     /* 17 EEXIST       */  "File exists",
404     /* 18 EXDEV        */  "Improper link",
405     /* 19 ENODEV       */  "No such device",
406     /* 20 ENOTDIR      */  "Not a directory",
407     /* 21 EISDIR       */  "Is a directory",
408     /* 22 EINVAL       */  "Invalid argument",
409     /* 23 ENFILE       */  "Too many open files in system",
410     /* 24 EMFILE       */  "Too many open files",
411     /* 25 ENOTTY       */  "Inappropriate I/O control operation",
412     /* 26 ETXTBSY      */  "Unknown error",
413     /* 27 EFBIG        */  "File too large",
414     /* 28 ENOSPC       */  "No space left on device",
415     /* 29 ESPIPE       */  "Invalid seek",
416     /* 30 EROFS        */  "Read-only file system",
417     /* 31 EMLINK       */  "Too many links",
418     /* 32 EPIPE        */  "Broken pipe",
419     /* 33 EDOM         */  "Domain error",
420     /* 34 ERANGE       */  "Result too large",
421     /* 35 EUCLEAN      */  "Unknown error",
422     /* 36 EDEADLK      */  "Resource deadlock would occur",
423     /* 37 UNKNOWN      */  "Unknown error",
424     /* 38 ENAMETOOLONG */  "Filename too long",
425     /* 39 ENOLCK       */  "No locks available",
426     /* 40 ENOSYS       */  "Function not implemented",
427     /* 41 ENOTEMPTY    */  "Directory not empty",
428     /* 42 EILSEQ       */  "Illegal byte sequence",
429     /* 43 ENETDOWN     */  "Network is down",
430     /* 44 ECONNRESET   */  "Connection reset",
431     /* 45 ECONNREFUSED */  "Connection refused",
432     /* 46 EADDRINUSE   */  "Address already in use"
433
434 };
435
436 #else /* WIN */
437
438 char *osErrMessages[] =
439 {
440         /*   0                                  */      "Success"
441         /*   1 EPERM                    */      "Operation not permitted"
442         /*   2 ENOENT                   */      "No such file or directory"
443         /*   3 ESRCH                    */      "No such process"
444         /*   4 EINTR                    */      "Interrupted system call"
445         /*   5 EIO                              */      "I/O error"
446         /*   6 ENXIO                    */      "No such device or address"
447         /*   7 E2BIG                    */      "Arg list too long"
448         /*   8 ENOEXEC                  */      "Exec format error"
449         /*   9 EBADF                    */      "Bad file number"
450         /*  10 ECHILD                   */      "No child processes"
451         /*  11 EAGAIN                   */      "Try again"
452         /*  12 ENOMEM                   */      "Out of memory"
453         /*  13 EACCES                   */      "Permission denied"
454         /*  14 EFAULT                   */      "Bad address"
455         /*  15 ENOTBLK                  */      "Block device required"
456         /*  16 EBUSY                    */      "Device or resource busy"
457         /*  17 EEXIST                   */      "File exists"
458         /*  18 EXDEV                    */      "Cross-device link"
459         /*  19 ENODEV                   */      "No such device"
460         /*  20 ENOTDIR                  */      "Not a directory"
461         /*  21 EISDIR                   */      "Is a directory"
462         /*  22 EINVAL                   */      "Invalid argument"
463         /*  23 ENFILE                   */      "File table overflow"
464         /*  24 EMFILE                   */      "Too many open files"
465         /*  25 ENOTTY                   */      "Not a typewriter"
466         /*  26 ETXTBSY                  */      "Text file busy"
467         /*  27 EFBIG                    */      "File too large"
468         /*  28 ENOSPC                   */      "No space left on device"
469         /*  29 ESPIPE                   */      "Illegal seek"
470         /*  30 EROFS                    */      "Read-only file system"
471         /*  31 EMLINK                   */      "Too many links"
472         /*  32 EPIPE                    */      "Broken pipe"
473         /*  33 EDOM                     */      "Math argument out of domain of func"
474         /*  34 ERANGE                   */      "Math result not representable"
475         /*  35 EDEADLK                  */      "Resource deadlock would occur"
476         /*  36 ENAMETOOLONG     */      "File name too long"
477         /*  37 ENOLCK                   */      "No record locks available"
478         /*  38 ENOSYS                   */      "Function not implemented"
479         /*  39 ENOTEMPTY                */      "Directory not empty"
480         /*  40 ELOOP                    */      "Too many symbolic links encountered"
481         /*  41 EWOULDBLOCK EAGAIN */"Operation would block"
482         /*  42 ENOMSG                   */      "No message of desired type"
483         /*  43 EIDRM                    */      "Identifier removed"
484
485 #if !BLD_FEATURE_SQUEEZE
486         /*  44 ECHRNG                   */      "Channel number out of range"
487         /*  45 EL2NSYNC                 */      "Level 2 not synchronized"
488         /*  46 EL3HLT                   */      "Level 3 halted"
489         /*  47 EL3RST                   */      "Level 3 reset"
490         /*  48 ELNRNG                   */      "Link number out of range"
491         /*  49 EUNATCH                  */      "Protocol driver not attached"
492         /*  50 ENOCSI                   */      "No CSI structure available"
493         /*  51 EL2HLT                   */      "Level 2 halted"
494         /*  52 EBADE                    */      "Invalid exchange"
495         /*  53 EBADR                    */      "Invalid request descriptor"
496         /*  54 EXFULL                   */      "Exchange full"
497         /*  55 ENOANO                   */      "No anode"
498         /*  56 EBADRQC                  */      "Invalid request code"
499         /*  57 EBADSLT                  */      "Invalid slot"
500         /*  59 EBFONT                   */      "Bad font file format"
501         /*  60 ENOSTR                   */      "Device not a stream"
502         /*  61 ENODATA                  */      "No data available"
503         /*  62 ETIME                    */      "Timer expired"
504         /*  63 ENOSR                    */      "Out of streams resources"
505         /*  64 ENONET                   */      "Machine is not on the network"
506         /*  65 ENOPKG                   */      "Package not installed"
507         /*  66 EREMOTE                  */      "Object is remote"
508         /*  67 ENOLINK                  */      "Link has been severed"
509         /*  68 EADV                     */      "Advertise error"
510         /*  69 ESRMNT                   */      "Srmount error"
511         /*  70 ECOMM                    */      "Communication error on send"
512         /*  71 EPROTO                   */      "Protocol error"
513         /*  72 EMULTIHOP                */      "Multihop attempted"
514         /*  73 EDOTDOT                  */      "RFS specific error"
515         /*  74 EBADMSG                  */      "Not a data message"
516         /*  75 EOVERFLOW                */      "Value too large for defined data type"
517         /*  76 ENOTUNIQ                 */      "Name not unique on network"
518         /*  77 EBADFD                   */      "File descriptor in bad state"
519         /*  78 EREMCHG                  */      "Remote address changed"
520         /*  79 ELIBACC                  */      "Can not access a needed shared library"
521         /*  80 ELIBBAD                  */      "Accessing a corrupted shared library"
522         /*  81 ELIBSCN                  */      ".lib section in a.out corrupted"
523         /*  82 ELIBMAX                  */      "Linking in too many shared libraries"
524         /*  83 ELIBEXEC                 */      "Cannot exec a shared library directly"
525         /*  84 EILSEQ                   */      "Illegal byte sequence"
526         /*  85 ERESTART                 */      "Interrupted system call should be restarted"
527         /*  86 ESTRPIPE                 */      "Streams pipe error"
528         /*  87 EUSERS                   */      "Too many users"
529         /*  88 ENOTSOCK                 */      "Socket operation on non-socket"
530         /*  89 EDESTADDRREQ             */      "Destination address required"
531         /*  90 EMSGSIZE                 */      "Message too long"
532         /*  91 EPROTOTYPE               */      "Protocol wrong type for socket"
533         /*  92 ENOPROTOOPT              */      "Protocol not available"
534         /*  93 EPROTONOSUPPORT  */      "Protocol not supported"
535         /*  94 ESOCKTNOSUPPORT  */      "Socket type not supported"
536         /*  95 EOPNOTSUPP               */      "Operation not supported on transport endpoint"
537         /*  96 EPFNOSUPPORT     */      "Protocol family not supported"
538         /*  97 EAFNOSUPPORT     */      "Address family not supported by protocol"
539         /*  98 EADDRINUSE               */      "Address already in use"
540         /*  99 EADDRNOTAVAIL    */      "Cannot assign requested address"
541         /* 100 ENETDOWN                 */      "Network is down"
542         /* 101 ENETUNREACH              */      "Network is unreachable"
543         /* 102 ENETRESET                */      "Network dropped connection because of reset"
544         /* 103 ECONNABORTED     */      "Software caused connection abort"
545         /* 104 ECONNRESET               */      "Connection reset by peer"
546         /* 105 ENOBUFS                  */      "No buffer space available"
547         /* 106 EISCONN                  */      "Transport endpoint is already connected"
548         /* 107 ENOTCONN                 */      "Transport endpoint is not connected"
549         /* 108 ESHUTDOWN                */      "Cannot send after transport endpoint shutdown"
550         /* 109 ETOOMANYREFS     */      "Too many references: cannot splice"
551         /* 110 ETIMEDOUT                */      "Connection timed out"
552         /* 111 ECONNREFUSED     */      "Connection refused"
553         /* 112 EHOSTDOWN                */      "Host is down"
554         /* 113 EHOSTUNREACH     */      "No route to host"
555         /* 114 EALREADY                 */      "Operation already in progress"
556         /* 115 EINPROGRESS              */      "Operation now in progress"
557         /* 116 ESTALE                   */      "Stale NFS file handle"
558         /* 117 EUCLEAN                  */      "Structure needs cleaning"
559         /* 118 ENOTNAM                  */      "Not a XENIX named type file"
560         /* 119 ENAVAIL                  */      "No XENIX semaphores available"
561         /* 120 EISNAM                   */      "Is a named type file"
562         /* 121 EREMOTEIO                */      "Remote I/O error"
563         /* 122 EDQUOT                   */      "Quota exceeded"
564         /* 123 ENOMEDIUM                */      "No medium found"
565         /* 124 EMEDIUMTYPE              */      "Wrong medium type"
566 };
567 #endif /* BLD_FEATURE_SQUEEZE */
568 #endif /* WIN */
569
570         int osNumErr = sizeof(osErrMessages) / sizeof(char*);
571
572         if (err < MPR_ERR_BASE) {
573                 err = MPR_ERR_BASE - err;
574                 if (err < 0 || err >= mprNumErr) {
575                         return "Bad error code";
576                 }
577                 return mprErrMessages[err];
578
579         } else {
580                 /*
581                  *      Negative O/S error code. Map to a positive standard Posix error.
582                  */
583                 err = -err;
584                 if (err < 0 || err >= osNumErr) {
585                         return "Bad O/S error code";
586                 }
587                 return osErrMessages[err];
588         }
589 }
590
591 #endif
592 /*****************************************************************************/
593
594 /*
595  * Local variables:
596  * tab-width: 4
597  * c-basic-offset: 4
598  * End:
599  * vim:tw=78
600  * vim600: sw=4 ts=4 fdm=marker
601  * vim<600: sw=4 ts=4
602  */