Freeciv-3.4
Loading...
Searching...
No Matches
support.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14/***********************************************************************
15 This module contains replacements for functions which are not
16 available on all platforms. Where the functions are available
17 natively, these are (mostly) just wrappers.
18
19 Notice the function names here are prefixed by, eg, "fc_".
20 An alternative would be to use the "standard" function name, and
21 provide the implementation only if required. However the method
22 here has some advantages:
23
24 - We can provide definite prototypes in support.h, rather than
25 worrying about whether a system prototype exists, and if so where,
26 and whether it is correct. (Note that whether or not configure
27 finds a function and defines HAVE_FOO does not necessarily say
28 whether or not there is a _prototype_ for the function available.)
29
30 - We don't have to include fc_config.h in support.h, but can instead
31 restrict it to this .c file.
32
33 - We can add some extra stuff to these functions if we want.
34
35 The main disadvantage is need to remember to use these
36 "fc_" functions on systems which have the functions natively.
37
38***********************************************************************/
39
40#ifdef HAVE_CONFIG_H
41#include <fc_config.h>
42#endif
43
44#include "fc_prehdrs.h"
45
46#include <ctype.h>
47#include <errno.h>
48#include <math.h> /* ceil() */
49#include <stdarg.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <sys/stat.h>
54
55#ifdef HAVE_FCNTL_H
56#include <fcntl.h>
57#endif
58#ifdef HAVE_SYS_IOCTL_H
59#include <sys/ioctl.h>
60#endif
61#ifdef HAVE_SYS_SELECT_H
62#include <sys/select.h>
63#endif
64#ifdef HAVE_SYS_TIME_H
65#include <sys/time.h>
66#endif
67#ifdef FREECIV_HAVE_SYS_TYPES_H
68#include <sys/types.h>
69#endif
70#ifdef HAVE_UNISTD_H
71#include <unistd.h> /* usleep, fcntl, gethostname */
72#endif
73#ifdef HAVE_TIME_H
74#include <time.h> /* nanosleep */
75#endif
76#ifdef HAVE_SYS_UTSNAME_H
77#include <sys/utsname.h>
78#endif
79#ifdef FREECIV_HAVE_LIBZ
80#include <zlib.h>
81#endif
82#ifdef FREECIV_MSWINDOWS
83#include <process.h>
84#include <windows.h>
85#endif /* FREECIV_MSWINDOWS */
86#ifdef HAVE_STRINGS_H
87# include <strings.h>
88#endif
89#ifdef HAVE_LIBGEN_H
90/* POSIX version of basename() */
91# include <libgen.h>
92#endif
93
94#ifdef FREECIV_HAVE_LIBZ
95#include <zlib.h>
96#endif
97
98/* ICU */
99#include "unicode/ustring.h"
100
101/* utility */
102#include "fciconv.h"
103#include "fcintl.h"
104#include "fcthread.h"
105#include "log.h"
106#include "mem.h"
107#include "netintf.h"
108
109#include "support.h"
110
112
113static int icu_buffer_uchars = 0;
114static UChar *icu_buffer1 = nullptr;
115static UChar *icu_buffer2 = nullptr;
117
118#ifndef HAVE_WORKING_VSNPRINTF
119static char *vsnprintf_buf = nullptr;
121#endif /* HAVE_WORKING_VSNPRINTF */
122
123#ifndef HAVE_LOCALTIME_R
125#endif /* HAVE_LOCALTIME_R */
126
127/************************************************************************/
130static void icu_buffers_initial(void)
131{
132 if (icu_buffer1 == nullptr) {
133 icu_buffer_uchars = 1024;
134 icu_buffer1 = fc_malloc((icu_buffer_uchars + 1) * sizeof(UChar));
135 icu_buffer2 = fc_malloc((icu_buffer_uchars + 1) * sizeof(UChar));
136
137 /* Make sure there's zero after the buffer published with cmp_buffer_uchars */
140 }
141}
142
143/************************************************************************/
146static void icu_buffers_increase(void)
147{
148 icu_buffer_uchars *= 1.5;
151
152 /* Make sure there's zero after the buffer published with cmp_buffer_uchars */
155}
156
157/************************************************************************/
160static void fc_strAPI_init(void)
161{
162 if (icu_buffer_uchars == 0) {
165 }
166}
167
168/************************************************************************/
171static void fc_strAPI_free(void)
172{
173 if (icu_buffer1 != nullptr) {
175 icu_buffer1 = nullptr;
177 icu_buffer2 = nullptr;
179 }
181}
182
183/************************************************************************/
186int fc_strcasecmp(const char *str0, const char *str1)
187{
189 int len0;
190 int len1;
191 bool enough_mem = FALSE;
192 int ret;
193
194 if (str0 == nullptr) {
195 return -1;
196 }
197 if (str1 == nullptr) {
198 return 1;
199 }
200
201 if (icu_buffer_uchars == 0) {
203 }
204
206
207 while (!enough_mem) {
210
213
214 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
215 * the buffers we were using */
218 } else {
220 }
221 }
222
224 0, &err_code);
225
227
228 return ret;
229}
230
231/************************************************************************/
235int fc_strncasecmp(const char *str0, const char *str1, size_t n)
236{
238 int len0;
239 int len1;
240 bool enough_mem = FALSE;
241 int ret;
242
243 if (str0 == nullptr) {
244 return -1;
245 }
246 if (str1 == nullptr) {
247 return 1;
248 }
249
250 if (icu_buffer_uchars == 0) {
252 }
253
255
256 while (!enough_mem) {
259
262
263 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
264 * the buffers we were using */
267 } else {
269 }
270 }
271
272 if (len0 > n) {
273 len0 = n;
274 }
275 if (len1 > n) {
276 len1 = n;
277 }
278
280 0, &err_code);
281
283
284 return ret;
285}
286
287/************************************************************************/
295void remove_escapes(const char *str, bool full_escapes,
296 char *buf, size_t buf_len)
297{
298 char *dest = buf;
299 const char *const max = buf + buf_len - 1;
300
301 while (*str != '\0' && dest < max) {
302 if (*str == '\\' && *(str + 1) == '\n') {
303 /* Escape followed by newline. Skip both */
304 str += 2;
305 } else if (full_escapes && *str == '\\') {
306 str++;
307 if (*str == 'n') {
308 *dest++ = '\n';
309 str++;
310 }
311 } else {
312 *dest++ = *str++;
313 }
314 }
315 *dest = '\0';
316}
317
318/************************************************************************/
321size_t effectivestrlenquote(const char *str)
322{
323 int len;
324
325 if (!str) {
326 return 0;
327 }
328
329 len = strlen(str);
330
331 if (str[0] == '"' && str[len-1] == '"') {
332 return len - 2;
333 }
334
335 return len;
336}
337
338/************************************************************************/
342int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
343{
344 size_t i;
345 size_t len0;
346 size_t len1;
347 size_t cmplen;
348
349 if (str0 == nullptr) {
350 return -1;
351 }
352 if (str1 == nullptr) {
353 return 1;
354 }
355
356 len0 = strlen(str0); /* TODO: We iterate string once already here, */
357 len1 = strlen(str1); /* could iterate only once */
358
359 if (str0[0] == '"') {
360 if (str0[len0 - 1] == '"') {
361 /* Surrounded with quotes */
362 str0++;
363 len0 -= 2;
364 }
365 }
366
367 if (str1[0] == '"') {
368 if (str1[len1 - 1] == '"') {
369 /* Surrounded with quotes */
370 str1++;
371 len1 -= 2;
372 }
373 }
374
375 if (len0 < n || len1 < n) {
376 /* One of the strings is shorter than what should be compared... */
377 if (len0 != len1) {
378 /* ...and another is longer than it. */
379 return len0 - len1;
380 }
381
382 cmplen = len0; /* This avoids comparing ending quote */
383 } else {
384 cmplen = n;
385 }
386
387 for (i = 0; i < cmplen ; i++, str0++, str1++) {
388 if (fc_tolower(*str0) != fc_tolower(*str1)) {
389 return ((int) (unsigned char) fc_tolower(*str0))
390 - ((int) (unsigned char) fc_tolower(*str1));
391 }
392 }
393
394 /* All characters compared and all matched */
395 return 0;
396}
397
398/************************************************************************/
402char *fc_strcasestr(const char *haystack, const char *needle)
403{
404#ifdef HAVE_STRCASESTR
405 return strcasestr(haystack, needle);
406#else
407 size_t haystacks;
408 size_t needles;
409 const char *p;
410
411 if (needle == nullptr || '\0' == *needle) {
412 return (char *)haystack;
413 }
414 if (haystack == nullptr || '\0' == *haystack) {
415 return nullptr;
416 }
419 if (haystacks < needles) {
420 return nullptr;
421 }
422
423 for (p = haystack; p <= &haystack[haystacks - needles]; p++) {
424 if (0 == fc_strncasecmp(p, needle, needles)) {
425 return (char *)p;
426 }
427 }
428
429 return nullptr;
430#endif /* HAVE_STRCASESTR */
431}
432
433/************************************************************************/
436int fc_strcoll(const char *str0, const char *str1)
437{
438#if defined(ENABLE_NLS) && defined(HAVE_STRCOLL)
439 return strcoll(str0, str1);
440#elif defined(ENABLE_NLS) && defined(HAVE__STRCOLL)
441 return _strcoll(str0, str1);
442#else
443 return strcmp(str0, str1);
444#endif
445}
446
447/************************************************************************/
450int fc_stricoll(const char *str0, const char *str1)
451{
452 /* We prefer _stricoll() over stricoll() since
453 * latter is not declared in MinGW headers causing compiler
454 * warning, preventing -Werror builds. */
455#if defined(ENABLE_NLS) && defined(HAVE__STRICOLL)
456 return _stricoll(str0, str1);
457#elif defined(ENABLE_NLS) && defined(HAVE_STRICOLL)
458 return stricoll(str0, str1);
459#elif defined(ENABLE_NLS) && defined(HAVE_STRCASECOLL)
460 return strcasecoll(str0, str1);
461#else
462 return fc_strcasecmp(str0, str1);
463#endif
464}
465
466/************************************************************************/
470FILE *fc_fopen(const char *filename, const char *opentype)
471{
472 FILE *result;
473
474#ifdef FREECIV_MSWINDOWS
476#else /* FREECIV_MSWINDOWS */
477 const char *real_filename = filename;
478#endif /* FREECIV_MSWINDOWS */
479
480#ifdef HAVE_FOPEN_S
481 if (fopen_s(&result, real_filename, opentype) != 0) {
482 result = nullptr;
483 }
484#else /* HAVE_FOPEN_S */
485 result = fopen(real_filename, opentype);
486#endif /* HAVE_FOPEN_S */
487
488#ifdef FREECIV_MSWINDOWS
490#endif /* FREECIV_MSWINDOWS */
491
492 return result;
493}
494
495/************************************************************************/
499#ifdef FREECIV_HAVE_LIBZ
500gzFile fc_gzopen(const char *filename, const char *opentype)
501{
502#ifdef FREECIV_MSWINDOWS
503 gzFile result;
506
509 return result;
510#else /* FREECIV_MSWINDOWS */
511 return gzopen(filename, opentype);
512#endif /* FREECIV_MSWINDOWS */
513}
514#endif /* FREECIV_HAVE_LIBZ */
515
516/************************************************************************/
520int fc_remove(const char *filename)
521{
522#ifdef FREECIV_MSWINDOWS
523 int result;
526
529 return result;
530#else /* FREECIV_MSWINDOWS */
531 return remove(filename);
532#endif /* FREECIV_MSWINDOWS */
533}
534
535/************************************************************************/
539int fc_stat(const char *filename, struct stat *buf)
540{
541#ifdef FREECIV_MSWINDOWS
542 int result;
545
548 return result;
549#else /* FREECIV_MSWINDOWS */
550 return stat(filename, buf);
551#endif /* FREECIV_MSWINDOWS */
552}
553
554/************************************************************************/
558{
559#ifdef FREECIV_MSWINDOWS
560 return GetLastError();
561#else /* FREECIV_MSWINDOWS */
562 return errno;
563#endif /* FREECIV_MSWINDOWS */
564}
565
566/************************************************************************/
575{
576#ifdef FREECIV_MSWINDOWS
577 static char buf[256];
578
580 nullptr, err, 0, buf, sizeof(buf), nullptr)) {
581 fc_snprintf(buf, sizeof(buf),
582 _("error %ld (failed FormatMessage)"), err);
583 }
584 return buf;
585#else /* FREECIV_MSWINDOWS */
586#ifdef HAVE_STRERROR
587 static char buf[256];
588
590 buf, sizeof(buf));
591#else /* HAVE_STRERROR */
592 static char buf[64];
593
594 fc_snprintf(buf, sizeof(buf),
595 _("error %d (compiled without strerror)"), err);
596 return buf;
597#endif /* HAVE_STRERROR */
598#endif /* FREECIV_MSWINDOWS */
599}
600
601/************************************************************************/
604void fc_usleep(unsigned long usec)
605{
606#ifdef HAVE_NANOSLEEP
607 struct timespec ts;
608
609 if (usec >= 1000000) {
610 ts.tv_sec = usec / 1000000;
611 ts.tv_nsec = (usec % 1000000) * 1000;
612 } else {
613 ts.tv_sec = 0;
614 ts.tv_nsec = usec * 1000;
615 }
616
617 nanosleep(&ts, nullptr);
618#else /* HAVE_NANOSLEEP */
619#ifdef HAVE_USLEEP
620 usleep(usec);
621#else /* HAVE_USLEEP */
622#ifdef HAVE_SNOOZE /* BeOS */
623 snooze(usec);
624#else /* HAVE_SNOOZE */
625#ifdef FREECIV_MSWINDOWS
626 Sleep(usec / 1000);
627#else /* FREECIV_MSWINDOWS */
629
630 tv.tv_sec = 0;
631 tv.tv_usec = usec;
632 /* FIXME: an interrupt can cause an EINTR return here. In that case we
633 * need to have another select call. */
634 fc_select(0, nullptr, nullptr, nullptr, &tv);
635#endif /* FREECIV_MSWINDOWS */
636#endif /* HAVE_SNOOZE */
637#endif /* HAVE_USLEEP */
638#endif /* HAVE_NANOSLEEP */
639}
640
641/************************************************************************/
646char *fc_strrep_resize(char *str, size_t *len, const char *search,
647 const char *replace)
648{
649 size_t len_max;
650
651 fc_assert_ret_val(str != nullptr, nullptr);
652 fc_assert_ret_val(len != nullptr, nullptr);
653
654 if (search == nullptr || replace == nullptr) {
655 return str;
656 }
657
658 len_max = ceil((double)strlen(str) * strlen(replace) / strlen(search)) + 1;
659 if ((*len) < len_max) {
660 /* Replace string is longer than search string; allocate enough memory
661 * for the worst case */
662 (*len) = len_max;
664 }
665
666#ifndef FREECIV_NDEBUG
667 bool success =
668#endif
669 fc_strrep(str, (*len), search, replace);
670
671 /* Should never happen */
673 "Can't replace '%s' by '%s' in '%s'. Too small "
674 "size after reallocation: " SIZE_T_PRINTF ".",
675 search, replace, str, *len);
676
677 return str;
678}
679
680/************************************************************************/
685bool fc_strrep(char *str, size_t len, const char *search,
686 const char *replace)
687{
688 size_t len_search, len_replace;
689 char *s, *p;
690
691 fc_assert_ret_val(str != nullptr, FALSE);
692
693 if (search == nullptr || replace == nullptr) {
694 return TRUE;
695 }
696
698 len_replace = strlen(replace);
699
700 s = str;
701 while (s != nullptr) {
702 p = strstr(s, search);
703 if (p == nullptr) {
704 /* Nothing found */
705 break;
706 }
707
708 if (len < (strlen(str) + len_replace - len_search + 1)) {
709 /* sizeof(str) not large enough to do the replacement */
710 return FALSE;
711 }
712
713 memmove(p + len_replace, p + len_search, strlen(p + len_search) + 1);
714 memcpy(p, replace, len_replace);
715 s = p + len_replace;
716 }
717
718 return TRUE;
719}
720
721/************************************************************************/
742size_t fc_strlcpy(char *dest, const char *src, size_t n)
743{
744 bool enough_mem = FALSE;
745 int slen;
746 int dlen;
748
749 fc_assert_ret_val(dest != nullptr, -1);
750 fc_assert_ret_val(src != nullptr, -1);
751 fc_assert_ret_val(0 < n, -1);
752
753 if (icu_buffer_uchars == 0) {
755 }
756
758
759 while (!enough_mem) {
761
762 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
763 * the buffers we were using */
767 } else {
769 }
770 }
771
772 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
773
775
776 dest[n - 1] = '\0';
777
778 return dlen;
779}
780
781/************************************************************************/
787size_t fc_strlcat(char *dest, const char *src, size_t n)
788{
789 size_t start;
790
791 start = strlen(dest);
792
793 fc_assert(start < n);
794
795 return fc_strlcpy(dest + start, src, n - start) + start;
796}
797
798/************************************************************************/
849/* This must be at least as big as PLAIN_FILE_BUF_SIZE in ioz.c */
850#define VSNP_BUF_SIZE (8096*1024)
851int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
852{
853#ifdef HAVE_WORKING_VSNPRINTF
854 int r;
855#endif
856
857 /* This may be overzealous, but I suspect any triggering of these to
858 * be bugs. */
859
860 fc_assert_ret_val(0 < n, -1);
861
862#ifdef HAVE_WORKING_VSNPRINTF
863 r = vsnprintf(str, n, format, ap);
864 str[n - 1] = 0;
865
866 return r;
867#else /* HAVE_WORKING_VSNPRINTF */
868 {
869 /* Don't use fc_malloc() or log_*() here, since they may call
870 fc_vsnprintf() if it fails. */
871 size_t len;
872
873 if (n > VSNP_BUF_SIZE) {
874 fprintf(stderr, "fc_vsnprintf() call with length " SIZE_T_PRINTF "."
875 "Maximum supported is %d", n, VSNP_BUF_SIZE);
877 }
878
880
881 if (vsnprintf_buf == nullptr) {
883
884 if (vsnprintf_buf == nullptr) {
885 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
886 "replacement.", VSNP_BUF_SIZE);
888
890 }
891 }
892
893 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
894
895#ifdef HAVE_VSNPRINTF
897#else
898 vsprintf(vsnprintf_buf, format, ap);
899#endif /* HAVE_VSNPRINTF */
900
902
903 if (len >= VSNP_BUF_SIZE - 1) {
904 fprintf(stderr, "Overflow in vsnprintf replacement!"
905 " (buffer size %d) aborting...\n", VSNP_BUF_SIZE);
906 abort();
907 }
908 if (n >= len + 1) {
910 } else {
911 memcpy(str, vsnprintf_buf, n - 1);
912 str[n - 1] = '\0';
913 }
914
916
917 return len;
918 }
919#endif /* HAVE_WORKING_VSNPRINTF */
920}
921
922/************************************************************************/
925int fc_snprintf(char *str, size_t n, const char *format, ...)
926{
927 int ret;
928 va_list ap;
929
930 va_start(ap, format);
931 ret = fc_vsnprintf(str, n, format, ap);
932 va_end(ap);
933
934 return ret;
935}
936
937/************************************************************************/
951int cat_snprintf(char *str, size_t n, const char *format, ...)
952{
953 size_t len;
954 int ret;
955 va_list ap;
956
957 fc_assert_ret_val(0 < n, -1);
958
959 len = strlen(str);
960 fc_assert_ret_val(len < n, -1);
961
962 va_start(ap, format);
963 ret = fc_vsnprintf(str+len, n-len, format, ap);
964 va_end(ap);
965
966 return (-1 == ret ? -1 : ret + len);
967}
968
969/************************************************************************/
972int fc_gethostname(char *buf, size_t len)
973{
974#ifdef HAVE_GETHOSTNAME
975 return gethostname(buf, len);
976#else
977 return -1;
978#endif
979}
980
981#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
982/****************************************************************************
983 Support for console I/O in case FREECIV_SOCKET_ZERO_NOT_STDIN.
984****************************************************************************/
985
986#define CONSOLE_BUF_SIZE 100
987static char console_buf[CONSOLE_BUF_SIZE + 1];
988
989/***************************************************************************/
990
991#ifdef FREECIV_MSWINDOWS
993
994/************************************************************************/
998{
1000 char *s;
1001
1002 if ((s = strchr(console_buf, '\n'))) {
1003 *s = '\0';
1004 }
1005 }
1006
1007 return 0;
1008}
1009#endif /* FREECIV_MSWINDOWS */
1010
1011/************************************************************************/
1014void fc_init_console(void)
1015{
1016#ifdef FREECIV_MSWINDOWS
1018 return;
1019 }
1020
1021 console_buf[0] = '\0';
1023 nullptr, 0, nullptr);
1024#else /* FREECIV_MSWINDOWS */
1025 static bool initialized = FALSE;
1026
1027 if (!initialized) {
1028 initialized = TRUE;
1029#ifdef HAVE_FILENO
1031#endif
1032 }
1033#endif /* FREECIV_MSWINDOWS */
1034}
1035
1036/************************************************************************/
1043char *fc_read_console(void)
1044{
1045#ifdef FREECIV_MSWINDOWS
1049
1050 return console_buf;
1051 }
1052
1053 return nullptr;
1054#else /* FREECIV_MSWINDOWS */
1055 if (!feof(stdin)) { /* input from server operator */
1056 static char *bufptr = console_buf;
1057
1058 /* fetch chars until \n, or run out of space in buffer */
1059 /* blocks if fc_nonblock() in fc_init_console() failed */
1060 while ((*bufptr = fgetc(stdin)) != EOF) {
1061 if (*bufptr == '\n') {
1062 *bufptr = '\0';
1063 }
1064 if (*bufptr == '\0') {
1066
1067 return console_buf;
1068 }
1069 if ((bufptr - console_buf) <= CONSOLE_BUF_SIZE) {
1070 bufptr++; /* prevent overrun */
1071 }
1072 }
1073 }
1074
1075 return nullptr;
1076#endif /* FREECIV_MSWINDOWS */
1077}
1078
1079#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
1080
1081/************************************************************************/
1086{
1087 struct stat tmp;
1088
1089 if (fc_stat(name, &tmp) == 0) {
1090 return S_ISREG(tmp.st_mode);
1091 } else {
1092 return write_access && errno == ENOENT;
1093 }
1094}
1095
1096/************************************************************************/
1101{
1102 size_t slen = (size_t)strlen(str);
1103 int num_lines = 0;
1104
1105 /* At top of this loop, s points to the rest of string,
1106 * either at start or after inserted newline: */
1107 top:
1108 if (str && *str != '\0' && slen > desired_len) {
1109 char *c;
1110
1111 num_lines++;
1112
1113 /* Check if there is already a newline: */
1114 for (c = str; c < str + desired_len; c++) {
1115 if (*c == '\n') {
1116 slen -= c + 1 - str;
1117 str = c + 1;
1118 goto top;
1119 }
1120 }
1121
1122 /* Find space and break: */
1123 for (c = str + desired_len; c > str; c--) {
1124 if (fc_isspace(*c)) {
1125 *c = '\n';
1126 slen -= c + 1 - str;
1127 str = c + 1;
1128 goto top;
1129 }
1130 }
1131
1132 /* Couldn't find a good break; settle for a bad one... */
1133 for (c = str + desired_len + 1; *c != '\0'; c++) {
1134 if (fc_isspace(*c)) {
1135 *c = '\n';
1136 slen -= c + 1 - str;
1137 str = c + 1;
1138 goto top;
1139 }
1140 }
1141 }
1142
1143 return num_lines;
1144}
1145
1146/****************************************************************************
1147 Character function wrappers
1148
1149 These functions are wrappers for the libc character class functions,
1150 without any locale-dependent behavior. The character functions work as
1151 documented for ASCII. Bytes outside of the ASCII set will not be reported
1152 to belong to any character class, and will be left unchanged by
1153 transformations. This behavior is safe but not strictly correct
1154 forsingle-byte 8-bit- or UTF-8 encoded text; in UTF-8, any byte that is
1155 part of a multibyte sequence is non-ASCII.
1156****************************************************************************/
1157
1158/************************************************************************/
1161bool fc_isalnum(char c)
1162{
1163 if (128 <= (unsigned char) c) {
1164 return FALSE;
1165 }
1166 return isalnum((int) ((unsigned char) c)) != 0;
1167}
1168
1169/************************************************************************/
1172bool fc_isalpha(char c)
1173{
1174 if (128 <= (unsigned char) c) {
1175 return FALSE;
1176 }
1177 return isalpha((int) ((unsigned char) c)) != 0;
1178}
1179
1180/************************************************************************/
1183bool fc_isdigit(char c)
1184{
1185 if (128 <= (unsigned char) c) {
1186 return FALSE;
1187 }
1188 return isdigit((int) ((unsigned char) c)) != 0;
1189}
1190
1191/************************************************************************/
1194bool fc_isprint(char c)
1195{
1196 if (128 <= (unsigned char) c) {
1197 return FALSE;
1198 }
1199 return isprint((int) ((unsigned char) c)) != 0;
1200}
1201
1202/************************************************************************/
1205bool fc_isspace(char c)
1206{
1207 if (128 <= (unsigned char) c) {
1208 return FALSE;
1209 }
1210 return isspace((int) ((unsigned char) c)) != 0;
1211}
1212
1213/************************************************************************/
1216bool fc_isupper(char c)
1217{
1218 if (128 <= (unsigned char) c) {
1219 return FALSE;
1220 }
1221 return isupper((int) ((unsigned char) c)) != 0;
1222}
1223
1224/************************************************************************/
1227char fc_toupper(char c)
1228{
1229 if (128 <= (unsigned char) c) {
1230 return c;
1231 }
1232 return (char) toupper((int) ((unsigned char) c));
1233}
1234
1235/************************************************************************/
1238char fc_tolower(char c)
1239{
1240 if (128 <= (unsigned char) c) {
1241 return c;
1242 }
1243 return (char) tolower((int) ((unsigned char) c));
1244}
1245
1246/************************************************************************/
1252const char *fc_basename(const char *path)
1253{
1254 static char buf[2048];
1255
1256 /* Copy const parameter string to buffer that basename() can
1257 * modify */
1258 fc_strlcpy(buf, path, sizeof(buf));
1259
1260 return basename(buf);
1261}
1262
1263/************************************************************************/
1266struct tm *fc_localtime(const time_t *timep, struct tm *result)
1267{
1268#ifdef HAVE_LOCALTIME_R
1269 return localtime_r(timep, result);
1270#else /* HAVE_LOCALTIME_R */
1272 memcpy(result, localtime(timep), sizeof(struct tm));
1274
1275 return result;
1276#endif /* HAVE_LOCALTIME_R */
1277}
1278
1279/************************************************************************/
1282int fc_at_quick_exit(void (*func)(void))
1283{
1284#ifdef HAVE_AT_QUICK_EXIT
1285 return at_quick_exit(func);
1286#else /* HAVE_AT_QUICK_EXIT */
1287 return -1;
1288#endif /* HAVE_AT_QUICK_EXIT */
1289}
1290
1291/************************************************************************/
1295{
1297
1298#ifndef HAVE_WORKING_VSNPRINTF
1300#endif /* HAVE_WORKING_VSNPRINTF */
1301
1302#ifndef HAVE_LOCALTIME_R
1304#endif /* HAVE_LOCALTIME_R */
1305
1307}
1308
1309/************************************************************************/
1313{
1315
1316#ifndef HAVE_WORKING_VSNPRINTF
1317 if (vsnprintf_buf != nullptr) {
1319 vsnprintf_buf = nullptr;
1320 }
1322#endif /* HAVE_WORKING_VSNPRINTF */
1323
1324#ifndef HAVE_LOCALTIME_R
1326#endif /* HAVE_LOCALTIME_R */
1327
1329}
1330
1331/************************************************************************/
1335{
1336 return support_initialized;
1337}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
char * incite_cost
Definition comments.c:77
static bool initialized
Definition effects.c:42
char * internal_to_local_string_malloc(const char *text)
char * local_to_internal_string_buffer(const char *text, char *buf, size_t bufsz)
#define _(String)
Definition fcintl.h:67
void fc_mutex_allocate(fc_mutex *mutex)
Definition fcthread.c:144
void fc_mutex_init(fc_mutex *mutex)
Definition fcthread.c:128
void fc_mutex_release(fc_mutex *mutex)
Definition fcthread.c:152
void fc_mutex_destroy(fc_mutex *mutex)
Definition fcthread.c:136
const char * name
Definition inputfile.c:127
get_token_fn_t func
Definition inputfile.c:128
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:209
#define fc_realloc(ptr, sz)
Definition mem.h:36
#define fc_malloc(sz)
Definition mem.h:34
void fc_nonblock(int sockfd)
Definition netintf.c:227
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
Definition netintf.c:125
struct timeval fc_timeval
Definition netintf.h:90
int len
Definition packhand.c:129
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:925
bool fc_isalpha(char c)
Definition support.c:1172
int fc_gethostname(char *buf, size_t len)
Definition support.c:972
bool fc_isprint(char c)
Definition support.c:1194
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:742
static bool support_initialized
Definition support.c:111
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
void fc_usleep(unsigned long usec)
Definition support.c:604
void fc_support_init(void)
Definition support.c:1294
bool fc_isspace(char c)
Definition support.c:1205
const char * fc_strerror(fc_errno err)
Definition support.c:574
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:787
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:402
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:685
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1266
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:951
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:851
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:470
static void fc_strAPI_free(void)
Definition support.c:171
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1100
static fc_mutex localtime_mutex
Definition support.c:124
static UChar * icu_buffer1
Definition support.c:114
fc_mutex icu_buffer_mutex
Definition support.c:116
fc_errno fc_get_errno(void)
Definition support.c:557
void fc_support_free(void)
Definition support.c:1312
void remove_escapes(const char *str, bool full_escapes, char *buf, size_t buf_len)
Definition support.c:295
bool fc_isdigit(char c)
Definition support.c:1183
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:436
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:539
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1085
bool fc_isalnum(char c)
Definition support.c:1161
bool fc_isupper(char c)
Definition support.c:1216
const char * fc_basename(const char *path)
Definition support.c:1252
static void icu_buffers_initial(void)
Definition support.c:130
gzFile fc_gzopen(const char *filename, const char *opentype)
Definition support.c:500
static char * vsnprintf_buf
Definition support.c:119
static int icu_buffer_uchars
Definition support.c:113
int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
Definition support.c:342
static fc_mutex vsnprintf_mutex
Definition support.c:120
static void fc_strAPI_init(void)
Definition support.c:160
size_t effectivestrlenquote(const char *str)
Definition support.c:321
char fc_tolower(char c)
Definition support.c:1238
static void icu_buffers_increase(void)
Definition support.c:146
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1282
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:450
int fc_remove(const char *filename)
Definition support.c:520
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
char * fc_strrep_resize(char *str, size_t *len, const char *search, const char *replace)
Definition support.c:646
static UChar * icu_buffer2
Definition support.c:115
bool are_support_services_available(void)
Definition support.c:1334
char fc_toupper(char c)
Definition support.c:1227
#define VSNP_BUF_SIZE
Definition support.c:850
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int fc_errno
Definition support.h:140