]> sigrok.org Git - libserialport.git/blob - serialport.c
Rename "name" to "value" to be more consistent with Windows terminology.
[libserialport.git] / serialport.c
1 /*
2  * This file is part of the libserialport project.
3  *
4  * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5  * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
6  * Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as
10  * published by the Free Software Foundation, either version 3 of the
11  * License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #ifdef _WIN32
30 #include <windows.h>
31 #include <tchar.h>
32 #else
33 #include <termios.h>
34 #include <sys/ioctl.h>
35 #endif
36 #ifdef __APPLE__
37 #include <IOKitLib.h>
38 #include <serial/IOSerialKeys.h>
39 #endif
40 #ifdef __linux__
41 #include "libudev.h"
42 #include "linux/serial.h"
43 #endif
44
45 #include "serialport.h"
46
47 static char **sp_list_new(void)
48 {
49         char **list;
50         if ((list = malloc(sizeof(char *))))
51                 list[0] = NULL;
52         return list;
53 }
54
55 static char **sp_list_append(char **list, void *data, size_t len)
56 {
57         void *tmp;
58         unsigned int count;
59         for (count = 0; list[count]; count++);
60         if (!(tmp = realloc(list, sizeof(char *) * (count + 2))))
61                 goto fail;
62         list = tmp;
63         if (!(list[count] = malloc(len)))
64                 goto fail;
65         memcpy(list[count], data, len);
66         list[count + 1] = NULL;
67         return list;
68 fail:
69         sp_free_port_list(list);
70         return NULL;
71 }
72
73 /**
74  * List the serial ports available on the system.
75  *
76  * @return A null-terminated array of port name strings.
77  */
78 char **sp_list_ports(void)
79 {
80         char **list = NULL;
81
82 #ifdef _WIN32
83         HKEY key;
84         TCHAR *value, *data;
85         DWORD max_value_len, max_data_size, max_data_len;
86         DWORD value_len, data_size, data_len;
87         DWORD type, index = 0;
88
89         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
90                         0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
91                 return NULL;
92         if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
93                                 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS)
94                 goto out_close;
95         max_data_len = max_data_size / sizeof(TCHAR);
96         if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR))))
97                 goto out_close;
98         if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR))))
99                 goto out_free_value;
100         if (!(list = sp_list_new()))
101                 goto out;
102         while (
103                 value_len = max_value_len,
104                 data_size = max_data_size,
105                 RegEnumValue(key, index, value, &value_len,
106                         NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
107         {
108                 data_len = data_size / sizeof(TCHAR);
109                 data[data_len] = '\0';
110                 if (type == REG_SZ)
111                         if (!(list = sp_list_append(list,
112                                         data, (data_len + 1) * sizeof(TCHAR))))
113                                 goto out;
114                 index++;
115         }
116 out:
117         free(data);
118 out_free_value:
119         free(value);
120 out_close:
121         RegCloseKey(key);
122         return list;
123 #endif
124 #ifdef __APPLE__
125         mach_port_t master;
126         CFMutableDictionaryRef classes;
127         io_iterator_t iter;
128         char *path;
129         io_object_t port;
130         CFTypeRef cf_path;
131         Boolean result;
132
133         if (IOMasterPort(MACH_PORT_NULL, &master) != KERN_SUCCESS)
134                 return NULL;
135
136         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
137                 return NULL;
138
139         CFDictionarySetValue(classes,
140                         CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
141
142         if (!(IOServiceGetMatchingServices(master, classes, &iter)))
143                 return NULL;
144
145         if (!(path = malloc(PATH_MAX)))
146                 goto out_release;
147
148         if (!(list = sp_list_new()))
149                 goto out;
150
151         while (port = IOIteratorNext(iter)) {
152                 cf_path = IORegistryEntryCreateCFProperty(port,
153                                 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
154                 if (cf_path) {
155                         result = CFStringGetCString(cf_path,
156                                         path, PATH_MAX, kCFStringEncodingASCII);
157                         CFRelease(cf_path);
158                         if (result)
159                                 if (!(list = sp_list_append(list, path, strlen(path) + 1)))
160                                 {
161                                         IOObjectRelease(port);
162                                         goto out;
163                                 }
164                 }
165                 IOObjectRelease(port);
166         }
167
168 out:
169         free(path);
170 out_release:
171         IOObjectRelease(iter);
172         return list;
173 #endif
174 #ifdef __linux__
175         struct udev *ud;
176         struct udev_enumerate *ud_enumerate;
177         struct udev_list_entry *ud_list;
178         struct udev_list_entry *ud_entry;
179         const char *path;
180         struct udev_device *ud_dev, *ud_parent;
181         const char *name;
182         const char *driver;
183         int fd, ioctl_result;
184         struct serial_struct serial_info;
185
186         ud = udev_new();
187         ud_enumerate = udev_enumerate_new(ud);
188         udev_enumerate_add_match_subsystem(ud_enumerate, "tty");
189         udev_enumerate_scan_devices(ud_enumerate);
190         ud_list = udev_enumerate_get_list_entry(ud_enumerate);
191         if (!(list = sp_list_new()))
192                 goto out;
193         udev_list_entry_foreach(ud_entry, ud_list)
194         {
195                 path = udev_list_entry_get_name(ud_entry);
196                 ud_dev = udev_device_new_from_syspath(ud, path);
197                 /* If there is no parent device, this is a virtual tty. */
198                 ud_parent = udev_device_get_parent(ud_dev);
199                 if (ud_parent == NULL)
200                 {
201                         udev_device_unref(ud_dev);
202                         continue;
203                 }
204                 name = udev_device_get_devnode(ud_dev);
205                 /* The serial8250 driver has a hardcoded number of ports.
206                  * The only way to tell which actually exist on a given system
207                  * is to try to open them and make an ioctl call. */
208                 driver = udev_device_get_driver(ud_parent);
209                 if (driver && !strcmp(driver, "serial8250"))
210                 {
211                         if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0)
212                                 goto skip;
213                         ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
214                         close(fd);
215                         if (ioctl_result != 0)
216                                 goto skip;
217                         if (serial_info.type == PORT_UNKNOWN)
218                                 goto skip;
219                 }
220                 list = sp_list_append(list, (void *)name, strlen(name) + 1);
221 skip:
222                 udev_device_unref(ud_dev);
223                 if (!list)
224                         goto out;
225         }
226 out:
227         udev_enumerate_unref(ud_enumerate);
228         udev_unref(ud);
229         return list;
230 #endif
231 }
232
233 /**
234  * Free a port list returned by sp_list_ports.
235  */
236 void sp_free_port_list(char **list)
237 {
238         unsigned int i;
239         for (i = 0; list[i]; i++)
240                 free(list[i]);
241         free(list);
242 }
243
244 static int sp_validate_port(struct sp_port *port)
245 {
246         if (port == NULL)
247                 return 0;
248 #ifdef _WIN32
249         if (port->hdl == INVALID_HANDLE_VALUE)
250                 return 0;
251 #else
252         if (port->fd < 0)
253                 return 0;
254 #endif
255         return 1;
256 }
257
258 #define CHECK_PORT() do { if (!sp_validate_port(port)) return SP_ERR_ARG; } while (0)
259
260 /**
261  * Open the specified serial port.
262  *
263  * @param port Pointer to empty port structure allocated by caller.
264  * @param portname Name of port to open.
265  * @param flags Flags to use when opening the serial port. Possible flags
266  *              are: SP_MODE_RDWR, SP_MODE_RDONLY, SP_MODE_NONBLOCK.
267  *
268  * @return SP_OK on success, SP_ERR_FAIL on failure,
269  *         or SP_ERR_ARG if an invalid port or name is passed.
270  */
271 int sp_open(struct sp_port *port, char *portname, int flags)
272 {
273         if (!port)
274                 return SP_ERR_ARG;
275
276         if (!portname)
277                 return SP_ERR_ARG;
278
279         port->name = portname;
280
281 #ifdef _WIN32
282         DWORD desired_access = 0, flags_and_attributes = 0;
283         /* Map 'flags' to the OS-specific settings. */
284         desired_access |= GENERIC_READ;
285         flags_and_attributes = FILE_ATTRIBUTE_NORMAL;
286         if (flags & SP_MODE_RDWR)
287                 desired_access |= GENERIC_WRITE;
288         if (flags & SP_MODE_NONBLOCK)
289                 flags_and_attributes |= FILE_FLAG_OVERLAPPED;
290
291         port->hdl = CreateFile(port->name, desired_access, 0, 0,
292                          OPEN_EXISTING, flags_and_attributes, 0);
293         if (port->hdl == INVALID_HANDLE_VALUE)
294                 return SP_ERR_FAIL;
295 #else
296         int flags_local = 0;
297         /* Map 'flags' to the OS-specific settings. */
298         if (flags & SP_MODE_RDWR)
299                 flags_local |= O_RDWR;
300         if (flags & SP_MODE_RDONLY)
301                 flags_local |= O_RDONLY;
302         if (flags & SP_MODE_NONBLOCK)
303                 flags_local |= O_NONBLOCK;
304
305         if ((port->fd = open(port->name, flags_local)) < 0)
306                 return SP_ERR_FAIL;
307 #endif
308
309         return SP_OK;
310 }
311
312 /**
313  * Close the specified serial port.
314  *
315  * @param port Pointer to port structure.
316  *
317  * @return SP_OK on success, SP_ERR_FAIL on failure,
318  *         or SP_ERR_ARG if an invalid port is passed.
319  */
320 int sp_close(struct sp_port *port)
321 {
322         CHECK_PORT();
323
324 #ifdef _WIN32
325         /* Returns non-zero upon success, 0 upon failure. */
326         if (CloseHandle(port->hdl) == 0)
327                 return SP_ERR_FAIL;
328 #else
329         /* Returns 0 upon success, -1 upon failure. */
330         if (close(port->fd) == -1)
331                 return SP_ERR_FAIL;
332 #endif
333
334         return SP_OK;
335 }
336
337 /**
338  * Flush serial port buffers.
339  *
340  * @param port Pointer to port structure.
341  *
342  * @return SP_OK on success, SP_ERR_FAIL on failure,
343  *         or SP_ERR_ARG if an invalid port is passed.
344  */
345 int sp_flush(struct sp_port *port)
346 {
347         CHECK_PORT();
348
349 #ifdef _WIN32
350         /* Returns non-zero upon success, 0 upon failure. */
351         if (PurgeComm(port->hdl, PURGE_RXCLEAR | PURGE_TXCLEAR) == 0)
352                 return SP_ERR_FAIL;
353 #else
354         /* Returns 0 upon success, -1 upon failure. */
355         if (tcflush(port->fd, TCIOFLUSH) < 0)
356                 return SP_ERR_FAIL;
357 #endif
358         return SP_OK;
359 }
360
361 /**
362  * Write a number of bytes to the specified serial port.
363  *
364  * @param port Pointer to port structure.
365  * @param buf Buffer containing the bytes to write.
366  * @param count Number of bytes to write.
367  *
368  * @return The number of bytes written, SP_ERR_FAIL on failure,
369  *         or SP_ERR_ARG if an invalid port is passed.
370  */
371 int sp_write(struct sp_port *port, const void *buf, size_t count)
372 {
373         CHECK_PORT();
374
375         if (!buf)
376                 return SP_ERR_ARG;
377
378 #ifdef _WIN32
379         DWORD written = 0;
380         /* Returns non-zero upon success, 0 upon failure. */
381         if (WriteFile(port->hdl, buf, count, &written, NULL) == 0)
382                 return SP_ERR_FAIL;
383         return written;
384 #else
385         /* Returns the number of bytes written, or -1 upon failure. */
386         ssize_t written = write(port->fd, buf, count);
387         if (written < 0)
388                 return SP_ERR_FAIL;
389         else
390                 return written;;
391 #endif
392 }
393
394 /**
395  * Read a number of bytes from the specified serial port.
396  *
397  * @param port Pointer to port structure.
398  * @param buf Buffer where to store the bytes that are read.
399  * @param count The number of bytes to read.
400  *
401  * @return The number of bytes read, SP_ERR_FAIL on failure,
402  *         or SP_ERR_ARG if an invalid port is passed.
403  */
404 int sp_read(struct sp_port *port, void *buf, size_t count)
405 {
406         CHECK_PORT();
407
408         if (!buf)
409                 return SP_ERR_ARG;
410
411 #ifdef _WIN32
412         DWORD bytes_read = 0;
413         /* Returns non-zero upon success, 0 upon failure. */
414         if (ReadFile(port->hdl, buf, count, &bytes_read, NULL) == 0)
415                 return SP_ERR_FAIL;
416         return bytes_read;
417 #else
418         ssize_t bytes_read;
419         /* Returns the number of bytes read, or -1 upon failure. */
420         if ((bytes_read = read(port->fd, buf, count)) < 0)
421                 return SP_ERR_FAIL;
422         return bytes_read;
423 #endif
424 }
425
426 /**
427  * Set serial parameters for the specified serial port.
428  *
429  * @param port Pointer to port structure.
430  * @param baudrate The baudrate to set.
431  * @param bits The number of data bits to use.
432  * @param parity The parity setting to use (0 = none, 1 = even, 2 = odd).
433  * @param stopbits The number of stop bits to use (1 or 2).
434  * @param flowcontrol The flow control settings to use (0 = none, 1 = RTS/CTS,
435  *                    2 = XON/XOFF).
436  *
437  * @return The number of bytes read, SP_ERR_FAIL on failure,
438  *         or SP_ERR_ARG if an invalid argument is passed.
439  */
440 int sp_set_params(struct sp_port *port, int baudrate,
441                               int bits, int parity, int stopbits,
442                               int flowcontrol, int rts, int dtr)
443 {
444         CHECK_PORT();
445
446 #ifdef _WIN32
447         DCB dcb;
448
449         if (!GetCommState(port->hdl, &dcb))
450                 return SP_ERR_FAIL;
451
452         switch (baudrate) {
453         /*
454          * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
455          * have documented CBR_* macros.
456          */
457         case 110:
458                 dcb.BaudRate = CBR_110;
459                 break;
460         case 300:
461                 dcb.BaudRate = CBR_300;
462                 break;
463         case 600:
464                 dcb.BaudRate = CBR_600;
465                 break;
466         case 1200:
467                 dcb.BaudRate = CBR_1200;
468                 break;
469         case 2400:
470                 dcb.BaudRate = CBR_2400;
471                 break;
472         case 4800:
473                 dcb.BaudRate = CBR_4800;
474                 break;
475         case 9600:
476                 dcb.BaudRate = CBR_9600;
477                 break;
478         case 14400:
479                 dcb.BaudRate = CBR_14400; /* Not available on Unix? */
480                 break;
481         case 19200:
482                 dcb.BaudRate = CBR_19200;
483                 break;
484         case 38400:
485                 dcb.BaudRate = CBR_38400;
486                 break;
487         case 57600:
488                 dcb.BaudRate = CBR_57600;
489                 break;
490         case 115200:
491                 dcb.BaudRate = CBR_115200;
492                 break;
493         case 128000:
494                 dcb.BaudRate = CBR_128000; /* Not available on Unix? */
495                 break;
496         case 256000:
497                 dcb.BaudRate = CBR_256000; /* Not available on Unix? */
498                 break;
499         default:
500                 return SP_ERR_ARG;
501         }
502
503         switch (stopbits) {
504         /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
505         case 1:
506                 dcb.StopBits = ONESTOPBIT;
507                 break;
508         case 2:
509                 dcb.StopBits = TWOSTOPBITS;
510                 break;
511         default:
512                 return SP_ERR_ARG;
513         }
514
515         switch (parity) {
516         /* Note: There's also SPACEPARITY, MARKPARITY (unneeded so far). */
517         case SP_PARITY_NONE:
518                 dcb.Parity = NOPARITY;
519                 break;
520         case SP_PARITY_EVEN:
521                 dcb.Parity = EVENPARITY;
522                 break;
523         case SP_PARITY_ODD:
524                 dcb.Parity = ODDPARITY;
525                 break;
526         default:
527                 return SP_ERR_ARG;
528         }
529
530         if (rts != -1) {
531                 if (rts)
532                         dcb.fRtsControl = RTS_CONTROL_ENABLE;
533                 else
534                         dcb.fRtsControl = RTS_CONTROL_DISABLE;
535         }
536
537         if (dtr != -1) {
538                 if (dtr)
539                         dcb.fDtrControl = DTR_CONTROL_ENABLE;
540                 else
541                         dcb.fDtrControl = DTR_CONTROL_DISABLE;
542         }
543
544         if (!SetCommState(port->hdl, &dcb))
545                 return SP_ERR_FAIL;
546 #else
547         struct termios term;
548         speed_t baud;
549         int controlbits;
550
551         if (tcgetattr(port->fd, &term) < 0)
552                 return SP_ERR_FAIL;
553
554         switch (baudrate) {
555         case 50:
556                 baud = B50;
557                 break;
558         case 75:
559                 baud = B75;
560                 break;
561         case 110:
562                 baud = B110;
563                 break;
564         case 134:
565                 baud = B134;
566                 break;
567         case 150:
568                 baud = B150;
569                 break;
570         case 200:
571                 baud = B200;
572                 break;
573         case 300:
574                 baud = B300;
575                 break;
576         case 600:
577                 baud = B600;
578                 break;
579         case 1200:
580                 baud = B1200;
581                 break;
582         case 1800:
583                 baud = B1800;
584                 break;
585         case 2400:
586                 baud = B2400;
587                 break;
588         case 4800:
589                 baud = B4800;
590                 break;
591         case 9600:
592                 baud = B9600;
593                 break;
594         case 19200:
595                 baud = B19200;
596                 break;
597         case 38400:
598                 baud = B38400;
599                 break;
600         case 57600:
601                 baud = B57600;
602                 break;
603         case 115200:
604                 baud = B115200;
605                 break;
606         case 230400:
607                 baud = B230400;
608                 break;
609 #if !defined(__APPLE__) && !defined(__OpenBSD__)
610         case 460800:
611                 baud = B460800;
612                 break;
613 #endif
614         default:
615                 return SP_ERR_ARG;
616         }
617
618         if (cfsetospeed(&term, baud) < 0)
619                 return SP_ERR_FAIL;
620
621         if (cfsetispeed(&term, baud) < 0)
622                 return SP_ERR_FAIL;
623
624         term.c_cflag &= ~CSIZE;
625         switch (bits) {
626         case 8:
627                 term.c_cflag |= CS8;
628                 break;
629         case 7:
630                 term.c_cflag |= CS7;
631                 break;
632         default:
633                 return SP_ERR_ARG;
634         }
635
636         term.c_cflag &= ~CSTOPB;
637         switch (stopbits) {
638         case 1:
639                 term.c_cflag &= ~CSTOPB;
640                 break;
641         case 2:
642                 term.c_cflag |= CSTOPB;
643                 break;
644         default:
645                 return SP_ERR_ARG;
646         }
647
648         term.c_iflag &= ~(IXON | IXOFF | IXANY);
649         term.c_cflag &= ~CRTSCTS;
650         switch (flowcontrol) {
651         case 0:
652                 /* No flow control. */
653                 break;
654         case 1:
655                 term.c_cflag |= CRTSCTS;
656                 break;
657         case 2:
658                 term.c_iflag |= IXON | IXOFF | IXANY;
659                 break;
660         default:
661                 return SP_ERR_ARG;
662         }
663
664         term.c_iflag &= ~IGNPAR;
665         term.c_cflag &= ~(PARENB | PARODD);
666         switch (parity) {
667         case SP_PARITY_NONE:
668                 term.c_iflag |= IGNPAR;
669                 break;
670         case SP_PARITY_EVEN:
671                 term.c_cflag |= PARENB;
672                 break;
673         case SP_PARITY_ODD:
674                 term.c_cflag |= PARENB | PARODD;
675                 break;
676         default:
677                 return SP_ERR_ARG;
678         }
679
680         /* Turn off all serial port cooking. */
681         term.c_iflag &= ~(ISTRIP | INLCR | ICRNL);
682         term.c_oflag &= ~(ONLCR | OCRNL | ONOCR);
683 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
684         term.c_oflag &= ~OFILL;
685 #endif
686
687         /* Disable canonical mode, and don't echo input characters. */
688         term.c_lflag &= ~(ICANON | ECHO);
689
690         /* Ignore modem status lines; enable receiver */
691         term.c_cflag |= (CLOCAL | CREAD);
692
693         /* Write the configured settings. */
694         if (tcsetattr(port->fd, TCSADRAIN, &term) < 0)
695                 return SP_ERR_FAIL;
696
697         if (rts != -1) {
698                 controlbits = TIOCM_RTS;
699                 if (ioctl(port->fd, rts ? TIOCMBIS : TIOCMBIC,
700                                 &controlbits) < 0)
701                         return SP_ERR_FAIL;
702         }
703
704         if (dtr != -1) {
705                 controlbits = TIOCM_DTR;
706                 if (ioctl(port->fd, dtr ? TIOCMBIS : TIOCMBIC,
707                                 &controlbits) < 0)
708                         return SP_ERR_FAIL;
709         }
710 #endif
711
712         return SP_OK;
713 }
714
715 /**
716  * Get error code for failed operation.
717  *
718  * In order to obtain the correct result, this function should be called
719  * straight after the failure, before executing any other system operations.
720  *
721  * @return The system's numeric code for the error that caused the last
722  *         operation to fail.
723  */
724 int sp_last_error_code(void)
725 {
726 #ifdef _WIN32
727         return GetLastError();
728 #else
729         return errno;
730 #endif
731 }
732
733 /**
734  * Get error message for failed operation.
735  *
736  * In order to obtain the correct result, this function should be called
737  * straight after the failure, before executing other system operations.
738  *
739  * @return The system's message for the error that caused the last
740  *         operation to fail. This string may be allocated by the function,
741  *         and can be freed after use by calling sp_free_error_message.
742  */
743 char *sp_last_error_message(void)
744 {
745 #ifdef _WIN32
746         LPVOID message;
747         DWORD error = GetLastError();
748
749         FormatMessage(
750                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
751                 FORMAT_MESSAGE_FROM_SYSTEM |
752                 FORMAT_MESSAGE_IGNORE_INSERTS,
753                 NULL,
754                 error,
755                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
756                 (LPTSTR) &message,
757                 0, NULL );
758
759         return message;
760 #else
761         return strerror(errno);
762 #endif
763 }
764
765 /**
766  * Free error message.
767  *
768  * This function can be used to free a string returned by the
769  * sp_last_error_message function.
770  */
771 void sp_free_error_message(char *message)
772 {
773 #ifdef _WIN32
774         LocalFree(message);
775 #else
776         (void)message;
777 #endif
778 }