summaryrefslogtreecommitdiff
path: root/mbglib/common/mbgerror.c
blob: 60eee81d6502cfd794c0131da0ca7a1f17f7897b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733

/**************************************************************************
 *
 *  $Id: mbgerror.c 1.2.1.5 2017/02/22 11:53:24 martin TEST $
 *
 *  Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
 *
 *  Description:
 *    Meinberg Library to communicate with USB devices from user space
 *
 * -----------------------------------------------------------------------
 *  $Log: mbgerror.c $
 *  Revision 1.2.1.5  2017/02/22 11:53:24  martin
 *  Removed type cast.which is now obsolete
 *  due to changed library type.
 *  Revision 1.2.1.4  2016/12/16 12:40:25Z  thomas-b
 *  Added table entry for posix errors for ENOSPC (MBG_ERR_NO_SPACE)
 *  Revision 1.2.1.3  2016/09/13 10:24:02  martin
 *  Fixed some compiler warnings.
 *  Revision 1.2.1.2  2016/08/16 12:48:30Z  gregoire.diehl
 *  CVI fixes
 *  Revision 1.2.1.1  2016/08/11 07:58:15  martin
 *  Fixed a compiler warning.
 *  Revision 1.2  2016/08/05 12:25:44Z  martin
 *  Added some functions.
 *  Revision 1.1  2014/03/07 12:08:14  martin
 *  Initial revision.
 *
 **************************************************************************/

#define _MBGERROR
 #include <mbgerror.h>
#undef _MBGERROR

#include <mbg_tgt.h>

#include <stdio.h>
#include <string.h>

#if defined( MBG_TGT_POSIX ) || \
    defined( MBG_TGT_WIN32 ) || \
    defined( MBG_TGT_DOS )
  #define _MBG_TGT_HAS_POSIX_ERRNO  1
#else
  #define _MBG_TGT_HAS_POSIX_ERRNO  0
#endif

#if _MBG_TGT_HAS_POSIX_ERRNO
  #include <errno.h>
#endif

#if defined( MBG_TGT_DOS )
  #include <stddef.h>
#endif

#if defined( MBG_TGT_POSIX )
  #include <netdb.h>
#endif

#if defined(USE_MBG_ZLIB)
  #include <zlib.h>
#endif


typedef struct
{
  int orig_errno;
  int mbg_errno;

} ERRNO_CNV_ENTRY;



#if _MBG_TGT_HAS_POSIX_ERRNO

static ERRNO_CNV_ENTRY posix_errno_table[] =
{
  // POSIX codes taken from Linux asm-generic/errno.h
  { EPERM,     MBG_ERR_PERM        },  //   1, Operation not permitted
  { ENOENT,    MBG_ERR_NO_ENTITY   },  //   2, No such file or directory
  // { ESRCH,                      },  //   3, No such process
  { EINTR,     MBG_ERR_INTR        },  //   4, Interrupted system call
  { EIO,       MBG_ERR_IO          },  //   5, I/O error
  { ENXIO,     MBG_ERR_NOT_FOUND   },  //   6, No such device or address
  // { E2BIG,                      },  //   7, Argument list too long
  // { ENOEXEC,                    },  //   8, Exec format error
  // { EBADF,                      },  //   9, Bad file number
  // { ECHILD,                     },  //  10, No child processes
  // { EAGAIN,                     },  //  11, Try again
  { ENOMEM,    MBG_ERR_NO_MEM      },  //  12, Out of memory
  { EACCES,    MBG_ERR_ACCESS      },  //  13, Permission denied
  // { EFAULT,                     },  //  14, Bad address
  // { ENOTBLK,                    },  //  15, Block device required
  { EBUSY,     MBG_ERR_BUSY        },  //  16, Device or resource busy
  { EEXIST,    MBG_ERR_EXIST       },  //  17, File exists
  { EXDEV,     MBG_ERR_NO_DEV      },  //  18, Cross-device link
  // { ENODEV,                     },  //  19, No such device
  // { ENOTDIR,                    },  //  20, Not a directory
  // { EISDIR,                     },  //  21, Is a directory
  { EINVAL,    MBG_ERR_INV_PARM    },  //  22, Invalid argument
  // { ENFILE,                     },  //  23, File table overflow
  // { EMFILE,                     },  //  24, Too many open files
  // { ENOTTY,                     },  //  25, Not a typewriter
  // { ETXTBSY,                    },  //  26, Text file busy
  // { EFBIG,                      },  //  27, File too large
  { ENOSPC,    MBG_ERR_NO_SPACE    },  //  28, No space left on device
  { ESPIPE,    MBG_ERR_PIPE        },  //  29, Illegal seek
  // { EROFS,                      },  //  30, Read-only file system
  // { EMLINK,                     },  //  31, Too many links
  // { EPIPE,                      },  //  32, Broken pipe
  // { EDOM,                       },  //  33, Math argument out of domain of func
  { ERANGE,    MBG_ERR_RANGE       },  //  34, Math result not representable
#if defined( EOVERFLOW )
  { EOVERFLOW, MBG_ERR_OVERFLOW    },  //  75, Value too large for defined data type
#endif
#if defined( ENOTSOCK )
  { ENOTSOCK, MBG_ERR_NOT_A_SOCKET },  //  88, Socket operation on non-socket
#endif
#if defined( ECONNRESET )
  { ECONNRESET, MBG_ERR_CONN_RESET },  //  104, Connection reset by peer
#endif
  { 0, 0                           }   // end-of-table identifier

};  // posix_errno_table

#endif  // _MBG_TGT_HAS_POSIX_ERRNO



#if defined( MBG_TGT_POSIX )

static ERRNO_CNV_ENTRY posix_h_errno_table[] =
{
  // POSIX codes taken from Linux netdb.h
  { HOST_NOT_FOUND, MBG_ERR_HOST_NOT_FOUND },  // The specified host is unknown
  // { NO_ADDRESS,       },  // Usually same numeric value as NO_DATA
  // { NO_DATA,          },  // The requested name is valid but does not have an IP address
  // { NO_RECOVERY,      },  // A nonrecoverable name server error occurred
  // { TRY_AGAIN,        },  // A temporary error occurred on an authoritative name server. Try again later.
  { 0, 0                 }   // end-of-table identifier

};  // posix_h_errno_table

#endif  // defined( MBG_TGT_POSIX )



#if defined( MBG_TGT_CVI )

static ERRNO_CNV_ENTRY cvi_rs232_error_table[] = 
{	
  // { kRS_UnknownSysError,            },  // Unknown system error.
  // { kRS_InvalidPortNum,             },  // In valid port number.
  // { kRS_PortNotOpen,                },  // Port is not open.
  // { kRS_UnknownIOError,             },  // Unknown I/O error.
  // { kRS_InternalError,              },  // Unexpected internal error.
  // { kRS_NoPortFound,                },  // No serial port found.
  // { kRS_CanNotOpenPort,             },  // Cannot open port.
  // { kRS_NullPointerPassed,          },  // A NULL pointer was passed when a non-NULL pointer was expected.
  // { kRS_OutOfMemory,                },  // Out of memory.
  // { kRS_OutOfSystemResources,       },  // Unable to allocate system resources.
  // { kRS_InvalidParameter,           },  // Invalid parameter.
  // { kRS_InvalidBaudRate,            },  // Invalid baud rate.
  // { kRS_InvalidParity,              },  // Invalid parity.
  // { kRS_InvalidDataBits,            },  // Invalid number of data bits.
  // { kRS_InvalidStopBits,            },  // Invalid number of stop bits.
  // { kRS_BadFileHandle,              },  // Bad file handle.
  // { kRS_FileIOError,                },  // File I/O error.
  // { kRS_InvalidCount,               },  // Invalid count; must be greater than or equal to 0.
  // { kRS_InvalidIntLevel,            },  // Invalid interrupt level.
  // { kRS_IOTimeOut,                  },  // I/O operation timed out.
  // { kRS_InvalidBreakTime,           },  // Break time must be a positive value.
  // { kRS_InvalidInQSize,             },  // Requested input queue size must be 0 or greater.
  // { kRS_InvalidOutQSize,            },  // Requested output queue size must be 0 or greater.
  // { kRS_GeneralIOFailure,           },  // General I/O error.
  // { kRS_InvalidBufferPointer,       },  // Buffer parameter is NULL.
  // { kRS_VISALibrariesMissing,       },  // A necessary run-time library could not be found or loaded.
  // { kRS_NoAckReceived,              },  // Packet was sent, but no acknowledgment was received.
  // { kRS_MaxRetriesBeforeSend,       },  // Packet was not sent within retry limit.
  // { kRS_MaxRetriesBeforeReceived,   },  // Packet was not received within retry limit.
  // { kRS_UnexpectedEOT,              },  // End of transmission character encountered when start of data character expected.
  // { kRS_CanNotReadPackNum,          },  // Unable to read packet number.
  // { kRS_InconsistentPackNum,        },  // Inconsistent packet number.
  // { kRS_CanNotReadPackData,         },  // Unable to read packet data.
  // { kRS_CanNotReadCheckSum,         },  // Unable to read checksum.
  // { kRS_CheckSumError,              },  // Checksum received did not match computed checksum.
  // { kRS_PackSizeGTInQ,              },  // Packet size exceeds input queue size.
  // { kRS_OpenFileError,              },  // Error opening file.
  // { kRS_ReadFileError,              },  // Error reading file.
  // { kRS_NoInitNegAck,               },  // Did not receive initial negative acknowledgment character.
  // { kRS_NoAckAfterEOT,              },  // Did not receive acknowledgment after end of transmission character was sent.
  // { kRS_WriteFileError,             },  // Error writing to file.
  // { kRS_NoSOHorEOT,                 },  // Did not receive either a start of data or end of transmission character when expected.
  // { kRS_TransferCancelled,          },  // Transfer was canceled because CAN ASCII character was received.
  // { kRS_InvalidStartDelay,          },  // Invalid start delay.
  // { kRS_InvalidMaxTries,            },  // Invalid maximum number of retries.
  // { kRS_InvalidWaitPeriod,          },  // Invalid wait period.
  // { kRS_InvalidPacketSize,          },  // Invalid packet size.
  // { kRS_CanNotReadCRC,              },  // Unable to read Cyclical Redundancy Check.
  // { kRS_CRCError,                   },  // Cyclical Redundancy Check error.
  { 0, 0                               }   // end-of-table identifier

};  // cvi_rs232_error_table

#endif  // defined( MBG_TGT_CVI )



#if defined( MBG_TGT_WIN32 )

static ERRNO_CNV_ENTRY win32_error_table[] =
{
  // System Error Codes (1300-1699)
  { ERROR_ACCESS_DENIED,         MBG_ERR_ACCESS      },  //
  { ERROR_PRIVILEGE_NOT_HELD,    MBG_ERR_PERM        },  //
  { ERROR_INVALID_HANDLE,        MBG_ERR_INV_HANDLE  },  //
  { ERROR_NOT_ENOUGH_MEMORY,     MBG_ERR_NO_MEM      },  //
  { ERROR_OUTOFMEMORY,           MBG_ERR_NO_MEM      },  //
  // { ERROR_WRITE_PROTECT,                          },  //
  // { ERROR_BAD_UNIT,                               },  //
  // { ERROR_NOT_READY,                              },  //
  // { ERROR_WRITE_FAULT,                            },  //
  // { ERROR_READ_FAULT,                             },  //
  // { ERROR_GEN_FAILURE,                            },  //
  // { ERROR_SHARING_VIOLATION,                      },  //
  // { ERROR_LOCK_VIOLATION,                         },  //
  // { ERROR_NOT_SUPPORTED,                          },  //
  // { ERROR_DUP_NAME,                               },  //
  // { ERROR_BAD_DEV_TYPE,                           },  //
  // { ERROR_BUFFER_OVERFLOW,                        },  //
  { ERROR_BUSY,                  MBG_ERR_BUSY        },  //
  // { ERROR_NOACCESS,                               },  //
  { 0, 0                                             }   // end-of-table identifier

};  // win32_error_table



static ERRNO_CNV_ENTRY win32_wsa_err_table[] =
{
  { WSAEINTR,               MBG_ERR_INTR             },    // 10004L A blocking operation was interrupted by a call to WSACancelBlockingCall.
  // { WSAEBADF                                            // 10009L The file handle supplied is not valid.
  // { WSAEACCES                                           // 10013L An attempt was made to access a socket in a way forbidden by its access permissions.
  // { WSAEFAULT                                           // 10014L The system detected an invalid pointer address in attempting to use a pointer argument in a call.
  // { WSAEINVAL                                           // 10022L An invalid argument was supplied.
  // { WSAEMFILE                                           // 10024L Too many open sockets.
  // { WSAEWOULDBLOCK                                      // 10035L A non-blocking socket operation could not be completed immediately.
  // { WSAEINPROGRESS                                      // 10036L A blocking operation is currently executing.
  // { WSAEALREADY                                         // 10037L An operation was attempted on a non-blocking socket that already had an operation in progress.
  { WSAENOTSOCK,            MBG_ERR_NOT_A_SOCKET     },    // 10038L An operation was attempted on something that is not a socket.
  // { WSAEDESTADDRREQ                                     // 10039L A required address was omitted from an operation on a socket.
  // { WSAEMSGSIZE                                         // 10040L A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
  // { WSAEPROTOTYPE                                       // 10041L A protocol was specified in the socket function call that does not support the semantics of the socket type requested.
  // { WSAENOPROTOOPT                                      // 10042L An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call.
  // { WSAEPROTONOSUPPORT                                  // 10043L The requested protocol has not been configured into the system, or no implementation for it exists.
  // { WSAESOCKTNOSUPPORT                                  // 10044L The support for the specified socket type does not exist in this address family.
  // { WSAEOPNOTSUPP                                       // 10045L The attempted operation is not supported for the type of object referenced.
  // { WSAEPFNOSUPPORT                                     // 10046L The protocol family has not been configured into the system or no implementation for it exists.
  // { WSAEAFNOSUPPORT                                     // 10047L An address incompatible with the requested protocol was used.
  // { WSAEADDRINUSE                                       // 10048L Only one usage of each socket address (protocol/network address/port) is normally permitted.
  // { WSAEADDRNOTAVAIL                                    // 10049L The requested address is not valid in its context.
  // { WSAENETDOWN                                         // 10050L A socket operation encountered a dead network.
  // { WSAENETUNREACH                                      // 10051L A socket operation was attempted to an unreachable network.
  // { WSAENETRESET                                        // 10052L The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress.
  // { WSAECONNABORTED                                     // 10053L An established connection was aborted by the software in your host machine.
  { WSAECONNRESET,          MBG_ERR_CONN_RESET       },    // 10054L An existing connection was forcibly closed by the remote host.
  // { WSAENOBUFS                                          // 10055L An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
  // { WSAEISCONN                                          // 10056L A connect request was made on an already connected socket.
  // { WSAENOTCONN                                         // 10057L A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
  // { WSAESHUTDOWN                                        // 10058L A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call.
  // { WSAETOOMANYREFS                                     // 10059L Too many references to some kernel object.
  // { WSAETIMEDOUT                                        // 10060L A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
  // { WSAECONNREFUSED                                     // 10061L No connection could be made because the target machine actively refused it.
  // { WSAELOOP                                            // 10062L Cannot translate name.
  // { WSAENAMETOOLONG                                     // 10063L Name component or name was too long.
  // { WSAEHOSTDOWN                                        // 10064L A socket operation failed because the destination host was down.
  // { WSAEHOSTUNREACH                                     // 10065L A socket operation was attempted to an unreachable host.
  // { WSAENOTEMPTY                                        // 10066L Cannot remove a directory that is not empty.
  // { WSAEPROCLIM                                         // 10067L A Windows Sockets implementation may have a limit on the number of applications that may use it simultaneously.
  // { WSAEUSERS                                           // 10068L Ran out of quota.
  // { WSAEDQUOT                                           // 10069L Ran out of disk quota.
  // { WSAESTALE                                           // 10070L File handle reference is no longer available.
  // { WSAEREMOTE                                          // 10071L Item is not available locally.
  // { WSASYSNOTREADY                                      // 10091L WSAStartup cannot function at this time because the underlying system it uses to provide network services is currently unavailable.
  // { WSAVERNOTSUPPORTED                                  // 10092L The Windows Sockets version requested is not supported.
  { WSANOTINITIALISED,      MBG_ERR_SOCK_INIT        },    // 10093L Either the application has not called WSAStartup, or WSAStartup failed.
  // { WSAEDISCON                                          // 10101L Returned by WSARecv or WSARecvFrom to indicate the remote party has initiated a graceful shutdown sequence.
  // { WSAENOMORE                                          // 10102L No more results can be returned by WSALookupServiceNext.
  // { WSAECANCELLED                                       // 10103L A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
  // { WSAEINVALIDPROCTABLE                                // 10104L The procedure call table is invalid.
  // { WSAEINVALIDPROVIDER                                 // 10105L The requested service provider is invalid.
  // { WSAEPROVIDERFAILEDINIT                              // 10106L The requested service provider could not be loaded or initialized.
  // { WSASYSCALLFAILURE                                   // 10107L A system call that should never fail has failed.
  // { WSASERVICE_NOT_FOUND                                // 10108L No such service is known. The service cannot be found in the specified name space.
  // { WSATYPE_NOT_FOUND                                   // 10109L The specified class was not found.
  // { WSA_E_NO_MORE                                       // 10110L No more results can be returned by WSALookupServiceNext.
  // { WSA_E_CANCELLED                                     // 10111L A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
  // { WSAEREFUSED                                         // 10112L A database query failed because it was actively refused.
  { WSAHOST_NOT_FOUND,      MBG_ERR_HOST_NOT_FOUND   },    // 11001L No such host is known.
  // { WSATRY_AGAIN                                        // 11002L This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server.
  // { WSANO_RECOVERY                                      // 11003L A non-recoverable error occurred during a database lookup.
  // { WSANO_DATA                                          // 11004L The requested name is valid, but no data of the requested type was found.
  { 0, 0                                             }     // end-of-table identifier

};  // win32_wsa_err_table

#endif  // defined( MBG_TGT_WIN32 )



/**
 * @brief Lookup some error code in a conversion table
 *
 * @param[in]  orig_errno
 * @param[in]  tbl
 *
 * @return @ref MBG_ERROR_CODES associated with the original error code,
 *         or ::MBG_ERR_UNSPEC if origianl code not found in table.
 */
static /*HDR*/
int lookup_mbg_errno( int orig_errno, const ERRNO_CNV_ENTRY tbl[] )
{
  const ERRNO_CNV_ENTRY *p;

  for ( p = tbl; p->orig_errno || p->mbg_errno; p++ )
    if ( p->orig_errno == orig_errno )
      return p->mbg_errno;

  return MBG_ERR_UNSPEC;

}  // lookup_mbg_errno



/*HDR*/
/**
 * @brief Return an error string associated with the @ref MBG_ERROR_CODES
 *
 * @param[in] mbg_errno  One of the @ref MBG_ERROR_CODES
 *
 * @return  A constant string describing the error, or NULL for unknown error codes
 */
const char *mbg_strerror( int mbg_errno )
{
  static const MBG_CODE_NAME_TABLE_ENTRY tbl[] = MBG_ERR_NAMES_ENG;

  const MBG_CODE_NAME_TABLE_ENTRY *p;

  for ( p = tbl; p->name; p++ )
  {
    if ( mbg_errno == p->code )
      return p->name;
  }


  return "Unknown error";

}  // mbg_strerror



// test if ioctl error and print msg if true
//### TODO check if this should be renamed
/*HDR*/
int mbg_ioctl_err( int rc, const char *descr )
{
  if ( mbg_rc_is_error( rc ) )
  {
    fprintf( stderr, "** %s: %s (rc: %i)\n", descr, mbg_strerror( rc ), rc );
    return -1;
  }

  return 0;

}  // mbg_ioctl_err



#if defined( MBG_TGT_CVI )

/*HDR*/
/**
 * @brief Translate an error code from the Labwindows/CVI RS-232 library to one of the @ref MBG_ERROR_CODES
 *
 * @param[in] cvi_rc  An error code returned by a CVI RS-232 library function
 * @param[in] info    An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 *
 * @see http://zone.ni.com/reference/en-XX/help/370051V-01/cvi/libref/cvirs232_error_conditions/
 */
int mbg_cvi_rs232_error_to_mbg( int cvi_rc, const char *info )
{
  #if DEBUG
    if ( info )
      fprintf( stderr, "%s, CVI RS-232 rc: %i\n", info, cvi_rc );
  #else
    (void) info;  // avoid compiler warning
  #endif

  return ( cvi_rc < 0 ) ? lookup_mbg_errno( cvi_rc, cvi_rs232_error_table ) : MBG_SUCCESS;

}  // mbg_cvi_rs232_error_to_mbg

#endif



#if defined( MBG_TGT_WIN32 )

/*HDR*/
/**
 * @brief Translate a Windows non-socket API error code to one of the @ref MBG_ERROR_CODES
 *
 * @param[in] last_err  A Windows non-socket API error code as returned by GetLastError()
 * @param[in] info      An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_win32_last_err_to_mbg( DWORD last_err, const char *info )
{
  #if DEBUG
    if ( info )
      fprintf( stderr, "%s, wsa_err: 0x%08lX\n", info, (long) last_err );
  #else
    (void) info;  // avoid compiler warning
  #endif

  return ( last_err == ERROR_SUCCESS ) ? MBG_SUCCESS : lookup_mbg_errno( last_err, win32_error_table );

}  // mbg_win32_last_err_to_mbg



/*HDR*/
/**
 * @brief Translate a Windows socket API error code to one of the @ref MBG_ERROR_CODES
 *
 * @param[in] wsa_err  A Windows socket API error code as returned by WSAGetLastError()
 * @param[in] info     An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_win32_wsa_err_to_mbg( DWORD wsa_err, const char *info )
{
  #if DEBUG
    if ( info )
      fprintf( stderr, "%s, wsa_err: 0x%08lX\n", info, (long) wsa_err );
  #else
    (void) info;  // avoid compiler warning
  #endif

  // The WSA error code is only retrieved after an error has occurred, so
  // we don't need care for the success case here.
  return lookup_mbg_errno( wsa_err, win32_wsa_err_table );

}  // mbg_win32_wsa_err_to_mbg

#endif  // defined( MBG_TGT_WIN32 )



#if _MBG_TGT_HAS_POSIX_ERRNO

/*HDR*/
/**
 * @brief Translate a POSIX errno error code to one of the @ref MBG_ERROR_CODES
 *
 * @param[in] posix_errno  A POSIX error code as usually defined in errno.h
 * @param[in] info         An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_posix_errno_to_mbg( int posix_errno, const char *info )
{
  #if DEBUG
    if ( info )
      fprintf( stderr, "%s: %s (errno: %i)\n", info,
               strerror( posix_errno ), posix_errno );
  #else
    (void) info;  // avoid compiler warning
  #endif

  return lookup_mbg_errno( posix_errno, posix_errno_table );

}  // mbg_posix_errno_to_mbg

#endif  // _MBG_TGT_HAS_POSIX_ERRNO



#if defined( MBG_TGT_POSIX )

/*HDR*/
/**
 * @brief Translate a POSIX h_errno error code to one of the @ref MBG_ERROR_CODES
 *
 * This function is specific to translate error codes returned by
 * gethostbyname() and gethostbyaddr(). In case of error these functions
 * don't set errno but h_errno to a specific value.
 *
 * The functions gethostbyname() and gethostbyaddr() are obsolete,
 * and getaddressinfo() should be used preferably.
 *
 * @param[in] posix_h_errno  An error code as usually defined in netdb.h
 * @param[in] info           An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_posix_h_errno_to_mbg( int posix_h_errno, const char *info )
{
  #if DEBUG
    if ( info )
      fprintf( stderr, "%s: %s (h_errno: %i)\n", info,
               hstrerror( posix_h_errno ), posix_h_errno );
  #else
    (void) info;  // avoid compiler warning
  #endif

  return lookup_mbg_errno( posix_h_errno, posix_h_errno_table );

}  // mbg_posix_h_errno_to_mbg

#endif  // defined( MBG_TGT_POSIX )



/*HDR*/
/**
 * @brief Get and translate last error after non-socket function call
 *
 * Retrieve the "last error" code after a non-socket function has been called
 * and translate to one of the @ref MBG_ERROR_CODES.
 *
 * On POSIX systems the "last error" code is always stored in errno, but
 * e.g. under Windows the "last error" code after a socket function
 * has to be retrieved by calling WSAGetLastError(), whereas the "last error"
 * code from non-socket POSIX-like functions has to be retrieved
 * by calling GetLastError().
 *
 * @param[in] info  An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_get_last_error( const char *info )
{
  #if defined( MBG_TGT_WIN32 )

    // Under Windows the "last error" code after a non-socket function
    // has to be retrieved by calling GetLastError(), whereas
    // the "last error" code from POSIX-like socket functions
    // is retrieved by calling WSAGetLastError().
    return mbg_win32_last_err_to_mbg( GetLastError(), info );

  #elif defined( MBG_TGT_POSIX )

    // On POSIX systems the "last error" code is always stored in errno.
    return mbg_posix_errno_to_mbg( errno, info );

  #else

    // ### TODO #error This function is not supported for this target.
    return mbg_posix_errno_to_mbg( errno, info );

  #endif

}  // mbg_get_last_error



#if !defined( MBG_TGT_DOS )

/*HDR*/
/**
 * @brief Get and translate last error after socket function call
 *
 * Retrieve the "last error" code after a socket function has been called
 * and translate to one of the @ref MBG_ERROR_CODES.
 *
 * On POSIX systems the "last error" code is always stored in errno, but
 * e.g. under Windows the "last error" code after a socket function
 * has to be retrieved by calling WSAGetLastError, whereas the "last error"
 * code from non-socket POSIX-like functions is stored in errno as usual.
 *
 * @param[in] info  An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_get_last_socket_error( const char *info )
{
  #if defined( MBG_TGT_CVI )

    #warning This needs to be implemented for CVI
    return MBG_ERR_UNSPEC;

  #elif defined( MBG_TGT_WIN32 )

    // Under Windows the "last error" code after a socket function
    // has to be retrieved by calling WSAGetLastError, whereas
    // the "last error" code from non-socket POSIX-like functions
    // is stored in errno as usual.
    return mbg_win32_wsa_err_to_mbg( WSAGetLastError(), info );

  #elif defined( MBG_TGT_POSIX )

    // On POSIX systems the "last error" code is always stored in errno.
    return mbg_posix_errno_to_mbg( errno, info );

  #else

    #error This function is not supported for this target.

  #endif

}  // mbg_get_last_socket_error



/*HDR*/
/**
 * @brief Retrieve and convert last error after gethostbyname()
 *
 * This function is specific to retrieve and translate error codes
 * returned by gethostbyname() and gethostbyaddr(). In case of error
 * these functions don't set errno but h_errno on POSIX systems, but
 * under Windows the error code can be retrieved by WSAGetLastError()
 * as usual.
 *
 * The functions gethostbyname() and gethostbyaddr() are obsolete,
 * and getaddressinfo() should be used preferably.
 *
 * @param[in] info  An optional informational text string, or NULL
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_get_gethostbyname_error( const char *info )
{
  #if defined( MBG_TGT_CVI )

    #warning This needs to be implemented for CVI
    return MBG_ERR_UNSPEC;

  #elif defined( MBG_TGT_WIN32 )

    return mbg_win32_wsa_err_to_mbg( WSAGetLastError(), info );

  #elif defined( MBG_TGT_POSIX )

    return mbg_posix_h_errno_to_mbg( h_errno, info );

  #else

    #error This function is not supported for this target.

  #endif

}  // mbg_get_gethostbyname_error

#endif  // !defined( MBG_TGT_DOS )



#if 0  // not yet finished
// error handler for getaddressinfo()
/*
 * Handle specific error returned by getaddressinfo()
 */
 /*HDR*/
int mbg_gai_error( int rc, const char *info )
{
  #if defined( MBG_TGT_CVI )

    #warning This needs to be implemented for CVI
    return MBG_ERR_UNSPEC;

  #elif defined( MBG_TGT_WIN32 )

    return mbg_win32_wsa_err_to_mbg( WSAGetLastError(), info );

  #elif defined( MBG_TGT_POSIX )

    return mbg_posix_h_errno_to_mbg( h_errno, info );

  #else

    return MBG_ERR_UNSPEC;

  #endif

}  // mbg_get_gai_error

#endif



#if defined( USE_MBG_ZLIB )

/*HDR*/
/**
 * @brief Retrieve and convert last zlib internal error code
 *
 * @param[in] zlib_error  zlib internal error code
 * @param[in] info        An optional informational text string, or NULL
 * @param[in] msg         An optional zlib specific error msg, or NULL.
 *                        Struct z_stream contains member msg.
 *
 * @return  One of the @ref MBG_ERROR_CODES
 */
int mbg_zlib_error_to_mbg( int zlib_error, const char *info, const char *msg )
{
  #if DEBUG
    if ( info && msg )
      fprintf( stderr, "%s: %s (zlib_error: %d)\n", info,
               msg, zlib_error );
  #endif

  switch ( zlib_error )
  {
    case Z_ERRNO: return mbg_get_last_error( info );
    case Z_MEM_ERROR: return MBG_ERR_NO_MEM;
    /*
     * All other zlib error codes are not specified any further.
     * So, it's hard to guess what they mean and we return MBG_UNSPEC so far.
     */
    default:
      return MBG_ERR_UNSPEC;
  }

}  // mbg_zlib_error_to_mbg

#endif // defined(USE_MBG_ZLIB)