Freeciv-3.2: /fast/freeciv/nightly/S3_2/utility/support.c Source File

Freeciv-3.2

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 GENERATING_MAC
56#include <events.h> /* for WaitNextEvent() */
57#endif
58#ifdef HAVE_FCNTL_H
59#include <fcntl.h>
60#endif
61#ifdef HAVE_SYS_IOCTL_H
62#include <sys/ioctl.h>
63#endif
64#ifdef HAVE_SYS_SELECT_H
65#include <sys/select.h>
66#endif
67#ifdef HAVE_SYS_TIME_H
68#include <sys/time.h>
69#endif
70#ifdef FREECIV_HAVE_SYS_TYPES_H
71#include <sys/types.h>
72#endif
73#ifdef HAVE_UNISTD_H
74#include <unistd.h> /* usleep, fcntl, gethostname */
75#endif
76#ifdef HAVE_TIME_H
77#include <time.h> /* nanosleep */
78#endif
79#ifdef HAVE_SYS_UTSNAME_H
80#include <sys/utsname.h>
81#endif
82#ifdef FREECIV_HAVE_LIBZ
83#include <zlib.h>
84#endif
85#ifdef FREECIV_MSWINDOWS
86#include <process.h>
87#include <windows.h>
88#endif /* FREECIV_MSWINDOWS */
89#ifdef HAVE_STRINGS_H
90# include <strings.h>
91#endif
92#ifdef HAVE_LIBGEN_H
93/* POSIX version of basename() */
94# include <libgen.h>
95#endif
96
97#ifdef FREECIV_HAVE_LIBZ
98#include <zlib.h>
99#endif
100
101/* ICU */
102#include "unicode/ustring.h"
103
104/* utility */
105#include "fciconv.h"
106#include "fcintl.h"
107#include "fcthread.h"
108#include "log.h"
109#include "mem.h"
110#include "netintf.h"
111
112#include "support.h"
113
114 static bool support_initialized = FALSE;
115
116 static int icu_buffer_uchars = 0;
117 static UChar *icu_buffer1 = NULL;
118 static UChar *icu_buffer2 = NULL;
119 fc_mutex icu_buffer_mutex;
120
121#ifndef HAVE_WORKING_VSNPRINTF
122 static char *vsnprintf_buf = NULL;
123 static fc_mutex vsnprintf_mutex;
124#endif /* HAVE_WORKING_VSNPRINTF */
125
126#ifndef HAVE_LOCALTIME_R
127 static fc_mutex localtime_mutex;
128#endif /* HAVE_LOCALTIME_R */
129
130/************************************************************************/
133 static void icu_buffers_initial(void)
134{
135 if (icu_buffer1 == NULL) {
136 icu_buffer_uchars = 1024;
137 icu_buffer1 = fc_malloc((icu_buffer_uchars + 1) * sizeof(UChar));
138 icu_buffer2 = fc_malloc((icu_buffer_uchars + 1) * sizeof(UChar));
139
140 /* Make sure there's zero after the buffer published with cmp_buffer_uchars */
141 icu_buffer1[icu_buffer_uchars] = 0;
142 icu_buffer2[icu_buffer_uchars] = 0;
143 }
144}
145
146/************************************************************************/
149 static void icu_buffers_increase(void)
150{
151 icu_buffer_uchars *= 1.5;
152 icu_buffer1 = fc_realloc(icu_buffer1, (icu_buffer_uchars + 1) * sizeof(UChar));
153 icu_buffer2 = fc_realloc(icu_buffer2, (icu_buffer_uchars + 1) * sizeof(UChar));
154
155 /* Make sure there's zero after the buffer published with cmp_buffer_uchars */
156 icu_buffer1[icu_buffer_uchars] = 0;
157 icu_buffer2[icu_buffer_uchars] = 0;
158}
159
160/************************************************************************/
163 static void fc_strAPI_init(void)
164{
165 if (icu_buffer_uchars == 0) {
166 fc_mutex_init(&icu_buffer_mutex);
167 icu_buffers_initial();
168 }
169}
170
171/************************************************************************/
174 static void fc_strAPI_free(void)
175{
176 if (icu_buffer1 != NULL) {
177 free(icu_buffer1);
178 icu_buffer1 = NULL;
179 free(icu_buffer2);
180 icu_buffer2 = NULL;
181 icu_buffer_uchars = 0;
182 }
183 fc_mutex_destroy(&icu_buffer_mutex);
184}
185
186/************************************************************************/
189 int fc_strcasecmp(const char *str0, const char *str1)
190{
191 UErrorCode err_code = U_ZERO_ERROR;
192 int len0;
193 int len1;
194 bool enough_mem = FALSE;
195 int ret;
196
197 if (str0 == NULL) {
198 return -1;
199 }
200 if (str1 == NULL) {
201 return 1;
202 }
203
204 if (icu_buffer_uchars == 0) {
205 fc_strAPI_init();
206 }
207
208 fc_mutex_allocate(&icu_buffer_mutex);
209
210 while (!enough_mem) {
211 UErrorCode err_code0 = U_ZERO_ERROR;
212 UErrorCode err_code1 = U_ZERO_ERROR;
213
214 u_strFromUTF8Lenient(icu_buffer1, icu_buffer_uchars, &len0, str0, -1, &err_code0);
215 u_strFromUTF8Lenient(icu_buffer2, icu_buffer_uchars, &len1, str1, -1, &err_code1);
216
217 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
218 * the buffers we were using */
219 if (err_code0 == U_BUFFER_OVERFLOW_ERROR || err_code1 == U_BUFFER_OVERFLOW_ERROR) {
220 icu_buffers_increase();
221 } else {
222 enough_mem = TRUE;
223 }
224 }
225
226 ret = u_strCaseCompare(icu_buffer1, -1, icu_buffer2, -1,
227 0, &err_code);
228
229 fc_mutex_release(&icu_buffer_mutex);
230
231 return ret;
232}
233
234/************************************************************************/
238 int fc_strncasecmp(const char *str0, const char *str1, size_t n)
239{
240 UErrorCode err_code = U_ZERO_ERROR;
241 int len0;
242 int len1;
243 bool enough_mem = FALSE;
244 int ret;
245
246 if (str0 == NULL) {
247 return -1;
248 }
249 if (str1 == NULL) {
250 return 1;
251 }
252
253 if (icu_buffer_uchars == 0) {
254 fc_strAPI_init();
255 }
256
257 fc_mutex_allocate(&icu_buffer_mutex);
258
259 while (!enough_mem) {
260 UErrorCode err_code0 = U_ZERO_ERROR;
261 UErrorCode err_code1 = U_ZERO_ERROR;
262
263 u_strFromUTF8Lenient(icu_buffer1, icu_buffer_uchars, &len0, str0, -1, &err_code0);
264 u_strFromUTF8Lenient(icu_buffer2, icu_buffer_uchars, &len1, str1, -1, &err_code1);
265
266 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
267 * the buffers we were using */
268 if (err_code0 == U_BUFFER_OVERFLOW_ERROR || err_code1 == U_BUFFER_OVERFLOW_ERROR) {
269 icu_buffers_increase();
270 } else {
271 enough_mem = TRUE;
272 }
273 }
274
275 if (len0 > n) {
276 len0 = n;
277 }
278 if (len1 > n) {
279 len1 = n;
280 }
281
282 ret = u_strCaseCompare(icu_buffer1, len0, icu_buffer2, len1,
283 0, &err_code);
284
285 fc_mutex_release(&icu_buffer_mutex);
286
287 return ret;
288}
289
290/************************************************************************/
297 void make_escapes(const char *str, char *buf, size_t buf_len)
298{
299 char *dest = buf;
300 /* Sometimes we insert 2 characters at once ('\n' -> "\\n"), so keep
301 * place for '\0' and an extra character. */
302 const char *const max = buf + buf_len - 2;
303
304 while (*str != '\0' && dest < max) {
305 switch (*str) {
306 case '\n':
307 *dest++ = '\\';
308 *dest++ = 'n';
309 str++;
310 break;
311 case '\\':
312 case '\"':
313 *dest++ = '\\';
314
315 fc__fallthrough;
316 default:
317 *dest++ = *str++;
318 break;
319 }
320 }
321 *dest = 0;
322}
323
324/************************************************************************/
333 void remove_escapes(const char *str, bool full_escapes,
334 char *buf, size_t buf_len)
335{
336 char *dest = buf;
337 const char *const max = buf + buf_len - 1;
338
339 while (*str != '\0' && dest < max) {
340 if (*str == '\\' && *(str + 1) == '\n') {
341 /* Escape followed by newline. Skip both */
342 str += 2;
343 } else if (full_escapes && *str == '\\') {
344 str++;
345 if (*str == 'n') {
346 *dest++ = '\n';
347 str++;
348 }
349 } else {
350 *dest++ = *str++;
351 }
352 }
353 *dest = '\0';
354}
355
356/************************************************************************/
359 size_t effectivestrlenquote(const char *str)
360{
361 int len;
362
363 if (!str) {
364 return 0;
365 }
366
367 len = strlen(str);
368
369 if (str[0] == '"' && str[len-1] == '"') {
370 return len - 2;
371 }
372
373 return len;
374}
375
376/************************************************************************/
380 int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
381{
382 size_t i;
383 size_t len0;
384 size_t len1;
385 size_t cmplen;
386
387 if (str0 == NULL) {
388 return -1;
389 }
390 if (str1 == NULL) {
391 return 1;
392 }
393
394 len0 = strlen(str0); /* TODO: We iterate string once already here, */
395 len1 = strlen(str1); /* could iterate only once */
396
397 if (str0[0] == '"') {
398 if (str0[len0 - 1] == '"') {
399 /* Surrounded with quotes */
400 str0++;
401 len0 -= 2;
402 }
403 }
404
405 if (str1[0] == '"') {
406 if (str1[len1 - 1] == '"') {
407 /* Surrounded with quotes */
408 str1++;
409 len1 -= 2;
410 }
411 }
412
413 if (len0 < n || len1 < n) {
414 /* One of the strings is shorter than what should be compared... */
415 if (len0 != len1) {
416 /* ...and another is longer than it. */
417 return len0 - len1;
418 }
419
420 cmplen = len0; /* This avoids comparing ending quote */
421 } else {
422 cmplen = n;
423 }
424
425 for (i = 0; i < cmplen ; i++, str0++, str1++) {
426 if (fc_tolower(*str0) != fc_tolower(*str1)) {
427 return ((int) (unsigned char) fc_tolower(*str0))
428 - ((int) (unsigned char) fc_tolower(*str1));
429 }
430 }
431
432 /* All characters compared and all matched */
433 return 0;
434}
435
436/************************************************************************/
440 char *fc_strcasestr(const char *haystack, const char *needle)
441{
442#ifdef HAVE_STRCASESTR
443 return strcasestr(haystack, needle);
444#else
445 size_t haystacks;
446 size_t needles;
447 const char *p;
448
449 if (NULL == needle || '\0' == *needle) {
450 return (char *)haystack;
451 }
452 if (NULL == haystack || '\0' == *haystack) {
453 return NULL;
454 }
455 haystacks = strlen(haystack);
456 needles = strlen(needle);
457 if (haystacks < needles) {
458 return NULL;
459 }
460
461 for (p = haystack; p <= &haystack[haystacks - needles]; p++) {
462 if (0 == fc_strncasecmp(p, needle, needles)) {
463 return (char *)p;
464 }
465 }
466 return NULL;
467#endif /* HAVE_STRCASESTR */
468}
469
470/************************************************************************/
473 int fc_strcoll(const char *str0, const char *str1)
474{
475#if defined(ENABLE_NLS) && defined(HAVE_STRCOLL)
476 return strcoll(str0, str1);
477#elif defined(ENABLE_NLS) && defined(HAVE__STRCOLL)
478 return _strcoll(str0, str1);
479#else
480 return strcmp(str0, str1);
481#endif
482}
483
484/************************************************************************/
487 int fc_stricoll(const char *str0, const char *str1)
488{
489 /* We prefer _stricoll() over stricoll() since
490 * latter is not declared in MinGW headers causing compiler
491 * warning, preventing -Werror builds. */
492#if defined(ENABLE_NLS) && defined(HAVE__STRICOLL)
493 return _stricoll(str0, str1);
494#elif defined(ENABLE_NLS) && defined(HAVE_STRICOLL)
495 return stricoll(str0, str1);
496#elif defined(ENABLE_NLS) && defined(HAVE_STRCASECOLL)
497 return strcasecoll(str0, str1);
498#else
499 return fc_strcasecmp(str0, str1);
500#endif
501}
502
503/************************************************************************/
507 FILE *fc_fopen(const char *filename, const char *opentype)
508{
509 FILE *result;
510
511#ifdef FREECIV_MSWINDOWS
512 char *real_filename = internal_to_local_string_malloc(filename);
513#else /* FREECIV_MSWINDOWS */
514 const char *real_filename = filename;
515#endif /* FREECIV_MSWINDOWS */
516
517#ifdef HAVE_FOPEN_S
518 if (fopen_s(&result, real_filename, opentype) != 0) {
519 result = NULL;
520 }
521#else /* HAVE_FOPEN_S */
522 result = fopen(real_filename, opentype);
523#endif /* HAVE_FOPEN_S */
524
525#ifdef FREECIV_MSWINDOWS
526 free(real_filename);
527#endif /* FREECIV_MSWINDOWS */
528
529 return result;
530}
531
532/************************************************************************/
536#ifdef FREECIV_HAVE_LIBZ
537 gzFile fc_gzopen(const char *filename, const char *opentype)
538{
539#ifdef FREECIV_MSWINDOWS
540 gzFile result;
541 char *filename_in_local_encoding =
542 internal_to_local_string_malloc(filename);
543
544 result = gzopen(filename_in_local_encoding, opentype);
545 free(filename_in_local_encoding);
546 return result;
547#else /* FREECIV_MSWINDOWS */
548 return gzopen(filename, opentype);
549#endif /* FREECIV_MSWINDOWS */
550}
551#endif /* FREECIV_HAVE_LIBZ */
552
553/************************************************************************/
557 int fc_remove(const char *filename)
558{
559#ifdef FREECIV_MSWINDOWS
560 int result;
561 char *filename_in_local_encoding =
562 internal_to_local_string_malloc(filename);
563
564 result = remove(filename_in_local_encoding);
565 free(filename_in_local_encoding);
566 return result;
567#else /* FREECIV_MSWINDOWS */
568 return remove(filename);
569#endif /* FREECIV_MSWINDOWS */
570}
571
572/************************************************************************/
576 int fc_stat(const char *filename, struct stat *buf)
577{
578#ifdef FREECIV_MSWINDOWS
579 int result;
580 char *filename_in_local_encoding =
581 internal_to_local_string_malloc(filename);
582
583 result = stat(filename_in_local_encoding, buf);
584 free(filename_in_local_encoding);
585 return result;
586#else /* FREECIV_MSWINDOWS */
587 return stat(filename, buf);
588#endif /* FREECIV_MSWINDOWS */
589}
590
591/************************************************************************/
594 fc_errno fc_get_errno(void)
595{
596#ifdef FREECIV_MSWINDOWS
597 return GetLastError();
598#else /* FREECIV_MSWINDOWS */
599 return errno;
600#endif /* FREECIV_MSWINDOWS */
601}
602
603/************************************************************************/
611 const char *fc_strerror(fc_errno err)
612{
613#ifdef FREECIV_MSWINDOWS
614 static char buf[256];
615
616 if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
617 NULL, err, 0, buf, sizeof(buf), NULL)) {
618 fc_snprintf(buf, sizeof(buf),
619 _("error %ld (failed FormatMessage)"), err);
620 }
621 return buf;
622#else /* FREECIV_MSWINDOWS */
623#ifdef HAVE_STRERROR
624 static char buf[256];
625
626 return local_to_internal_string_buffer(strerror(err),
627 buf, sizeof(buf));
628#else /* HAVE_STRERROR */
629 static char buf[64];
630
631 fc_snprintf(buf, sizeof(buf),
632 _("error %d (compiled without strerror)"), err);
633 return buf;
634#endif /* HAVE_STRERROR */
635#endif /* FREECIV_MSWINDOWS */
636}
637
638/************************************************************************/
641 void fc_usleep(unsigned long usec)
642{
643#ifdef HAVE_NANOSLEEP
644 struct timespec ts;
645
646 if (usec >= 1000000) {
647 ts.tv_sec = usec / 1000000;
648 ts.tv_nsec = (usec % 1000000) * 1000;
649 } else {
650 ts.tv_sec = 0;
651 ts.tv_nsec = usec * 1000;
652 }
653
654 nanosleep(&ts, NULL);
655#else /* HAVE_NANOSLEEP */
656#ifdef HAVE_USLEEP
657 usleep(usec);
658#else /* HAVE_USLEEP */
659#ifdef HAVE_SNOOZE /* BeOS */
660 snooze(usec);
661#else /* HAVE_SNOOZE */
662#ifdef GENERATING_MAC
663 EventRecord the_event; /* dummy - always be a null event */
664
665 usec /= 16666; /* microseconds to 1/60th seconds */
666 if (usec < 1) {
667 usec = 1;
668 }
669
670 /* Supposed to give other application processor time for the mac */
671 WaitNextEvent(0, &the_event, usec, 0L);
672#else /* GENERATING_MAC */
673#ifdef FREECIV_MSWINDOWS
674 Sleep(usec / 1000);
675#else /* FREECIV_MSWINDOWS */
676 fc_timeval tv;
677
678 tv.tv_sec = 0;
679 tv.tv_usec = usec;
680 /* FIXME: an interrupt can cause an EINTR return here. In that case we
681 * need to have another select call. */
682 fc_select(0, NULL, NULL, NULL, &tv);
683#endif /* FREECIV_MSWINDOWS */
684#endif /* GENERATING_MAC */
685#endif /* HAVE_SNOOZE */
686#endif /* HAVE_USLEEP */
687#endif /* HAVE_NANOSLEEP */
688}
689
690/************************************************************************/
695 char *fc_strrep_resize(char *str, size_t *len, const char *search,
696 const char *replace)
697{
698 size_t len_max;
699
700 fc_assert_ret_val(str != NULL, NULL);
701 fc_assert_ret_val(len != NULL, NULL);
702
703 if (search == NULL || replace == NULL) {
704 return str;
705 }
706
707 len_max = ceil((double)strlen(str) * strlen(replace) / strlen(search)) + 1;
708 if ((*len) < len_max) {
709 /* Replace string is longer than search string; allocate enough memory
710 * for the worst case */
711 (*len) = len_max;
712 str = fc_realloc(str, len_max);
713 }
714
715#ifndef FREECIV_NDEBUG
716 bool success =
717#endif
718 fc_strrep(str, (*len), search, replace);
719
720 /* Should never happen */
721 fc_assert_ret_val_msg(success, NULL,
722 "Can't replace '%s' by '%s' in '%s'. Too small "
723 "size after reallocation: " SIZE_T_PRINTF ".",
724 search, replace, str, *len);
725
726 return str;
727}
728
729/************************************************************************/
734 bool fc_strrep(char *str, size_t len, const char *search,
735 const char *replace)
736{
737 size_t len_search, len_replace;
738 char *s, *p;
739
740 fc_assert_ret_val(str != NULL, FALSE);
741
742 if (search == NULL || replace == NULL) {
743 return TRUE;
744 }
745
746 len_search = strlen(search);
747 len_replace = strlen(replace);
748
749 s = str;
750 while (s != NULL) {
751 p = strstr(s, search);
752 if (p == NULL) {
753 /* Nothing found */
754 break;
755 }
756
757 if (len < (strlen(str) + len_replace - len_search + 1)) {
758 /* sizeof(str) not large enough to do the replacement */
759 return FALSE;
760 }
761
762 memmove(p + len_replace, p + len_search, strlen(p + len_search) + 1);
763 memcpy(p, replace, len_replace);
764 s = p + len_replace;
765 }
766
767 return TRUE;
768}
769
770/************************************************************************/
791 size_t fc_strlcpy(char *dest, const char *src, size_t n)
792{
793 bool enough_mem = FALSE;
794 int slen;
795 int dlen;
796 UErrorCode err_code = U_ZERO_ERROR;
797
798 fc_assert_ret_val(NULL != dest, -1);
799 fc_assert_ret_val(NULL != src, -1);
800 fc_assert_ret_val(0 < n, -1);
801
802 if (icu_buffer_uchars == 0) {
803 fc_strAPI_init();
804 }
805
806 fc_mutex_allocate(&icu_buffer_mutex);
807
808 while (!enough_mem) {
809 u_strFromUTF8(icu_buffer1, icu_buffer_uchars, &slen, src, -1, &err_code);
810
811 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
812 * the buffers we were using */
813 if (err_code == U_BUFFER_OVERFLOW_ERROR) {
814 icu_buffers_increase();
815 err_code = U_ZERO_ERROR;
816 } else {
817 enough_mem = TRUE;
818 }
819 }
820
821 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
822
823 fc_mutex_release(&icu_buffer_mutex);
824
825 dest[n - 1] = '\0';
826
827 return dlen;
828}
829
830/************************************************************************/
836 size_t fc_strlcat(char *dest, const char *src, size_t n)
837{
838 size_t start;
839
840 start = strlen(dest);
841
842 fc_assert(start < n);
843
844 return fc_strlcpy(dest + start, src, n - start) + start;
845}
846
847/************************************************************************/
898/* This must be at least as big as PLAIN_FILE_BUF_SIZE in ioz.c */
899#define VSNP_BUF_SIZE (8096*1024)
900 int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
901{
902#ifdef HAVE_WORKING_VSNPRINTF
903 int r;
904#endif
905
906 /* This may be overzealous, but I suspect any triggering of these to
907 * be bugs. */
908
909 fc_assert_ret_val(0 < n, -1);
910
911#ifdef HAVE_WORKING_VSNPRINTF
912 r = vsnprintf(str, n, format, ap);
913 str[n - 1] = 0;
914
915 return r;
916#else /* HAVE_WORKING_VSNPRINTF */
917 {
918 /* Don't use fc_malloc() or log_*() here, since they may call
919 fc_vsnprintf() if it fails. */
920 size_t len;
921
922 if (n > VSNP_BUF_SIZE) {
923 fprintf(stderr, "fc_vsnprintf() call with length " SIZE_T_PRINTF "."
924 "Maximum supported is %d", n, VSNP_BUF_SIZE);
925 exit(EXIT_FAILURE);
926 }
927
928 fc_mutex_allocate(&vsnprintf_mutex);
929
930 if (vsnprintf_buf == NULL) {
931 vsnprintf_buf = malloc(VSNP_BUF_SIZE);
932
933 if (vsnprintf_buf == NULL) {
934 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
935 "replacement.", VSNP_BUF_SIZE);
936 fc_mutex_release(&vsnprintf_mutex);
937
938 exit(EXIT_FAILURE);
939 }
940 }
941
942 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
943
944#ifdef HAVE_VSNPRINTF
945 vsnprintf(vsnprintf_buf, VSNP_BUF_SIZE, format, ap);
946#else
947 vsprintf(vsnprintf_buf, format, ap);
948#endif /* HAVE_VSNPRINTF */
949
950 len = strlen(vsnprintf_buf);
951
952 if (len >= VSNP_BUF_SIZE - 1) {
953 fprintf(stderr, "Overflow in vsnprintf replacement!"
954 " (buffer size %d) aborting...\n", VSNP_BUF_SIZE);
955 abort();
956 }
957 if (n >= len + 1) {
958 memcpy(str, vsnprintf_buf, len + 1);
959 } else {
960 memcpy(str, vsnprintf_buf, n - 1);
961 str[n - 1] = '\0';
962 }
963
964 fc_mutex_release(&vsnprintf_mutex);
965
966 return len;
967 }
968#endif /* HAVE_WORKING_VSNPRINTF */
969}
970
971/************************************************************************/
974 int fc_snprintf(char *str, size_t n, const char *format, ...)
975{
976 int ret;
977 va_list ap;
978
979 va_start(ap, format);
980 ret = fc_vsnprintf(str, n, format, ap);
981 va_end(ap);
982
983 return ret;
984}
985
986/************************************************************************/
1000 int cat_snprintf(char *str, size_t n, const char *format, ...)
1001{
1002 size_t len;
1003 int ret;
1004 va_list ap;
1005
1006 fc_assert_ret_val(0 < n, -1);
1007
1008 len = strlen(str);
1009 fc_assert_ret_val(len < n, -1);
1010
1011 va_start(ap, format);
1012 ret = fc_vsnprintf(str+len, n-len, format, ap);
1013 va_end(ap);
1014
1015 return (-1 == ret ? -1 : ret + len);
1016}
1017
1018/************************************************************************/
1021 int fc_gethostname(char *buf, size_t len)
1022{
1023#ifdef HAVE_GETHOSTNAME
1024 return gethostname(buf, len);
1025#else
1026 return -1;
1027#endif
1028}
1029
1030#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
1031/****************************************************************************
1032 Support for console I/O in case FREECIV_SOCKET_ZERO_NOT_STDIN.
1033****************************************************************************/
1034
1035#define CONSOLE_BUF_SIZE 100
1036static char console_buf[CONSOLE_BUF_SIZE + 1];
1037
1038/***************************************************************************/
1039
1040#ifdef FREECIV_MSWINDOWS
1041static HANDLE console_thread = INVALID_HANDLE_VALUE;
1042
1043/************************************************************************/
1046static DWORD WINAPI windows_console_thread(LPVOID arg)
1047{
1048 if (fgets(console_buf, CONSOLE_BUF_SIZE, stdin)) {
1049 char *s;
1050
1051 if ((s = strchr(console_buf, '\n'))) {
1052 *s = '\0';
1053 }
1054 }
1055
1056 return 0;
1057}
1058#endif /* FREECIV_MSWINDOWS */
1059
1060/************************************************************************/
1063void fc_init_console(void)
1064{
1065#ifdef FREECIV_MSWINDOWS
1066 if (console_thread != INVALID_HANDLE_VALUE) {
1067 return;
1068 }
1069
1070 console_buf[0] = '\0';
1071 console_thread = (HANDLE) CreateThread(NULL, 0, windows_console_thread,
1072 NULL, 0, NULL);
1073#else /* FREECIV_MSWINDOWS */
1074 static bool initialized = FALSE;
1075
1076 if (!initialized) {
1077 initialized = TRUE;
1078#ifdef HAVE_FILENO
1079 fc_nonblock(fileno(stdin));
1080#endif
1081 }
1082#endif /* FREECIV_MSWINDOWS */
1083}
1084
1085/************************************************************************/
1092char *fc_read_console(void)
1093{
1094#ifdef FREECIV_MSWINDOWS
1095 if (WaitForSingleObject(console_thread, 0) == WAIT_OBJECT_0) {
1096 CloseHandle(console_thread);
1097 console_thread = INVALID_HANDLE_VALUE;
1098
1099 return console_buf;
1100 }
1101
1102 return NULL;
1103#else /* FREECIV_MSWINDOWS */
1104 if (!feof(stdin)) { /* input from server operator */
1105 static char *bufptr = console_buf;
1106
1107 /* fetch chars until \n, or run out of space in buffer */
1108 /* blocks if fc_nonblock() in fc_init_console() failed */
1109 while ((*bufptr = fgetc(stdin)) != EOF) {
1110 if (*bufptr == '\n') {
1111 *bufptr = '\0';
1112 }
1113 if (*bufptr == '\0') {
1114 bufptr = console_buf;
1115
1116 return console_buf;
1117 }
1118 if ((bufptr - console_buf) <= CONSOLE_BUF_SIZE) {
1119 bufptr++; /* prevent overrun */
1120 }
1121 }
1122 }
1123
1124 return NULL;
1125#endif /* FREECIV_MSWINDOWS */
1126}
1127
1128#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
1129
1130/************************************************************************/
1134 bool is_reg_file_for_access(const char *name, bool write_access)
1135{
1136 struct stat tmp;
1137
1138 if (fc_stat(name, &tmp) == 0) {
1139 return S_ISREG(tmp.st_mode);
1140 } else {
1141 return write_access && errno == ENOENT;
1142 }
1143}
1144
1145/************************************************************************/
1149 int fc_break_lines(char *str, size_t desired_len)
1150{
1151 size_t slen = (size_t)strlen(str);
1152 int num_lines = 0;
1153
1154 /* At top of this loop, s points to the rest of string,
1155 * either at start or after inserted newline: */
1156 top:
1157 if (str && *str != '\0' && slen > desired_len) {
1158 char *c;
1159
1160 num_lines++;
1161
1162 /* Check if there is already a newline: */
1163 for (c = str; c < str + desired_len; c++) {
1164 if (*c == '\n') {
1165 slen -= c + 1 - str;
1166 str = c + 1;
1167 goto top;
1168 }
1169 }
1170
1171 /* Find space and break: */
1172 for (c = str + desired_len; c > str; c--) {
1173 if (fc_isspace(*c)) {
1174 *c = '\n';
1175 slen -= c + 1 - str;
1176 str = c + 1;
1177 goto top;
1178 }
1179 }
1180
1181 /* Couldn't find a good break; settle for a bad one... */
1182 for (c = str + desired_len + 1; *c != '\0'; c++) {
1183 if (fc_isspace(*c)) {
1184 *c = '\n';
1185 slen -= c + 1 - str;
1186 str = c + 1;
1187 goto top;
1188 }
1189 }
1190 }
1191
1192 return num_lines;
1193}
1194
1195/****************************************************************************
1196 Character function wrappers
1197
1198 These functions are wrappers for the libc character class functions,
1199 without any locale-dependent behavior. The character functions work as
1200 documented for ASCII. Bytes outside of the ASCII set will not be reported
1201 to belong to any character class, and will be left unchanged by
1202 transformations. This behavior is safe but not strictly correct
1203 forsingle-byte 8-bit- or UTF-8 encoded text; in UTF-8, any byte that is
1204 part of a multibyte sequence is non-ASCII.
1205****************************************************************************/
1206
1207/************************************************************************/
1210 bool fc_isalnum(char c)
1211{
1212 if (128 <= (unsigned char) c) {
1213 return FALSE;
1214 }
1215 return isalnum((int) ((unsigned char) c)) != 0;
1216}
1217
1218/************************************************************************/
1221 bool fc_isalpha(char c)
1222{
1223 if (128 <= (unsigned char) c) {
1224 return FALSE;
1225 }
1226 return isalpha((int) ((unsigned char) c)) != 0;
1227}
1228
1229/************************************************************************/
1232 bool fc_isdigit(char c)
1233{
1234 if (128 <= (unsigned char) c) {
1235 return FALSE;
1236 }
1237 return isdigit((int) ((unsigned char) c)) != 0;
1238}
1239
1240/************************************************************************/
1243 bool fc_isprint(char c)
1244{
1245 if (128 <= (unsigned char) c) {
1246 return FALSE;
1247 }
1248 return isprint((int) ((unsigned char) c)) != 0;
1249}
1250
1251/************************************************************************/
1254 bool fc_isspace(char c)
1255{
1256 if (128 <= (unsigned char) c) {
1257 return FALSE;
1258 }
1259 return isspace((int) ((unsigned char) c)) != 0;
1260}
1261
1262/************************************************************************/
1265 bool fc_isupper(char c)
1266{
1267 if (128 <= (unsigned char) c) {
1268 return FALSE;
1269 }
1270 return isupper((int) ((unsigned char) c)) != 0;
1271}
1272
1273/************************************************************************/
1276 char fc_toupper(char c)
1277{
1278 if (128 <= (unsigned char) c) {
1279 return c;
1280 }
1281 return (char) toupper((int) ((unsigned char) c));
1282}
1283
1284/************************************************************************/
1287 char fc_tolower(char c)
1288{
1289 if (128 <= (unsigned char) c) {
1290 return c;
1291 }
1292 return (char) tolower((int) ((unsigned char) c));
1293}
1294
1295/************************************************************************/
1301 const char *fc_basename(const char *path)
1302{
1303 static char buf[2048];
1304
1305 /* Copy const parameter string to buffer that basename() can
1306 * modify */
1307 fc_strlcpy(buf, path, sizeof(buf));
1308
1309 return basename(buf);
1310}
1311
1312/************************************************************************/
1315 struct tm *fc_localtime(const time_t *timep, struct tm *result)
1316{
1317#ifdef HAVE_LOCALTIME_R
1318 return localtime_r(timep, result);
1319#else /* HAVE_LOCALTIME_R */
1320 fc_mutex_allocate(&localtime_mutex);
1321 memcpy(result, localtime(timep), sizeof(struct tm));
1322 fc_mutex_release(&localtime_mutex);
1323
1324 return result;
1325#endif /* HAVE_LOCALTIME_R */
1326}
1327
1328/************************************************************************/
1331 int fc_at_quick_exit(void (*func)(void))
1332{
1333#ifdef HAVE_AT_QUICK_EXIT
1334 return at_quick_exit(func);
1335#else /* HAVE_AT_QUICK_EXIT */
1336 return -1;
1337#endif /* HAVE_AT_QUICK_EXIT */
1338}
1339
1340/************************************************************************/
1343 void fc_support_init(void)
1344{
1345 fc_strAPI_init();
1346
1347#ifndef HAVE_WORKING_VSNPRINTF
1348 fc_mutex_init(&vsnprintf_mutex);
1349#endif /* HAVE_WORKING_VSNPRINTF */
1350
1351#ifndef HAVE_LOCALTIME_R
1352 fc_mutex_init(&localtime_mutex);
1353#endif /* HAVE_LOCALTIME_R */
1354
1355 support_initialized = TRUE;
1356}
1357
1358/************************************************************************/
1361 void fc_support_free(void)
1362{
1363 support_initialized = FALSE;
1364
1365#ifndef HAVE_WORKING_VSNPRINTF
1366 if (vsnprintf_buf != NULL) {
1367 free(vsnprintf_buf);
1368 vsnprintf_buf = NULL;
1369 }
1370 fc_mutex_destroy(&vsnprintf_mutex);
1371#endif /* HAVE_WORKING_VSNPRINTF */
1372
1373#ifndef HAVE_LOCALTIME_R
1374 fc_mutex_destroy(&localtime_mutex);
1375#endif /* HAVE_LOCALTIME_R */
1376
1377 fc_strAPI_free();
1378}
1379
1380/************************************************************************/
1383 bool are_support_services_available(void)
1384{
1385 return support_initialized;
1386}
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
events.h
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:974
fc_isalpha
bool fc_isalpha(char c)
Definition support.c:1221
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1021
fc_isprint
bool fc_isprint(char c)
Definition support.c:1243
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
support_initialized
static bool support_initialized
Definition support.c:114
make_escapes
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:297
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
fc_usleep
void fc_usleep(unsigned long usec)
Definition support.c:641
fc_support_init
void fc_support_init(void)
Definition support.c:1343
fc_isspace
bool fc_isspace(char c)
Definition support.c:1254
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:611
fc_strlcat
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:836
fc_strcasestr
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:440
fc_strrep
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:734
fc_localtime
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1315
cat_snprintf
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:1000
fc_vsnprintf
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:900
fc_fopen
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:507
fc_strAPI_free
static void fc_strAPI_free(void)
Definition support.c:174
fc_break_lines
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1149
localtime_mutex
static fc_mutex localtime_mutex
Definition support.c:127
icu_buffer1
static UChar * icu_buffer1
Definition support.c:117
icu_buffer_mutex
fc_mutex icu_buffer_mutex
Definition support.c:119
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:594
fc_support_free
void fc_support_free(void)
Definition support.c:1361
remove_escapes
void remove_escapes(const char *str, bool full_escapes, char *buf, size_t buf_len)
Definition support.c:333
fc_isdigit
bool fc_isdigit(char c)
Definition support.c:1232
fc_strcoll
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:473
fc_stat
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:576
is_reg_file_for_access
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1134
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1210
fc_isupper
bool fc_isupper(char c)
Definition support.c:1265
fc_basename
const char * fc_basename(const char *path)
Definition support.c:1301
icu_buffers_initial
static void icu_buffers_initial(void)
Definition support.c:133
vsnprintf_buf
static char * vsnprintf_buf
Definition support.c:122
icu_buffer_uchars
static int icu_buffer_uchars
Definition support.c:116
fc_strncasequotecmp
int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
Definition support.c:380
vsnprintf_mutex
static fc_mutex vsnprintf_mutex
Definition support.c:123
fc_strAPI_init
static void fc_strAPI_init(void)
Definition support.c:163
effectivestrlenquote
size_t effectivestrlenquote(const char *str)
Definition support.c:359
fc_tolower
char fc_tolower(char c)
Definition support.c:1287
icu_buffers_increase
static void icu_buffers_increase(void)
Definition support.c:149
fc_at_quick_exit
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1331
fc_stricoll
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:487
fc_remove
int fc_remove(const char *filename)
Definition support.c:557
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
fc_strrep_resize
char * fc_strrep_resize(char *str, size_t *len, const char *search, const char *replace)
Definition support.c:695
icu_buffer2
static UChar * icu_buffer2
Definition support.c:118
are_support_services_available
bool are_support_services_available(void)
Definition support.c:1383
fc_toupper
char fc_toupper(char c)
Definition support.c:1276
VSNP_BUF_SIZE
#define VSNP_BUF_SIZE
Definition support.c:899
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