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
115
116static int icu_buffer_uchars = 0;
120
121#ifndef HAVE_WORKING_VSNPRINTF
122static char *vsnprintf_buf = NULL;
124#endif /* HAVE_WORKING_VSNPRINTF */
125
126#ifndef HAVE_LOCALTIME_R
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;
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) {
182 }
184}
185
186/************************************************************************/
189int fc_strcasecmp(const char *str0, const char *str1)
190{
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) {
213
216
217 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
218 * the buffers we were using */
221 } else {
223 }
224 }
225
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{
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) {
262
265
266 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
267 * the buffers we were using */
270 } else {
272 }
273 }
274
275 if (len0 > n) {
276 len0 = n;
277 }
278 if (len1 > n) {
279 len1 = n;
280 }
281
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
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/************************************************************************/
380int 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/************************************************************************/
440char *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 }
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/************************************************************************/
473int 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/************************************************************************/
487int 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/************************************************************************/
507FILE *fc_fopen(const char *filename, const char *opentype)
508{
509 FILE *result;
510
511#ifdef FREECIV_MSWINDOWS
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
527#endif /* FREECIV_MSWINDOWS */
528
529 return result;
530}
531
532/************************************************************************/
536#ifdef FREECIV_HAVE_LIBZ
537gzFile fc_gzopen(const char *filename, const char *opentype)
538{
539#ifdef FREECIV_MSWINDOWS
540 gzFile result;
543
546 return result;
547#else /* FREECIV_MSWINDOWS */
548 return gzopen(filename, opentype);
549#endif /* FREECIV_MSWINDOWS */
550}
551#endif /* FREECIV_HAVE_LIBZ */
552
553/************************************************************************/
557int fc_remove(const char *filename)
558{
559#ifdef FREECIV_MSWINDOWS
560 int result;
563
566 return result;
567#else /* FREECIV_MSWINDOWS */
568 return remove(filename);
569#endif /* FREECIV_MSWINDOWS */
570}
571
572/************************************************************************/
576int fc_stat(const char *filename, struct stat *buf)
577{
578#ifdef FREECIV_MSWINDOWS
579 int result;
582
585 return result;
586#else /* FREECIV_MSWINDOWS */
587 return stat(filename, buf);
588#endif /* FREECIV_MSWINDOWS */
589}
590
591/************************************************************************/
595{
596#ifdef FREECIV_MSWINDOWS
597 return GetLastError();
598#else /* FREECIV_MSWINDOWS */
599 return errno;
600#endif /* FREECIV_MSWINDOWS */
601}
602
603/************************************************************************/
612{
613#ifdef FREECIV_MSWINDOWS
614 static char buf[256];
615
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
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/************************************************************************/
641void 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 */
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/************************************************************************/
695char *fc_strrep_resize(char *str, size_t *len, const char *search,
696 const char *replace)
697{
698 size_t len_max;
699
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;
713 }
714
715#ifndef FREECIV_NDEBUG
716 bool success =
717#endif
719
720 /* Should never happen */
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/************************************************************************/
734bool 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
741
742 if (search == NULL || replace == NULL) {
743 return TRUE;
744 }
745
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);
764 s = p + len_replace;
765 }
766
767 return TRUE;
768}
769
770/************************************************************************/
791size_t fc_strlcpy(char *dest, const char *src, size_t n)
792{
793 bool enough_mem = FALSE;
794 int slen;
795 int dlen;
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) {
804 }
805
807
808 while (!enough_mem) {
810
811 /* No need to handle U_STRING_NOT_TERMINATED_WARNING here as there's '0' after
812 * the buffers we were using */
816 } else {
818 }
819 }
820
821 u_strToUTF8(dest, n - 1, &dlen, icu_buffer1, slen, &err_code);
822
824
825 dest[n - 1] = '\0';
826
827 return dlen;
828}
829
830/************************************************************************/
836size_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)
900int 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);
926 }
927
929
930 if (vsnprintf_buf == NULL) {
932
933 if (vsnprintf_buf == NULL) {
934 fprintf(stderr, "Could not allocate %i bytes for vsnprintf() "
935 "replacement.", VSNP_BUF_SIZE);
937
939 }
940 }
941
942 vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0';
943
944#ifdef HAVE_VSNPRINTF
946#else
947 vsprintf(vsnprintf_buf, format, ap);
948#endif /* HAVE_VSNPRINTF */
949
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) {
959 } else {
960 memcpy(str, vsnprintf_buf, n - 1);
961 str[n - 1] = '\0';
962 }
963
965
966 return len;
967 }
968#endif /* HAVE_WORKING_VSNPRINTF */
969}
970
971/************************************************************************/
974int 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/************************************************************************/
1000int 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/************************************************************************/
1021int 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
1042
1043/************************************************************************/
1047{
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
1067 return;
1068 }
1069
1070 console_buf[0] = '\0';
1072 NULL, 0, NULL);
1073#else /* FREECIV_MSWINDOWS */
1074 static bool initialized = FALSE;
1075
1076 if (!initialized) {
1077 initialized = TRUE;
1078#ifdef HAVE_FILENO
1080#endif
1081 }
1082#endif /* FREECIV_MSWINDOWS */
1083}
1084
1085/************************************************************************/
1092char *fc_read_console(void)
1093{
1094#ifdef FREECIV_MSWINDOWS
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') {
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/************************************************************************/
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/************************************************************************/
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/************************************************************************/
1210bool 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/************************************************************************/
1221bool 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/************************************************************************/
1232bool 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/************************************************************************/
1243bool 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/************************************************************************/
1254bool 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/************************************************************************/
1265bool 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/************************************************************************/
1276char 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/************************************************************************/
1287char 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/************************************************************************/
1301const 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/************************************************************************/
1315struct 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 */
1321 memcpy(result, localtime(timep), sizeof(struct tm));
1323
1324 return result;
1325#endif /* HAVE_LOCALTIME_R */
1326}
1327
1328/************************************************************************/
1331int 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/************************************************************************/
1344{
1346
1347#ifndef HAVE_WORKING_VSNPRINTF
1349#endif /* HAVE_WORKING_VSNPRINTF */
1350
1351#ifndef HAVE_LOCALTIME_R
1353#endif /* HAVE_LOCALTIME_R */
1354
1356}
1357
1358/************************************************************************/
1362{
1364
1365#ifndef HAVE_WORKING_VSNPRINTF
1366 if (vsnprintf_buf != NULL) {
1369 }
1371#endif /* HAVE_WORKING_VSNPRINTF */
1372
1373#ifndef HAVE_LOCALTIME_R
1375#endif /* HAVE_LOCALTIME_R */
1376
1378}
1379
1380/************************************************************************/
1384{
1385 return support_initialized;
1386}
#define str
Definition astring.c:76
#define n
Definition astring.c:77
char * incite_cost
Definition comments.c:75
static bool initialized
Definition effects.c:42
char * internal_to_local_string_malloc(const char *text)
char * local_to_internal_string_buffer(const char *text, char *buf, size_t bufsz)
#define _(String)
Definition fcintl.h:67
void fc_mutex_allocate(fc_mutex *mutex)
void fc_mutex_init(fc_mutex *mutex)
void fc_mutex_release(fc_mutex *mutex)
void fc_mutex_destroy(fc_mutex *mutex)
const char * name
Definition inputfile.c:127
get_token_fn_t func
Definition inputfile.c:128
#define fc_assert(condition)
Definition log.h: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:127
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
bool fc_isalpha(char c)
Definition support.c:1221
int fc_gethostname(char *buf, size_t len)
Definition support.c:1021
bool fc_isprint(char c)
Definition support.c:1243
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
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:641
void fc_support_init(void)
Definition support.c:1343
bool fc_isspace(char c)
Definition support.c:1254
const char * fc_strerror(fc_errno err)
Definition support.c:611
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:836
char * fc_strcasestr(const char *haystack, const char *needle)
Definition support.c:440
bool fc_strrep(char *str, size_t len, const char *search, const char *replace)
Definition support.c:734
struct tm * fc_localtime(const time_t *timep, struct tm *result)
Definition support.c:1315
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:1000
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:900
FILE * fc_fopen(const char *filename, const char *opentype)
Definition support.c:507
static void fc_strAPI_free(void)
Definition support.c:174
int fc_break_lines(char *str, size_t desired_len)
Definition support.c:1149
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:594
void fc_support_free(void)
Definition support.c:1361
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:1232
int fc_strcoll(const char *str0, const char *str1)
Definition support.c:473
int fc_stat(const char *filename, struct stat *buf)
Definition support.c:576
bool is_reg_file_for_access(const char *name, bool write_access)
Definition support.c:1134
bool fc_isalnum(char c)
Definition support.c:1210
bool fc_isupper(char c)
Definition support.c:1265
const char * fc_basename(const char *path)
Definition support.c:1301
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:380
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:1287
static void icu_buffers_increase(void)
Definition support.c:149
int fc_at_quick_exit(void(*func)(void))
Definition support.c:1331
int fc_stricoll(const char *str0, const char *str1)
Definition support.c:487
int fc_remove(const char *filename)
Definition support.c:557
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:695
static UChar * icu_buffer2
Definition support.c:118
bool are_support_services_available(void)
Definition support.c:1383
char fc_toupper(char c)
Definition support.c:1276
#define VSNP_BUF_SIZE
Definition support.c:899
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define fc__fallthrough
Definition support.h:119
int fc_errno
Definition support.h:140