Freeciv-3.3
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/************************************************************************/
294void make_escapes(const char *str, char *buf, size_t buf_len)
295{
296 char *dest = buf;
297 /* Sometimes we insert 2 characters at once ('\n' -> "\\n"), so keep
298 * place for '\0' and an extra character. */
299 const char *const max = buf + buf_len - 2;
300
301 while (*str != '\0' && dest < max) {
302 switch (*str) {
303 case '\n':
304 *dest++ = '\\';
305 *dest++ = 'n';
306 str++;
307 break;
308 case '\\':
309 case '\"':
310 *dest++ = '\\';
311
313 default:
314 *dest++ = *str++;
315 break;
316 }
317 }
318 *dest = 0;
319}
320
321/************************************************************************/
330void remove_escapes(const char *str, bool full_escapes,
331 char *buf, size_t buf_len)
332{
333 char *dest = buf;
334 const char *const max = buf + buf_len - 1;
335
336 while (*str != '\0' && dest < max) {
337 if (*str == '\\' && *(str + 1) == '\n') {
338 /* Escape followed by newline. Skip both */
339 str += 2;
340 } else if (full_escapes && *str == '\\') {
341 str++;
342 if (*str == 'n') {
343 *dest++ = '\n';
344 str++;
345 }
346 } else {
347 *dest++ = *str++;
348 }
349 }
350 *dest = '\0';
351}
352
353/************************************************************************/
356size_t effectivestrlenquote(const char *str)
357{
358 int len;
359
360 if (!str) {
361 return 0;
362 }
363
364 len = strlen(str);
365
366 if (str[0] == '"' && str[len-1] == '"') {
367 return len - 2;
368 }
369
370 return len;
371}
372
373/************************************************************************/
377int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
378{
379 size_t i;
380 size_t len0;
381 size_t len1;
382 size_t cmplen;
383
384 if (str0 == nullptr) {
385 return -1;
386 }
387 if (str1 == nullptr) {
388 return 1;
389 }
390
391 len0 = strlen(str0); /* TODO: We iterate string once already here, */
392 len1 = strlen(str1); /* could iterate only once */
393
394 if (str0[0] == '"') {
395 if (str0[len0 - 1] == '"') {
396 /* Surrounded with quotes */
397 str0++;
398 len0 -= 2;
399 }
400 }
401
402 if (str1[0] == '"') {
403 if (str1[len1 - 1] == '"') {
404 /* Surrounded with quotes */
405 str1++;
406 len1 -= 2;
407 }
408 }
409
410 if (len0 < n || len1 < n) {
411 /* One of the strings is shorter than what should be compared... */
412 if (len0 != len1) {
413 /* ...and another is longer than it. */
414 return len0 - len1;
415 }
416
417 cmplen = len0; /* This avoids comparing ending quote */
418 } else {
419 cmplen = n;
420 }
421
422 for (i = 0; i < cmplen ; i++, str0++, str1++) {
423 if (fc_tolower(*str0) != fc_tolower(*str1)) {
424 return ((int) (unsigned char) fc_tolower(*str0))
425 - ((int) (unsigned char) fc_tolower(*str1));
426 }
427 }
428
429 /* All characters compared and all matched */
430 return 0;
431}
432
433/************************************************************************/
437char *fc_strcasestr(const char *haystack, const char *needle)
438{
439#ifdef HAVE_STRCASESTR
440 return strcasestr(haystack, needle);
441#else
442 size_t haystacks;
443 size_t needles;
444 const char *p;
445
446 if (needle == nullptr || '\0' == *needle) {
447 return (char *)haystack;
448 }
449 if (haystack == nullptr || '\0' == *haystack) {
450 return nullptr;
451 }
454 if (haystacks < needles) {
455 return nullptr;
456 }
457
458 for (p = haystack; p <= &haystack[haystacks - needles]; p++) {
459 if (0 == fc_strncasecmp(p, needle, needles)) {
460 return (char *)p;
461 }
462 }
463
464 return nullptr;
465#endif /* HAVE_STRCASESTR */
466}
467
468/************************************************************************/
471int fc_strcoll(const char *str0, const char *str1)
472{
473#if defined(ENABLE_NLS) && defined(HAVE_STRCOLL)
474 return strcoll(str0, str1);
475#elif defined(ENABLE_NLS) && defined(HAVE__STRCOLL)
476 return _strcoll(str0, str1);
477#else
478 return strcmp(str0, str1);
479#endif
480}
481
482/************************************************************************/
485int fc_stricoll(const char *str0, const char *str1)
486{
487 /* We prefer _stricoll() over stricoll() since
488 * latter is not declared in MinGW headers causing compiler
489 * warning, preventing -Werror builds. */
490#if defined(ENABLE_NLS) && defined(HAVE__STRICOLL)
491 return _stricoll(str0, str1);
492#elif defined(ENABLE_NLS) && defined(HAVE_STRICOLL)
493 return stricoll(str0, str1);
494#elif defined(ENABLE_NLS) && defined(HAVE_STRCASECOLL)
495 return strcasecoll(str0, str1);
496#else
497 return fc_strcasecmp(str0, str1);
498#endif
499}
500
501/************************************************************************/
505FILE *fc_fopen(const char *filename, const char *opentype)
506{
507 FILE *result;
508
509#ifdef FREECIV_MSWINDOWS
511#else /* FREECIV_MSWINDOWS */
512 const char *real_filename = filename;
513#endif /* FREECIV_MSWINDOWS */
514
515#ifdef HAVE_FOPEN_S
516 if (fopen_s(&result, real_filename, opentype) != 0) {
517 result = nullptr;
518 }
519#else /* HAVE_FOPEN_S */
520 result = fopen(real_filename, opentype);
521#endif /* HAVE_FOPEN_S */
522
523#ifdef FREECIV_MSWINDOWS
525#endif /* FREECIV_MSWINDOWS */
526
527 return result;
528}
529
530/************************************************************************/
534#ifdef FREECIV_HAVE_LIBZ
535gzFile fc_gzopen(const char *filename, const char *opentype)
536{
537#ifdef FREECIV_MSWINDOWS
538 gzFile result;
541
544 return result;
545#else /* FREECIV_MSWINDOWS */
546 return gzopen(filename, opentype);
547#endif /* FREECIV_MSWINDOWS */
548}
549#endif /* FREECIV_HAVE_LIBZ */
550
551/************************************************************************/
555int fc_remove(const char *filename)
556{
557#ifdef FREECIV_MSWINDOWS
558 int result;
561
564 return result;
565#else /* FREECIV_MSWINDOWS */
566 return remove(filename);
567#endif /* FREECIV_MSWINDOWS */
568}
569
570/************************************************************************/
574int fc_stat(const char *filename, struct stat *buf)
575{
576#ifdef FREECIV_MSWINDOWS
577 int result;
580
583 return result;
584#else /* FREECIV_MSWINDOWS */
585 return stat(filename, buf);
586#endif /* FREECIV_MSWINDOWS */
587}
588
589/************************************************************************/
593{
594#ifdef FREECIV_MSWINDOWS
595 return GetLastError();
596#else /* FREECIV_MSWINDOWS */
597 return errno;
598#endif /* FREECIV_MSWINDOWS */
599}
600
601/************************************************************************/
610{
611#ifdef FREECIV_MSWINDOWS
612 static char buf[256];
613
615 nullptr, err, 0, buf, sizeof(buf), nullptr)) {
616 fc_snprintf(buf, sizeof(buf),
617 _("error %ld (failed FormatMessage)"), err);
618 }
619 return buf;
620#else /* FREECIV_MSWINDOWS */
621#ifdef HAVE_STRERROR
622 static char buf[256];
623
625 buf, sizeof(buf));
626#else /* HAVE_STRERROR */
627 static char buf[64];
628
629 fc_snprintf(buf, sizeof(buf),
630 _("error %d (compiled without strerror)"), err);
631 return buf;
632#endif /* HAVE_STRERROR */
633#endif /* FREECIV_MSWINDOWS */
634}
635
636/************************************************************************/
639void fc_usleep(unsigned long usec)
640{
641#ifdef HAVE_NANOSLEEP
642 struct timespec ts;
643
644 if (usec >= 1000000) {
645 ts.tv_sec = usec / 1000000;
646 ts.tv_nsec = (usec % 1000000) * 1000;
647 } else {
648 ts.tv_sec = 0;
649 ts.tv_nsec = usec * 1000;
650 }
651
652 nanosleep(&ts, nullptr);
653#else /* HAVE_NANOSLEEP */
654#ifdef HAVE_USLEEP
655 usleep(usec);
656#else /* HAVE_USLEEP */
657#ifdef HAVE_SNOOZE /* BeOS */
658 snooze(usec);
659#else /* HAVE_SNOOZE */
660#ifdef FREECIV_MSWINDOWS
661 Sleep(usec / 1000);
662#else /* FREECIV_MSWINDOWS */
664
665 tv.tv_sec = 0;
666 tv.tv_usec = usec;
667 /* FIXME: an interrupt can cause an EINTR return here. In that case we
668 * need to have another select call. */
669 fc_select(0, nullptr, nullptr, nullptr, &tv);
670#endif /* FREECIV_MSWINDOWS */
671#endif /* HAVE_SNOOZE */
672#endif /* HAVE_USLEEP */
673#endif /* HAVE_NANOSLEEP */
674}
675
676/************************************************************************/
681char *fc_strrep_resize(char *str, size_t *len, const char *search,
682 const char *replace)
683{
684 size_t len_max;
685
686 fc_assert_ret_val(str != nullptr, nullptr);
687 fc_assert_ret_val(len != nullptr, nullptr);
688
689 if (search == nullptr || replace == nullptr) {
690 return str;
691 }
692
693 len_max = ceil((double)strlen(str) * strlen(replace) / strlen(search)) + 1;
694 if ((*len) < len_max) {
695 /* Replace string is longer than search string; allocate enough memory
696 * for the worst case */
697 (*len) = len_max;
699 }
700
701#ifndef FREECIV_NDEBUG
702 bool success =
703#endif
704 fc_strrep(str, (*len), search, replace);
705
706 /* Should never happen */
708 "Can't replace '%s' by '%s' in '%s'. Too small "
709 "size after reallocation: " SIZE_T_PRINTF ".",
710 search, replace, str, *len);
711
712 return str;
713}
714
715/************************************************************************/
720bool fc_strrep(char *str, size_t len, const char *search,
721 const char *replace)
722{
723 size_t len_search, len_replace;
724 char *s, *p;
725
726 fc_assert_ret_val(str != nullptr, FALSE);
727
728 if (search == nullptr || replace == nullptr) {
729 return TRUE;
730 }
731
733 len_replace = strlen(replace);
734
735 s = str;
736 while (s != nullptr) {
737 p = strstr(s, search);
738 if (p == nullptr) {
739 /* Nothing found */
740 break;
741 }
742
743 if (len < (strlen(str) + len_replace - len_search + 1)) {
744 /* sizeof(str) not large enough to do the replacement */
745 return FALSE;
746 }
747
748 memmove(p + len_replace, p + len_search, strlen(p + len_search) + 1);
749 memcpy(p, replace, len_replace);
750 s = p + len_replace;
751 }
752
753 return TRUE;
754}
755
756/************************************************************************/
777size_t fc_strlcpy(char *dest, const char *src, size_t n)
778{
779 bool enough_mem = FALSE;
780 int slen;
781 int dlen;
783
784 fc_assert_ret_val(dest != nullptr, -1);
785 fc_assert_ret_val(src != nullptr, -1);
786 fc_assert_ret_val(0 < n, -1);
787
788 if (icu_buffer_uchars == 0) {
790 }
791
793
794 while (!enough_mem) {
796
797 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
798 * the buffers we were using */
802 } else {
804 }
805 }
806
807 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
808
810
811 dest[n - 1] = '\0';
812
813 return dlen;
814}
815
816/************************************************************************/
822size_t fc_strlcat(char *dest, const char *src, size_t n)
823{
824 size_t start;
825
826 start = strlen(dest);
827
828 fc_assert(start < n);
829
830 return fc_strlcpy(dest + start, src, n - start) + start;
831}
832
833/************************************************************************/
884/* This must be at least as big as PLAIN_FILE_BUF_SIZE in ioz.c */
885#define VSNP_BUF_SIZE (8096*1024)
886int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
887{
888#ifdef HAVE_WORKING_VSNPRINTF
889 int r;
890#endif
891
892 /* This may be overzealous, but I suspect any triggering of these to
893 * be bugs. */
894
895 fc_assert_ret_val(0 < n, -1);
896
897#ifdef HAVE_WORKING_VSNPRINTF
898 r = vsnprintf(str, n, format, ap);
899 str[n - 1] = 0;
900
901 return r;
902#else /* HAVE_WORKING_VSNPRINTF */
903 {
904 /* Don't use fc_malloc() or log_*() here, since they may call
905 fc_vsnprintf() if it fails. */
906 size_t len;
907
908 if (n > VSNP_BUF_SIZE) {
909 fprintf(stderr, "fc_vsnprintf() call with length " SIZE_T_PRINTF "."
910 "Maximum supported is %d", n, VSNP_BUF_SIZE);
912 }
913
915
916 if (vsnprintf_buf == nullptr) {
918
919 if (vsnprintf_buf == nullptr) {
920 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
921 "replacement.", VSNP_BUF_SIZE);
923
925 }
926 }
927
928 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
929
930#ifdef HAVE_VSNPRINTF
932#else
933 vsprintf(vsnprintf_buf, format, ap);
934#endif /* HAVE_VSNPRINTF */
935
937
938 if (len >= VSNP_BUF_SIZE - 1) {
939 fprintf(stderr, "Overflow in vsnprintf replacement!"
940 " (buffer size %d) aborting...\n", VSNP_BUF_SIZE);
941 abort();
942 }
943 if (n >= len + 1) {
945 } else {
946 memcpy(str, vsnprintf_buf, n - 1);
947 str[n - 1] = '\0';
948 }
949
951
952 return len;
953 }
954#endif /* HAVE_WORKING_VSNPRINTF */
955}
956
957/************************************************************************/
960int fc_snprintf(char *str, size_t n, const char *format, ...)
961{
962 int ret;
963 va_list ap;
964
965 va_start(ap, format);
966 ret = fc_vsnprintf(str, n, format, ap);
967 va_end(ap);
968
969 return ret;
970}
971
972/************************************************************************/
986int cat_snprintf(char *str, size_t n, const char *format, ...)
987{
988 size_t len;
989 int ret;
990 va_list ap;
991
992 fc_assert_ret_val(0 < n, -1);
993
994 len = strlen(str);
995 fc_assert_ret_val(len < n, -1);
996
997 va_start(ap, format);
998 ret = fc_vsnprintf(str+len, n-len, format, ap);
999 va_end(ap);
1000
1001 return (-1 == ret ? -1 : ret + len);
1002}
1003
1004/************************************************************************/
1007int fc_gethostname(char *buf, size_t len)
1008{
1009#ifdef HAVE_GETHOSTNAME
1010 return gethostname(buf, len);
1011#else
1012 return -1;
1013#endif
1014}
1015
1016#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
1017/****************************************************************************
1018 Support for console I/O in case FREECIV_SOCKET_ZERO_NOT_STDIN.
1019****************************************************************************/
1020
1021#define CONSOLE_BUF_SIZE 100
1022static char console_buf[CONSOLE_BUF_SIZE + 1];
1023
1024/***************************************************************************/
1025
1026#ifdef FREECIV_MSWINDOWS
1028
1029/************************************************************************/
1033{
1035 char *s;
1036
1037 if ((s = strchr(console_buf, '\n'))) {
1038 *s = '\0';
1039 }
1040 }
1041
1042 return 0;
1043}
1044#endif /* FREECIV_MSWINDOWS */
1045
1046/************************************************************************/
1049void fc_init_console(void)
1050{
1051#ifdef FREECIV_MSWINDOWS
1053 return;
1054 }
1055
1056 console_buf[0] = '\0';
1058 nullptr, 0, nullptr);
1059#else /* FREECIV_MSWINDOWS */
1060 static bool initialized = FALSE;
1061
1062 if (!initialized) {
1063 initialized = TRUE;
1064#ifdef HAVE_FILENO
1066#endif
1067 }
1068#endif /* FREECIV_MSWINDOWS */
1069}
1070
1071/************************************************************************/
1078char *fc_read_console(void)
1079{
1080#ifdef FREECIV_MSWINDOWS
1084
1085 return console_buf;
1086 }
1087
1088 return nullptr;
1089#else /* FREECIV_MSWINDOWS */
1090 if (!feof(stdin)) { /* input from server operator */
1091 static char *bufptr = console_buf;
1092
1093 /* fetch chars until \n, or run out of space in buffer */
1094 /* blocks if fc_nonblock() in fc_init_console() failed */
1095 while ((*bufptr = fgetc(stdin)) != EOF) {
1096 if (*bufptr == '\n') {
1097 *bufptr = '\0';
1098 }
1099 if (*bufptr == '\0') {
1101
1102 return console_buf;
1103 }
1104 if ((bufptr - console_buf) <= CONSOLE_BUF_SIZE) {
1105 bufptr++; /* prevent overrun */
1106 }
1107 }
1108 }
1109
1110 return nullptr;
1111#endif /* FREECIV_MSWINDOWS */
1112}
1113
1114#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
1115
1116/************************************************************************/
1121{
1122 struct stat tmp;
1123
1124 if (fc_stat(name, &tmp) == 0) {
1125 return S_ISREG(tmp.st_mode);
1126 } else {
1127 return write_access && errno == ENOENT;
1128 }
1129}
1130
1131/************************************************************************/
1136{
1137 size_t slen = (size_t)strlen(str);
1138 int num_lines = 0;
1139
1140 /* At top of this loop, s points to the rest of string,
1141 * either at start or after inserted newline: */
1142 top:
1143 if (str && *str != '\0' && slen > desired_len) {
1144 char *c;
1145
1146 num_lines++;
1147
1148 /* Check if there is already a newline: */
1149 for (c = str; c < str + desired_len; c++) {
1150 if (*c == '\n') {
1151 slen -= c + 1 - str;
1152 str = c + 1;
1153 goto top;
1154 }
1155 }
1156
1157 /* Find space and break: */
1158 for (c = str + desired_len; c > str; c--) {
1159 if (fc_isspace(*c)) {
1160 *c = '\n';
1161 slen -= c + 1 - str;
1162 str = c + 1;
1163 goto top;
1164 }
1165 }
1166
1167 /* Couldn't find a good break; settle for a bad one... */
1168 for (c = str + desired_len + 1; *c != '\0'; c++) {
1169 if (fc_isspace(*c)) {
1170 *c = '\n';
1171 slen -= c + 1 - str;
1172 str = c + 1;
1173 goto top;
1174 }
1175 }
1176 }
1177
1178 return num_lines;
1179}
1180
1181/****************************************************************************
1182 Character function wrappers
1183
1184 These functions are wrappers for the libc character class functions,
1185 without any locale-dependent behavior. The character functions work as
1186 documented for ASCII. Bytes outside of the ASCII set will not be reported
1187 to belong to any character class, and will be left unchanged by
1188 transformations. This behavior is safe but not strictly correct
1189 forsingle-byte 8-bit- or UTF-8 encoded text; in UTF-8, any byte that is
1190 part of a multibyte sequence is non-ASCII.
1191****************************************************************************/
1192
1193/************************************************************************/
1196bool fc_isalnum(char c)
1197{
1198 if (128 <= (unsigned char) c) {
1199 return FALSE;
1200 }
1201 return isalnum((int) ((unsigned char) c)) != 0;
1202}
1203
1204/************************************************************************/
1207bool fc_isalpha(char c)
1208{
1209 if (128 <= (unsigned char) c) {
1210 return FALSE;
1211 }
1212 return isalpha((int) ((unsigned char) c)) != 0;
1213}
1214
1215/************************************************************************/
1218bool fc_isdigit(char c)
1219{
1220 if (128 <= (unsigned char) c) {
1221 return FALSE;
1222 }
1223 return isdigit((int) ((unsigned char) c)) != 0;
1224}
1225
1226/************************************************************************/
1229bool fc_isprint(char c)
1230{
1231 if (128 <= (unsigned char) c) {
1232 return FALSE;
1233 }
1234 return isprint((int) ((unsigned char) c)) != 0;
1235}
1236
1237/************************************************************************/
1240bool fc_isspace(char c)
1241{
1242 if (128 <= (unsigned char) c) {
1243 return FALSE;
1244 }
1245 return isspace((int) ((unsigned char) c)) != 0;
1246}
1247
1248/************************************************************************/
1251bool fc_isupper(char c)
1252{
1253 if (128 <= (unsigned char) c) {
1254 return FALSE;
1255 }
1256 return isupper((int) ((unsigned char) c)) != 0;
1257}
1258
1259/************************************************************************/
1262char fc_toupper(char c)
1263{
1264 if (128 <= (unsigned char) c) {
1265 return c;
1266 }
1267 return (char) toupper((int) ((unsigned char) c));
1268}
1269
1270/************************************************************************/
1273char fc_tolower(char c)
1274{
1275 if (128 <= (unsigned char) c) {
1276 return c;
1277 }
1278 return (char) tolower((int) ((unsigned char) c));
1279}
1280
1281/************************************************************************/
1287const char *fc_basename(const char *path)
1288{
1289 static char buf[2048];
1290
1291 /* Copy const parameter string to buffer that basename() can
1292 * modify */
1293 fc_strlcpy(buf, path, sizeof(buf));
1294
1295 return basename(buf);
1296}
1297
1298/************************************************************************/
1301struct tm *fc_localtime(const time_t *timep, struct tm *result)
1302{
1303#ifdef HAVE_LOCALTIME_R
1304 return localtime_r(timep, result);
1305#else /* HAVE_LOCALTIME_R */
1307 memcpy(result, localtime(timep), sizeof(struct tm));
1309
1310 return result;
1311#endif /* HAVE_LOCALTIME_R */
1312}
1313
1314/************************************************************************/
1317int fc_at_quick_exit(void (*func)(void))
1318{
1319#ifdef HAVE_AT_QUICK_EXIT
1320 return at_quick_exit(func);
1321#else /* HAVE_AT_QUICK_EXIT */
1322 return -1;
1323#endif /* HAVE_AT_QUICK_EXIT */
1324}
1325
1326/************************************************************************/
1330{
1332
1333#ifndef HAVE_WORKING_VSNPRINTF
1335#endif /* HAVE_WORKING_VSNPRINTF */
1336
1337#ifndef HAVE_LOCALTIME_R
1339#endif /* HAVE_LOCALTIME_R */
1340
1342}
1343
1344/************************************************************************/
1348{
1350
1351#ifndef HAVE_WORKING_VSNPRINTF
1352 if (vsnprintf_buf != nullptr) {
1354 vsnprintf_buf = nullptr;
1355 }
1357#endif /* HAVE_WORKING_VSNPRINTF */
1358
1359#ifndef HAVE_LOCALTIME_R
1361#endif /* HAVE_LOCALTIME_R */
1362
1364}
1365
1366/************************************************************************/
1370{
1371 return support_initialized;
1372}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
char * incite_cost
Definition comments.c:76
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)
void fc_mutex_init(fc_mutex *mutex)
void fc_mutex_release(fc_mutex *mutex)
void fc_mutex_destroy(fc_mutex *mutex)
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:127
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
bool fc_isalpha(char c)
Definition support.c:1207
int fc_gethostname(char *buf, size_t len)
Definition support.c:1007
bool fc_isprint(char c)
Definition support.c:1229
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
static bool support_initialized
Definition support.c:111
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:294
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
void fc_usleep(unsigned long usec)
Definition support.c:639
void fc_support_init(void)
Definition support.c:1329
bool fc_isspace(char c)
Definition support.c:1240
const char * fc_strerror(fc_errno err)
Definition support.c:609
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:822
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:437
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:720
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1301
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:886
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:505
static void fc_strAPI_free(void)
Definition support.c:171
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1135
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:592
void fc_support_free(void)
Definition support.c:1347
void remove_escapes(const char *str, bool full_escapes, char *buf, size_t buf_len)
Definition support.c:330
bool fc_isdigit(char c)
Definition support.c:1218
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:471
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:574
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1120
bool fc_isalnum(char c)
Definition support.c:1196
bool fc_isupper(char c)
Definition support.c:1251
const char * fc_basename(const char *path)
Definition support.c:1287
static void icu_buffers_initial(void)
Definition support.c:130
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:377
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:356
char fc_tolower(char c)
Definition support.c:1273
static void icu_buffers_increase(void)
Definition support.c:146
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1317
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:485
int fc_remove(const char *filename)
Definition support.c:555
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:681
static UChar * icu_buffer2
Definition support.c:115
bool are_support_services_available(void)
Definition support.c:1369
char fc_toupper(char c)
Definition support.c:1262
#define VSNP_BUF_SIZE
Definition support.c:885
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define fc__fallthrough
Definition support.h:119
int fc_errno
Definition support.h:140