Freeciv-3.1
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 remembering to use these "fc" functions on
36 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
115
116static int icu_buffer_uchars = 0;
117static UChar *icu_buffer1 = NULL;
118static UChar *icu_buffer2 = NULL;
120
121#ifndef HAVE_WORKING_VSNPRINTF
122static char *vsnprintf_buf = NULL;
123static fc_mutex vsnprintf_mutex;
124#endif /* HAVE_WORKING_VSNPRINTF */
125
126#ifndef HAVE_LOCALTIME_R
127static fc_mutex localtime_mutex;
128#endif /* HAVE_LOCALTIME_R */
129
130/************************************************************************/
133static 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 */
143 }
144}
145
146/************************************************************************/
149static 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 */
158}
159
160/************************************************************************/
163static void fc_strAPI_init(void)
164{
165 if (icu_buffer_uchars == 0) {
168 }
169}
170
171/************************************************************************/
174static 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;
182 }
184}
185
186/************************************************************************/
189int 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) {
206 }
207
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) {
221 } else {
222 enough_mem = TRUE;
223 }
224 }
225
226 ret = u_strCaseCompare(icu_buffer1, -1, icu_buffer2, -1,
227 0, &err_code);
228
230
231 return ret;
232}
233
234/************************************************************************/
238int 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) {
255 }
256
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) {
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
286
287 return ret;
288}
289
290/************************************************************************/
297void 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
316 default:
317 *dest++ = *str++;
318 break;
319 }
320 }
321 *dest = 0;
322}
323
324/************************************************************************/
333void 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/************************************************************************/
359size_t effectivestrlenquote(const char *str)
360{
361 int len;
362 if (!str) {
363 return 0;
364 }
365
366 len = strlen(str);
367
368 if (str[0] == '"' && str[len-1] == '"') {
369 return len - 2;
370 }
371
372 return len;
373}
374
375/************************************************************************/
379int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
380{
381 size_t i;
382 size_t len0;
383 size_t len1;
384 size_t cmplen;
385
386 if (str0 == NULL) {
387 return -1;
388 }
389 if (str1 == NULL) {
390 return 1;
391 }
392
393 len0 = strlen(str0); /* TODO: We iterate string once already here, */
394 len1 = strlen(str1); /* could iterate only once */
395
396 if (str0[0] == '"') {
397 if (str0[len0 - 1] == '"') {
398 /* Surrounded with quotes */
399 str0++;
400 len0 -= 2;
401 }
402 }
403
404 if (str1[0] == '"') {
405 if (str1[len1 - 1] == '"') {
406 /* Surrounded with quotes */
407 str1++;
408 len1 -= 2;
409 }
410 }
411
412 if (len0 < n || len1 < n) {
413 /* One of the strings is shorter than what should be compared... */
414 if (len0 != len1) {
415 /* ...and another is longer than it. */
416 return len0 - len1;
417 }
418
419 cmplen = len0; /* This avoids comparing ending quote */
420 } else {
421 cmplen = n;
422 }
423
424 for (i = 0; i < cmplen ; i++, str0++, str1++) {
425 if (fc_tolower(*str0) != fc_tolower(*str1)) {
426 return ((int) (unsigned char) fc_tolower(*str0))
427 - ((int) (unsigned char) fc_tolower(*str1));
428 }
429 }
430
431 /* All characters compared and all matched */
432 return 0;
433}
434
435/************************************************************************/
439char *fc_strcasestr(const char *haystack, const char *needle)
440{
441#ifdef HAVE_STRCASESTR
442 return strcasestr(haystack, needle);
443#else
444 size_t haystacks;
445 size_t needles;
446 const char *p;
447
448 if (NULL == needle || '\0' == *needle) {
449 return (char *)haystack;
450 }
451 if (NULL == haystack || '\0' == *haystack) {
452 return NULL;
453 }
454 haystacks = strlen(haystack);
455 needles = strlen(needle);
456 if (haystacks < needles) {
457 return NULL;
458 }
459
460 for (p = haystack; p <= &haystack[haystacks - needles]; p++) {
461 if (0 == fc_strncasecmp(p, needle, needles)) {
462 return (char *)p;
463 }
464 }
465 return NULL;
466#endif /* HAVE_STRCASESTR */
467}
468
469/************************************************************************/
472int fc_strcoll(const char *str0, const char *str1)
473{
474#if defined(ENABLE_NLS) && defined(HAVE_STRCOLL)
475 return strcoll(str0, str1);
476#elif defined(ENABLE_NLS) && defined(HAVE__STRCOLL)
477 return _strcoll(str0, str1);
478#else
479 return strcmp(str0, str1);
480#endif
481}
482
483/************************************************************************/
486int fc_stricoll(const char *str0, const char *str1)
487{
488 /* We prefer _stricoll() over stricoll() since
489 * latter is not declared in MinGW headers causing compiler
490 * warning, preventing -Werror builds. */
491#if defined(ENABLE_NLS) && defined(HAVE__STRICOLL)
492 return _stricoll(str0, str1);
493#elif defined(ENABLE_NLS) && defined(HAVE_STRICOLL)
494 return stricoll(str0, str1);
495#elif defined(ENABLE_NLS) && defined(HAVE_STRCASECOLL)
496 return strcasecoll(str0, str1);
497#else
498 return fc_strcasecmp(str0, str1);
499#endif
500}
501
502/************************************************************************/
506FILE *fc_fopen(const char *filename, const char *opentype)
507{
508 FILE *result;
509
510#ifdef FREECIV_MSWINDOWS
511 char *real_filename = internal_to_local_string_malloc(filename);
512#else /* FREECIV_MSWINDOWS */
513 const char *real_filename = filename;
514#endif /* FREECIV_MSWINDOWS */
515
516#ifdef HAVE_FOPEN_S
517 if (fopen_s(&result, real_filename, opentype) != 0) {
518 result = NULL;
519 }
520#else /* HAVE_FOPEN_S */
521 result = fopen(real_filename, opentype);
522#endif /* HAVE_FOPEN_S */
523
524#ifdef FREECIV_MSWINDOWS
525 free(real_filename);
526#endif /* FREECIV_MSWINDOWS */
527
528 return result;
529}
530
531/************************************************************************/
535#ifdef FREECIV_HAVE_LIBZ
536gzFile fc_gzopen(const char *filename, const char *opentype)
537{
538#ifdef FREECIV_MSWINDOWS
539 gzFile result;
540 char *filename_in_local_encoding =
542
543 result = gzopen(filename_in_local_encoding, opentype);
544 free(filename_in_local_encoding);
545 return result;
546#else /* FREECIV_MSWINDOWS */
547 return gzopen(filename, opentype);
548#endif /* FREECIV_MSWINDOWS */
549}
550#endif /* FREECIV_HAVE_LIBZ */
551
552/************************************************************************/
556int fc_remove(const char *filename)
557{
558#ifdef FREECIV_MSWINDOWS
559 int result;
560 char *filename_in_local_encoding =
562
563 result = remove(filename_in_local_encoding);
564 free(filename_in_local_encoding);
565 return result;
566#else /* FREECIV_MSWINDOWS */
567 return remove(filename);
568#endif /* FREECIV_MSWINDOWS */
569}
570
571/************************************************************************/
575int fc_stat(const char *filename, struct stat *buf)
576{
577#ifdef FREECIV_MSWINDOWS
578 int result;
579 char *filename_in_local_encoding =
581
582 result = stat(filename_in_local_encoding, buf);
583 free(filename_in_local_encoding);
584 return result;
585#else /* FREECIV_MSWINDOWS */
586 return stat(filename, buf);
587#endif /* FREECIV_MSWINDOWS */
588}
589
590/************************************************************************/
594{
595#ifdef FREECIV_MSWINDOWS
596 return GetLastError();
597#else /* FREECIV_MSWINDOWS */
598 return errno;
599#endif /* FREECIV_MSWINDOWS */
600}
601
602/************************************************************************/
610const char *fc_strerror(fc_errno err)
611{
612#ifdef FREECIV_MSWINDOWS
613 static char buf[256];
614
615 if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
616 NULL, err, 0, buf, sizeof(buf), NULL)) {
617 fc_snprintf(buf, sizeof(buf),
618 _("error %ld (failed FormatMessage)"), err);
619 }
620 return buf;
621#else /* FREECIV_MSWINDOWS */
622#ifdef HAVE_STRERROR
623 static char buf[256];
624
625 return local_to_internal_string_buffer(strerror(err),
626 buf, sizeof(buf));
627#else /* HAVE_STRERROR */
628 static char buf[64];
629
630 fc_snprintf(buf, sizeof(buf),
631 _("error %d (compiled without strerror)"), err);
632 return buf;
633#endif /* HAVE_STRERROR */
634#endif /* FREECIV_MSWINDOWS */
635}
636
637/************************************************************************/
640void fc_usleep(unsigned long usec)
641{
642#ifdef HAVE_NANOSLEEP
643 struct timespec ts;
644
645 if (usec >= 1000000) {
646 ts.tv_sec = usec / 1000000;
647 ts.tv_nsec = (usec % 1000000) * 1000;
648 } else {
649 ts.tv_sec = 0;
650 ts.tv_nsec = usec * 1000;
651 }
652
653 nanosleep(&ts, NULL);
654#else /* HAVE_NANOSLEEP */
655#ifdef HAVE_USLEEP
656 usleep(usec);
657#else /* HAVE_USLEEP */
658#ifdef HAVE_SNOOZE /* BeOS */
659 snooze(usec);
660#else /* HAVE_SNOOZE */
661#ifdef GENERATING_MAC
662 EventRecord the_event; /* dummy - always be a null event */
663
664 usec /= 16666; /* microseconds to 1/60th seconds */
665 if (usec < 1) {
666 usec = 1;
667 }
668 /* supposed to give other application processor time for the mac */
669 WaitNextEvent(0, &the_event, usec, 0L);
670#else /* GENERATING_MAC */
671#ifdef FREECIV_MSWINDOWS
672 Sleep(usec / 1000);
673#else /* FREECIV_MSWINDOWS */
674 fc_timeval tv;
675
676 tv.tv_sec = 0;
677 tv.tv_usec = usec;
678 /* FIXME: an interrupt can cause an EINTR return here. In that case we
679 * need to have another select call. */
680 fc_select(0, NULL, NULL, NULL, &tv);
681#endif /* FREECIV_MSWINDOWS */
682#endif /* GENERATING_MAC */
683#endif /* HAVE_SNOOZE */
684#endif /* HAVE_USLEEP */
685#endif /* HAVE_NANOSLEEP */
686}
687
688/************************************************************************/
693char *fc_strrep_resize(char *str, size_t *len, const char *search,
694 const char *replace)
695{
696 size_t len_max;
697
698 fc_assert_ret_val(str != NULL, NULL);
699 fc_assert_ret_val(len != NULL, NULL);
700 if (search == NULL || replace == NULL) {
701 return str;
702 }
703
704 len_max = ceil((double)strlen(str) * strlen(replace) / strlen(search)) + 1;
705 if ((*len) < len_max) {
706 /* replace string is longer than search string; allocate enough memory
707 * for the worst case */
708 (*len) = len_max;
709 str = fc_realloc(str, len_max);
710 }
711
712#ifndef FREECIV_NDEBUG
713 bool success =
714#endif
715 fc_strrep(str, (*len), search, replace);
716
717 /* Should never happen */
718 fc_assert_ret_val_msg(success, NULL,
719 "Can't replace '%s' by '%s' in '%s'. Too small "
720 "size after reallocation: " SIZE_T_PRINTF ".",
721 search, replace, str, *len);
722
723 return str;
724}
725
726/************************************************************************/
731bool fc_strrep(char *str, size_t len, const char *search,
732 const char *replace)
733{
734 size_t len_search, len_replace;
735 char *s, *p;
736
737 fc_assert_ret_val(str != NULL, FALSE);
738 if (search == NULL || replace == NULL) {
739 return TRUE;
740 }
741
742 len_search = strlen(search);
743 len_replace = strlen(replace);
744
745 s = str;
746 while (s != NULL) {
747 p = strstr(s, search);
748 if (p == NULL) {
749 /* nothing found */
750 break;
751 }
752
753 if (len < (strlen(str) + len_replace - len_search + 1)) {
754 /* sizeof(str) not large enough to do the replacement */
755 return FALSE;
756 }
757
758 memmove(p + len_replace, p + len_search, strlen(p + len_search) + 1);
759 memcpy(p, replace, len_replace);
760 s = p + len_replace;
761 }
762
763 return TRUE;
764}
765
766/************************************************************************/
787size_t fc_strlcpy(char *dest, const char *src, size_t n)
788{
789 bool enough_mem = FALSE;
790 int slen;
791 int dlen;
792 UErrorCode err_code = U_ZERO_ERROR;
793
794 fc_assert_ret_val(NULL != dest, -1);
795 fc_assert_ret_val(NULL != src, -1);
796 fc_assert_ret_val(0 < n, -1);
797
798 if (icu_buffer_uchars == 0) {
800 }
801
803
804 while (!enough_mem) {
805 u_strFromUTF8(icu_buffer1, icu_buffer_uchars, &slen, src, -1, &err_code);
806
807 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
808 * the buffers we were using */
809 if (err_code == U_BUFFER_OVERFLOW_ERROR) {
811 err_code = U_ZERO_ERROR;
812 } else {
813 enough_mem = TRUE;
814 }
815 }
816
817 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
818
820
821 dest[n - 1] = '\0';
822
823 return dlen;
824}
825
826/************************************************************************/
832size_t fc_strlcat(char *dest, const char *src, size_t n)
833{
834 size_t start;
835
836 start = strlen(dest);
837
838 fc_assert(start < n);
839
840 return fc_strlcpy(dest + start, src, n - start) + start;
841}
842
843/************************************************************************/
894/* This must be at least as big as PLAIN_FILE_BUF_SIZE in ioz.c */
895#define VSNP_BUF_SIZE (8096*1024)
896int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
897{
898#ifdef HAVE_WORKING_VSNPRINTF
899 int r;
900#endif
901
902 /* This may be overzealous, but I suspect any triggering of these to
903 * be bugs. */
904
905 fc_assert_ret_val(0 < n, -1);
906
907#ifdef HAVE_WORKING_VSNPRINTF
908 r = vsnprintf(str, n, format, ap);
909 str[n - 1] = 0;
910
911 return r;
912#else /* HAVE_WORKING_VSNPRINTF */
913 {
914 /* Don't use fc_malloc() or log_*() here, since they may call
915 fc_vsnprintf() if it fails. */
916 size_t len;
917
918 if (n > VSNP_BUF_SIZE) {
919 fprintf(stderr, "fc_vsnprintf() call with length " SIZE_T_PRINTF "."
920 "Maximum supported is %d", n, VSNP_BUF_SIZE);
921 exit(EXIT_FAILURE);
922 }
923
925
926 if (vsnprintf_buf == NULL) {
928
929 if (vsnprintf_buf == NULL) {
930 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
931 "replacement.", VSNP_BUF_SIZE);
933 exit(EXIT_FAILURE);
934 }
935 }
936
937 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
938
939#ifdef HAVE_VSNPRINTF
940 vsnprintf(vsnprintf_buf, VSNP_BUF_SIZE, format, ap);
941#else
942 vsprintf(vsnprintf_buf, format, ap);
943#endif /* HAVE_VSNPRINTF */
944
945 len = strlen(vsnprintf_buf);
946
947 if (len >= VSNP_BUF_SIZE - 1) {
948 fprintf(stderr, "Overflow in vsnprintf replacement!"
949 " (buffer size %d) aborting...\n", VSNP_BUF_SIZE);
950 abort();
951 }
952 if (n >= len + 1) {
953 memcpy(str, vsnprintf_buf, len + 1);
954 } else {
955 memcpy(str, vsnprintf_buf, n - 1);
956 str[n - 1] = '\0';
957 }
958
960
961 return len;
962 }
963#endif /* HAVE_WORKING_VSNPRINTF */
964}
965
966/************************************************************************/
969int fc_snprintf(char *str, size_t n, const char *format, ...)
970{
971 int ret;
972 va_list ap;
973
974 va_start(ap, format);
975 ret = fc_vsnprintf(str, n, format, ap);
976 va_end(ap);
977
978 return ret;
979}
980
981/************************************************************************/
995int cat_snprintf(char *str, size_t n, const char *format, ...)
996{
997 size_t len;
998 int ret;
999 va_list ap;
1000
1001 fc_assert_ret_val(0 < n, -1);
1002
1003 len = strlen(str);
1004 fc_assert_ret_val(len < n, -1);
1005
1006 va_start(ap, format);
1007 ret = fc_vsnprintf(str+len, n-len, format, ap);
1008 va_end(ap);
1009
1010 return (-1 == ret ? -1 : ret + len);
1011}
1012
1013/************************************************************************/
1016int fc_gethostname(char *buf, size_t len)
1017{
1018#ifdef HAVE_GETHOSTNAME
1019 return gethostname(buf, len);
1020#else
1021 return -1;
1022#endif
1023}
1024
1025#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
1026/****************************************************************************
1027 Support for console I/O in case FREECIV_SOCKET_ZERO_NOT_STDIN.
1028****************************************************************************/
1029
1030#define CONSOLE_BUF_SIZE 100
1031static char console_buf[CONSOLE_BUF_SIZE + 1];
1032
1033/***************************************************************************/
1034
1035#ifdef FREECIV_MSWINDOWS
1036static HANDLE console_thread = INVALID_HANDLE_VALUE;
1037
1038/************************************************************************/
1041static DWORD WINAPI windows_console_thread(LPVOID arg)
1042{
1043 if (fgets(console_buf, CONSOLE_BUF_SIZE, stdin)) {
1044 char *s;
1045
1046 if ((s = strchr(console_buf, '\n'))) {
1047 *s = '\0';
1048 }
1049 }
1050
1051 return 0;
1052}
1053#endif /* FREECIV_MSWINDOWS */
1054
1055/************************************************************************/
1058void fc_init_console(void)
1059{
1060#ifdef FREECIV_MSWINDOWS
1061 if (console_thread != INVALID_HANDLE_VALUE) {
1062 return;
1063 }
1064
1065 console_buf[0] = '\0';
1066 console_thread = (HANDLE) CreateThread(NULL, 0, windows_console_thread,
1067 NULL, 0, NULL);
1068#else /* FREECIV_MSWINDOWS */
1069 static bool initialized = FALSE;
1070
1071 if (!initialized) {
1072 initialized = TRUE;
1073#ifdef HAVE_FILENO
1074 fc_nonblock(fileno(stdin));
1075#endif
1076 }
1077#endif /* FREECIV_MSWINDOWS */
1078}
1079
1080/************************************************************************/
1087char *fc_read_console(void)
1088{
1089#ifdef FREECIV_MSWINDOWS
1090 if (WaitForSingleObject(console_thread, 0) == WAIT_OBJECT_0) {
1091 CloseHandle(console_thread);
1092 console_thread = INVALID_HANDLE_VALUE;
1093
1094 return console_buf;
1095 }
1096
1097 return NULL;
1098#else /* FREECIV_MSWINDOWS */
1099 if (!feof(stdin)) { /* input from server operator */
1100 static char *bufptr = console_buf;
1101
1102 /* fetch chars until \n, or run out of space in buffer */
1103 /* blocks if fc_nonblock() in fc_init_console() failed */
1104 while ((*bufptr = fgetc(stdin)) != EOF) {
1105 if (*bufptr == '\n') {
1106 *bufptr = '\0';
1107 }
1108 if (*bufptr == '\0') {
1109 bufptr = console_buf;
1110
1111 return console_buf;
1112 }
1113 if ((bufptr - console_buf) <= CONSOLE_BUF_SIZE) {
1114 bufptr++; /* prevent overrun */
1115 }
1116 }
1117 }
1118
1119 return NULL;
1120#endif /* FREECIV_MSWINDOWS */
1121}
1122
1123#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
1124
1125/************************************************************************/
1129bool is_reg_file_for_access(const char *name, bool write_access)
1130{
1131 struct stat tmp;
1132
1133 if (fc_stat(name, &tmp) == 0) {
1134 return S_ISREG(tmp.st_mode);
1135 } else {
1136 return write_access && errno == ENOENT;
1137 }
1138}
1139
1140/************************************************************************/
1144int fc_break_lines(char *str, size_t desired_len)
1145{
1146 size_t slen = (size_t)strlen(str);
1147 int num_lines = 0;
1148
1149 /* At top of this loop, s points to the rest of string,
1150 * either at start or after inserted newline: */
1151 top:
1152 if (str && *str != '\0' && slen > desired_len) {
1153 char *c;
1154
1155 num_lines++;
1156
1157 /* check if there is already a newline: */
1158 for (c = str; c < str + desired_len; c++) {
1159 if (*c == '\n') {
1160 slen -= c + 1 - str;
1161 str = c + 1;
1162 goto top;
1163 }
1164 }
1165
1166 /* find space and break: */
1167 for (c = str + desired_len; c > str; c--) {
1168 if (fc_isspace(*c)) {
1169 *c = '\n';
1170 slen -= c + 1 - str;
1171 str = c + 1;
1172 goto top;
1173 }
1174 }
1175
1176 /* couldn't find a good break; settle for a bad one... */
1177 for (c = str + desired_len + 1; *c != '\0'; c++) {
1178 if (fc_isspace(*c)) {
1179 *c = '\n';
1180 slen -= c + 1 - str;
1181 str = c + 1;
1182 goto top;
1183 }
1184 }
1185 }
1186
1187 return num_lines;
1188}
1189
1190/****************************************************************************
1191 Character function wrappers
1192
1193 These functions are wrappers for the libc character class functions,
1194 without any locale-dependent behavior. The character functions work as
1195 documented for ASCII. Bytes outside of the ASCII set will not be reported
1196 to belong to any character class, and will be left unchanged by
1197 transformations. This behavior is safe but not strictly correct
1198 forsingle-byte 8-bit- or UTF-8 encoded text; in UTF-8, any byte that is
1199 part of a multibyte sequence is non-ASCII.
1200****************************************************************************/
1201
1202/************************************************************************/
1205bool fc_isalnum(char c)
1206{
1207 if (128 <= (unsigned char) c) {
1208 return FALSE;
1209 }
1210 return isalnum((int) ((unsigned char) c)) != 0;
1211}
1212
1213/************************************************************************/
1216bool fc_isalpha(char c)
1217{
1218 if (128 <= (unsigned char) c) {
1219 return FALSE;
1220 }
1221 return isalpha((int) ((unsigned char) c)) != 0;
1222}
1223
1224/************************************************************************/
1227bool fc_isdigit(char c)
1228{
1229 if (128 <= (unsigned char) c) {
1230 return FALSE;
1231 }
1232 return isdigit((int) ((unsigned char) c)) != 0;
1233}
1234
1235/************************************************************************/
1238bool fc_isprint(char c)
1239{
1240 if (128 <= (unsigned char) c) {
1241 return FALSE;
1242 }
1243 return isprint((int) ((unsigned char) c)) != 0;
1244}
1245
1246/************************************************************************/
1249bool fc_isspace(char c)
1250{
1251 if (128 <= (unsigned char) c) {
1252 return FALSE;
1253 }
1254 return isspace((int) ((unsigned char) c)) != 0;
1255}
1256
1257/************************************************************************/
1260bool fc_isupper(char c)
1261{
1262 if (128 <= (unsigned char) c) {
1263 return FALSE;
1264 }
1265 return isupper((int) ((unsigned char) c)) != 0;
1266}
1267
1268/************************************************************************/
1271char fc_toupper(char c)
1272{
1273 if (128 <= (unsigned char) c) {
1274 return c;
1275 }
1276 return (char) toupper((int) ((unsigned char) c));
1277}
1278
1279/************************************************************************/
1282char fc_tolower(char c)
1283{
1284 if (128 <= (unsigned char) c) {
1285 return c;
1286 }
1287 return (char) tolower((int) ((unsigned char) c));
1288}
1289
1290/************************************************************************/
1296const char *fc_basename(const char *path)
1297{
1298 static char buf[2048];
1299
1300 /* Copy const parameter string to buffer that basename() can
1301 * modify */
1302 fc_strlcpy(buf, path, sizeof(buf));
1303
1304 return basename(buf);
1305}
1306
1307/************************************************************************/
1310struct tm *fc_localtime(const time_t *timep, struct tm *result)
1311{
1312#ifdef HAVE_LOCALTIME_R
1313 return localtime_r(timep, result);
1314#else /* HAVE_LOCALTIME_R */
1316 memcpy(result, localtime(timep), sizeof(struct tm));
1318
1319 return result;
1320#endif /* HAVE_LOCALTIME_R */
1321}
1322
1323/************************************************************************/
1326int fc_at_quick_exit(void (*func)(void))
1327{
1328#ifdef HAVE_AT_QUICK_EXIT
1329 return at_quick_exit(func);
1330#else /* HAVE_AT_QUICK_EXIT */
1331 return -1;
1332#endif /* HAVE_AT_QUICK_EXIT */
1333}
1334
1335/************************************************************************/
1339{
1341
1342#ifndef HAVE_WORKING_VSNPRINTF
1344#endif /* HAVE_WORKING_VSNPRINTF */
1345
1346#ifndef HAVE_LOCALTIME_R
1348#endif /* HAVE_LOCALTIME_R */
1349
1351}
1352
1353/************************************************************************/
1357{
1359
1360#ifndef HAVE_WORKING_VSNPRINTF
1361 if (vsnprintf_buf != NULL) {
1362 free(vsnprintf_buf);
1363 vsnprintf_buf = NULL;
1364 }
1366#endif /* HAVE_WORKING_VSNPRINTF */
1367
1368#ifndef HAVE_LOCALTIME_R
1370#endif /* HAVE_LOCALTIME_R */
1371
1373}
1374
1375/************************************************************************/
1379{
1380 return support_initialized;
1381}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
static bool initialized
Definition effects.c:42
char * internal_to_local_string_malloc(const char *text)
char * local_to_internal_string_buffer(const char *text, char *buf, size_t bufsz)
#define _(String)
Definition fcintl.h:67
void fc_allocate_mutex(fc_mutex *mutex)
void fc_release_mutex(fc_mutex *mutex)
void fc_destroy_mutex(fc_mutex *mutex)
void fc_init_mutex(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:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
#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:125
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
bool fc_isalpha(char c)
Definition support.c:1216
int fc_gethostname(char *buf, size_t len)
Definition support.c:1016
bool fc_isprint(char c)
Definition support.c:1238
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
static bool support_initialized
Definition support.c:114
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:297
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
void fc_usleep(unsigned long usec)
Definition support.c:640
void fc_support_init(void)
Definition support.c:1338
bool fc_isspace(char c)
Definition support.c:1249
const char * fc_strerror(fc_errno err)
Definition support.c:610
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:832
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:439
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:731
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1310
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:896
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:506
static void fc_strAPI_free(void)
Definition support.c:174
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1144
static fc_mutex localtime_mutex
Definition support.c:127
static UChar * icu_buffer1
Definition support.c:117
fc_mutex icu_buffer_mutex
Definition support.c:119
fc_errno fc_get_errno(void)
Definition support.c:593
void fc_support_free(void)
Definition support.c:1356
void remove_escapes(const char *str, bool full_escapes, char *buf, size_t buf_len)
Definition support.c:333
bool fc_isdigit(char c)
Definition support.c:1227
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:472
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:575
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1129
bool fc_isalnum(char c)
Definition support.c:1205
bool fc_isupper(char c)
Definition support.c:1260
const char * fc_basename(const char *path)
Definition support.c:1296
static void icu_buffers_initial(void)
Definition support.c:133
static char * vsnprintf_buf
Definition support.c:122
static int icu_buffer_uchars
Definition support.c:116
int fc_strncasequotecmp(const char *str0, const char *str1, size_t n)
Definition support.c:379
static fc_mutex vsnprintf_mutex
Definition support.c:123
static void fc_strAPI_init(void)
Definition support.c:163
size_t effectivestrlenquote(const char *str)
Definition support.c:359
char fc_tolower(char c)
Definition support.c:1282
static void icu_buffers_increase(void)
Definition support.c:149
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1326
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:486
int fc_remove(const char *filename)
Definition support.c:556
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
char * fc_strrep_resize(char *str, size_t *len, const char *search, const char *replace)
Definition support.c:693
static UChar * icu_buffer2
Definition support.c:118
bool are_support_services_available(void)
Definition support.c:1378
char fc_toupper(char c)
Definition support.c:1271
#define VSNP_BUF_SIZE
Definition support.c:895
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define fc__fallthrough
Definition support.h:109
int fc_errno
Definition support.h:115