Freeciv-3.3: /fast/freeciv/nightly/main/utility/support.c Source File

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
111 static bool support_initialized = FALSE;
112
113 static int icu_buffer_uchars = 0;
114 static UChar *icu_buffer1 = nullptr;
115 static UChar *icu_buffer2 = nullptr;
116 fc_mutex icu_buffer_mutex;
117
118#ifndef HAVE_WORKING_VSNPRINTF
119 static char *vsnprintf_buf = nullptr;
120 static fc_mutex vsnprintf_mutex;
121#endif /* HAVE_WORKING_VSNPRINTF */
122
123#ifndef HAVE_LOCALTIME_R
124 static fc_mutex localtime_mutex;
125#endif /* HAVE_LOCALTIME_R */
126
127/************************************************************************/
130 static 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 */
138 icu_buffer1[icu_buffer_uchars] = 0;
139 icu_buffer2[icu_buffer_uchars] = 0;
140 }
141}
142
143/************************************************************************/
146 static void icu_buffers_increase(void)
147{
148 icu_buffer_uchars *= 1.5;
149 icu_buffer1 = fc_realloc(icu_buffer1, (icu_buffer_uchars + 1) * sizeof(UChar));
150 icu_buffer2 = fc_realloc(icu_buffer2, (icu_buffer_uchars + 1) * sizeof(UChar));
151
152 /* Make sure there's zero after the buffer published with cmp_buffer_uchars */
153 icu_buffer1[icu_buffer_uchars] = 0;
154 icu_buffer2[icu_buffer_uchars] = 0;
155}
156
157/************************************************************************/
160 static void fc_strAPI_init(void)
161{
162 if (icu_buffer_uchars == 0) {
163 fc_mutex_init(&icu_buffer_mutex);
164 icu_buffers_initial();
165 }
166}
167
168/************************************************************************/
171 static void fc_strAPI_free(void)
172{
173 if (icu_buffer1 != nullptr) {
174 free(icu_buffer1);
175 icu_buffer1 = nullptr;
176 free(icu_buffer2);
177 icu_buffer2 = nullptr;
178 icu_buffer_uchars = 0;
179 }
180 fc_mutex_destroy(&icu_buffer_mutex);
181}
182
183/************************************************************************/
186 int fc_strcasecmp(const char *str0, const char *str1)
187{
188 UErrorCode err_code = U_ZERO_ERROR;
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) {
202 fc_strAPI_init();
203 }
204
205 fc_mutex_allocate(&icu_buffer_mutex);
206
207 while (!enough_mem) {
208 UErrorCode err_code0 = U_ZERO_ERROR;
209 UErrorCode err_code1 = U_ZERO_ERROR;
210
211 u_strFromUTF8Lenient(icu_buffer1, icu_buffer_uchars, &len0, str0, -1, &err_code0);
212 u_strFromUTF8Lenient(icu_buffer2, icu_buffer_uchars, &len1, str1, -1, &err_code1);
213
214 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
215 * the buffers we were using */
216 if (err_code0 == U_BUFFER_OVERFLOW_ERROR || err_code1 == U_BUFFER_OVERFLOW_ERROR) {
217 icu_buffers_increase();
218 } else {
219 enough_mem = TRUE;
220 }
221 }
222
223 ret = u_strCaseCompare(icu_buffer1, -1, icu_buffer2, -1,
224 0, &err_code);
225
226 fc_mutex_release(&icu_buffer_mutex);
227
228 return ret;
229}
230
231/************************************************************************/
235 int fc_strncasecmp(const char *str0, const char *str1, size_t n)
236{
237 UErrorCode err_code = U_ZERO_ERROR;
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) {
251 fc_strAPI_init();
252 }
253
254 fc_mutex_allocate(&icu_buffer_mutex);
255
256 while (!enough_mem) {
257 UErrorCode err_code0 = U_ZERO_ERROR;
258 UErrorCode err_code1 = U_ZERO_ERROR;
259
260 u_strFromUTF8Lenient(icu_buffer1, icu_buffer_uchars, &len0, str0, -1, &err_code0);
261 u_strFromUTF8Lenient(icu_buffer2, icu_buffer_uchars, &len1, str1, -1, &err_code1);
262
263 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
264 * the buffers we were using */
265 if (err_code0 == U_BUFFER_OVERFLOW_ERROR || err_code1 == U_BUFFER_OVERFLOW_ERROR) {
266 icu_buffers_increase();
267 } else {
268 enough_mem = TRUE;
269 }
270 }
271
272 if (len0 > n) {
273 len0 = n;
274 }
275 if (len1 > n) {
276 len1 = n;
277 }
278
279 ret = u_strCaseCompare(icu_buffer1, len0, icu_buffer2, len1,
280 0, &err_code);
281
282 fc_mutex_release(&icu_buffer_mutex);
283
284 return ret;
285}
286
287/************************************************************************/
294 void 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
312 fc__fallthrough;
313 default:
314 *dest++ = *str++;
315 break;
316 }
317 }
318 *dest = 0;
319}
320
321/************************************************************************/
330 void 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/************************************************************************/
356 size_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/************************************************************************/
377 int 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/************************************************************************/
437 char *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 }
452 haystacks = strlen(haystack);
453 needles = strlen(needle);
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/************************************************************************/
471 int 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/************************************************************************/
485 int 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/************************************************************************/
505 FILE *fc_fopen(const char *filename, const char *opentype)
506{
507 FILE *result;
508
509#ifdef FREECIV_MSWINDOWS
510 char *real_filename = internal_to_local_string_malloc(filename);
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
524 free(real_filename);
525#endif /* FREECIV_MSWINDOWS */
526
527 return result;
528}
529
530/************************************************************************/
534#ifdef FREECIV_HAVE_LIBZ
535 gzFile fc_gzopen(const char *filename, const char *opentype)
536{
537#ifdef FREECIV_MSWINDOWS
538 gzFile result;
539 char *filename_in_local_encoding =
540 internal_to_local_string_malloc(filename);
541
542 result = gzopen(filename_in_local_encoding, opentype);
543 free(filename_in_local_encoding);
544 return result;
545#else /* FREECIV_MSWINDOWS */
546 return gzopen(filename, opentype);
547#endif /* FREECIV_MSWINDOWS */
548}
549#endif /* FREECIV_HAVE_LIBZ */
550
551/************************************************************************/
555 int fc_remove(const char *filename)
556{
557#ifdef FREECIV_MSWINDOWS
558 int result;
559 char *filename_in_local_encoding =
560 internal_to_local_string_malloc(filename);
561
562 result = remove(filename_in_local_encoding);
563 free(filename_in_local_encoding);
564 return result;
565#else /* FREECIV_MSWINDOWS */
566 return remove(filename);
567#endif /* FREECIV_MSWINDOWS */
568}
569
570/************************************************************************/
574 int fc_stat(const char *filename, struct stat *buf)
575{
576#ifdef FREECIV_MSWINDOWS
577 int result;
578 char *filename_in_local_encoding =
579 internal_to_local_string_malloc(filename);
580
581 result = stat(filename_in_local_encoding, buf);
582 free(filename_in_local_encoding);
583 return result;
584#else /* FREECIV_MSWINDOWS */
585 return stat(filename, buf);
586#endif /* FREECIV_MSWINDOWS */
587}
588
589/************************************************************************/
592 fc_errno fc_get_errno(void)
593{
594#ifdef FREECIV_MSWINDOWS
595 return GetLastError();
596#else /* FREECIV_MSWINDOWS */
597 return errno;
598#endif /* FREECIV_MSWINDOWS */
599}
600
601/************************************************************************/
609 const char *fc_strerror(fc_errno err)
610{
611#ifdef FREECIV_MSWINDOWS
612 static char buf[256];
613
614 if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
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
624 return local_to_internal_string_buffer(strerror(err),
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/************************************************************************/
639 void 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 */
663 fc_timeval tv;
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/************************************************************************/
681 char *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;
698 str = fc_realloc(str, 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 */
707 fc_assert_ret_val_msg(success, nullptr,
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/************************************************************************/
720 bool 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
732 len_search = strlen(search);
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/************************************************************************/
777 size_t fc_strlcpy(char *dest, const char *src, size_t n)
778{
779 bool enough_mem = FALSE;
780 int slen;
781 int dlen;
782 UErrorCode err_code = U_ZERO_ERROR;
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) {
789 fc_strAPI_init();
790 }
791
792 fc_mutex_allocate(&icu_buffer_mutex);
793
794 while (!enough_mem) {
795 u_strFromUTF8(icu_buffer1, icu_buffer_uchars, &slen, src, -1, &err_code);
796
797 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
798 * the buffers we were using */
799 if (err_code == U_BUFFER_OVERFLOW_ERROR) {
800 icu_buffers_increase();
801 err_code = U_ZERO_ERROR;
802 } else {
803 enough_mem = TRUE;
804 }
805 }
806
807 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
808
809 fc_mutex_release(&icu_buffer_mutex);
810
811 dest[n - 1] = '\0';
812
813 return dlen;
814}
815
816/************************************************************************/
822 size_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)
886 int 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);
911 exit(EXIT_FAILURE);
912 }
913
914 fc_mutex_allocate(&vsnprintf_mutex);
915
916 if (vsnprintf_buf == nullptr) {
917 vsnprintf_buf = malloc(VSNP_BUF_SIZE);
918
919 if (vsnprintf_buf == nullptr) {
920 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
921 "replacement.", VSNP_BUF_SIZE);
922 fc_mutex_release(&vsnprintf_mutex);
923
924 exit(EXIT_FAILURE);
925 }
926 }
927
928 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
929
930#ifdef HAVE_VSNPRINTF
931 vsnprintf(vsnprintf_buf, VSNP_BUF_SIZE, format, ap);
932#else
933 vsprintf(vsnprintf_buf, format, ap);
934#endif /* HAVE_VSNPRINTF */
935
936 len = strlen(vsnprintf_buf);
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) {
944 memcpy(str, vsnprintf_buf, len + 1);
945 } else {
946 memcpy(str, vsnprintf_buf, n - 1);
947 str[n - 1] = '\0';
948 }
949
950 fc_mutex_release(&vsnprintf_mutex);
951
952 return len;
953 }
954#endif /* HAVE_WORKING_VSNPRINTF */
955}
956
957/************************************************************************/
960 int 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/************************************************************************/
986 int 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/************************************************************************/
1007 int 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
1027static HANDLE console_thread = INVALID_HANDLE_VALUE;
1028
1029/************************************************************************/
1032static DWORD WINAPI windows_console_thread(LPVOID arg)
1033{
1034 if (fgets(console_buf, CONSOLE_BUF_SIZE, stdin)) {
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
1052 if (console_thread != INVALID_HANDLE_VALUE) {
1053 return;
1054 }
1055
1056 console_buf[0] = '\0';
1057 console_thread = (HANDLE) CreateThread(nullptr, 0, windows_console_thread,
1058 nullptr, 0, nullptr);
1059#else /* FREECIV_MSWINDOWS */
1060 static bool initialized = FALSE;
1061
1062 if (!initialized) {
1063 initialized = TRUE;
1064#ifdef HAVE_FILENO
1065 fc_nonblock(fileno(stdin));
1066#endif
1067 }
1068#endif /* FREECIV_MSWINDOWS */
1069}
1070
1071/************************************************************************/
1078char *fc_read_console(void)
1079{
1080#ifdef FREECIV_MSWINDOWS
1081 if (WaitForSingleObject(console_thread, 0) == WAIT_OBJECT_0) {
1082 CloseHandle(console_thread);
1083 console_thread = INVALID_HANDLE_VALUE;
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') {
1100 bufptr = console_buf;
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/************************************************************************/
1120 bool is_reg_file_for_access(const char *name, bool write_access)
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/************************************************************************/
1135 int fc_break_lines(char *str, size_t desired_len)
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/************************************************************************/
1196 bool 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/************************************************************************/
1207 bool 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/************************************************************************/
1218 bool 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/************************************************************************/
1229 bool 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/************************************************************************/
1240 bool 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/************************************************************************/
1251 bool 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/************************************************************************/
1262 char 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/************************************************************************/
1273 char 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/************************************************************************/
1287 const 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/************************************************************************/
1301 struct 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 */
1306 fc_mutex_allocate(&localtime_mutex);
1307 memcpy(result, localtime(timep), sizeof(struct tm));
1308 fc_mutex_release(&localtime_mutex);
1309
1310 return result;
1311#endif /* HAVE_LOCALTIME_R */
1312}
1313
1314/************************************************************************/
1317 int 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/************************************************************************/
1329 void fc_support_init(void)
1330{
1331 fc_strAPI_init();
1332
1333#ifndef HAVE_WORKING_VSNPRINTF
1334 fc_mutex_init(&vsnprintf_mutex);
1335#endif /* HAVE_WORKING_VSNPRINTF */
1336
1337#ifndef HAVE_LOCALTIME_R
1338 fc_mutex_init(&localtime_mutex);
1339#endif /* HAVE_LOCALTIME_R */
1340
1341 support_initialized = TRUE;
1342}
1343
1344/************************************************************************/
1347 void fc_support_free(void)
1348{
1349 support_initialized = FALSE;
1350
1351#ifndef HAVE_WORKING_VSNPRINTF
1352 if (vsnprintf_buf != nullptr) {
1353 free(vsnprintf_buf);
1354 vsnprintf_buf = nullptr;
1355 }
1356 fc_mutex_destroy(&vsnprintf_mutex);
1357#endif /* HAVE_WORKING_VSNPRINTF */
1358
1359#ifndef HAVE_LOCALTIME_R
1360 fc_mutex_destroy(&localtime_mutex);
1361#endif /* HAVE_LOCALTIME_R */
1362
1363 fc_strAPI_free();
1364}
1365
1366/************************************************************************/
1369 bool are_support_services_available(void)
1370{
1371 return support_initialized;
1372}
str
#define str
Definition astring.c:76
n
#define n
Definition astring.c:77
incite_cost
char * incite_cost
Definition comments.c:74
initialized
static bool initialized
Definition effects.c:42
fc_prehdrs.h
fciconv.h
internal_to_local_string_malloc
char * internal_to_local_string_malloc(const char *text)
local_to_internal_string_buffer
char * local_to_internal_string_buffer(const char *text, char *buf, size_t bufsz)
fcintl.h
_
#define _(String)
Definition fcintl.h:67
fcthread.h
fc_mutex_allocate
void fc_mutex_allocate(fc_mutex *mutex)
fc_mutex_init
void fc_mutex_init(fc_mutex *mutex)
fc_mutex_release
void fc_mutex_release(fc_mutex *mutex)
fc_mutex_destroy
void fc_mutex_destroy(fc_mutex *mutex)
name
const char * name
Definition inputfile.c:127
func
get_token_fn_t func
Definition inputfile.c:128
log.h
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
fc_assert_ret_val_msg
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
mem.h
fc_realloc
#define fc_realloc(ptr, sz)
Definition mem.h:36
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
fc_nonblock
void fc_nonblock(int sockfd)
Definition netintf.c:227
fc_select
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
Definition netintf.c:125
netintf.h
fc_timeval
struct timeval fc_timeval
Definition netintf.h:90
len
int len
Definition packhand.c:127
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_isalpha
bool fc_isalpha(char c)
Definition support.c:1207
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1007
fc_isprint
bool fc_isprint(char c)
Definition support.c:1229
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
support_initialized
static bool support_initialized
Definition support.c:111
make_escapes
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:294
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
fc_usleep
void fc_usleep(unsigned long usec)
Definition support.c:639
fc_support_init
void fc_support_init(void)
Definition support.c:1329
fc_isspace
bool fc_isspace(char c)
Definition support.c:1240
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:609
fc_strlcat
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:822
fc_strcasestr
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:437
fc_strrep
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:720
fc_localtime
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1301
cat_snprintf
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
fc_vsnprintf
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:886
fc_fopen
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:505
fc_strAPI_free
static void fc_strAPI_free(void)
Definition support.c:171
fc_break_lines
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1135
localtime_mutex
static fc_mutex localtime_mutex
Definition support.c:124
icu_buffer1
static UChar * icu_buffer1
Definition support.c:114
icu_buffer_mutex
fc_mutex icu_buffer_mutex
Definition support.c:116
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:592
fc_support_free
void fc_support_free(void)
Definition support.c:1347
remove_escapes
void remove_escapes(const char *str, bool full_escapes, char *buf, size_t buf_len)
Definition support.c:330
fc_isdigit
bool fc_isdigit(char c)
Definition support.c:1218
fc_strcoll
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:471
fc_stat
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:574
is_reg_file_for_access
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1120
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1196
fc_isupper
bool fc_isupper(char c)
Definition support.c:1251
fc_basename
const char * fc_basename(const char *path)
Definition support.c:1287
icu_buffers_initial
static void icu_buffers_initial(void)
Definition support.c:130
vsnprintf_buf
static char * vsnprintf_buf
Definition support.c:119
icu_buffer_uchars
static int icu_buffer_uchars
Definition support.c:113
fc_strncasequotecmp
int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
Definition support.c:377
vsnprintf_mutex
static fc_mutex vsnprintf_mutex
Definition support.c:120
fc_strAPI_init
static void fc_strAPI_init(void)
Definition support.c:160
effectivestrlenquote
size_t effectivestrlenquote(const char *str)
Definition support.c:356
fc_tolower
char fc_tolower(char c)
Definition support.c:1273
icu_buffers_increase
static void icu_buffers_increase(void)
Definition support.c:146
fc_at_quick_exit
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1317
fc_stricoll
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:485
fc_remove
int fc_remove(const char *filename)
Definition support.c:555
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
fc_strrep_resize
char * fc_strrep_resize(char *str, size_t *len, const char *search, const char *replace)
Definition support.c:681
icu_buffer2
static UChar * icu_buffer2
Definition support.c:115
are_support_services_available
bool are_support_services_available(void)
Definition support.c:1369
fc_toupper
char fc_toupper(char c)
Definition support.c:1262
VSNP_BUF_SIZE
#define VSNP_BUF_SIZE
Definition support.c:885
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc__fallthrough
#define fc__fallthrough
Definition support.h:119
fc_errno
int fc_errno
Definition support.h:140