Freeciv-3.2
Loading...
Searching...
No Matches
featured_text.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#ifdef HAVE_CONFIG_H
14#include <fc_config.h>
15#endif
16
17#include <stdarg.h>
18#include <string.h>
19
20/* utility */
21#include "fcintl.h"
22#include "log.h"
23#include "mem.h"
24#include "shared.h"
25#include "support.h"
26
27/* common */
28#include "city.h"
29#include "combat.h"
30#include "game.h"
31#include "map.h"
32#include "tile.h"
33#include "unit.h"
34
35#include "featured_text.h"
36
37#define SEQ_START '['
38#define SEQ_STOP ']'
39#define SEQ_END '/'
40
41#define MAX_LEN_STR 32
42#define log_featured_text log_verbose
43
44#define text_tag_list_rev_iterate(tags, ptag) \
45 TYPED_LIST_ITERATE_REV(struct text_tag, tags, ptag)
46#define text_tag_list_rev_iterate_end LIST_ITERATE_REV_END
47
48/* The text_tag structure. See documentation in featured_text.h. */
49struct text_tag {
50 enum text_tag_type type; /* The type of the tag. */
51 ft_offset_t start_offset; /* The start offset (in bytes). */
52 ft_offset_t stop_offset; /* The stop offset (in bytes). */
53 union {
54 struct { /* TTT_COLOR only. */
55 char foreground[MAX_LEN_STR]; /* foreground color name. */
56 char background[MAX_LEN_STR]; /* background color name. */
58 struct { /* TTT_LINK only. */
59 enum text_link_type type; /* The target type of the link. */
60 int id; /* The id of linked object. */
61 char name[MAX_LEN_STR]; /* A string to indentify the link. */
63 };
64};
65
67 ST_START, /* e.g. [sequence]. */
68 ST_STOP, /* e.g. [/sequence]. */
69 ST_SINGLE /* e.g. [sequence/]. */
70};
71
72/* Predefined colors. */
74
75const struct ft_color ftc_warning = FT_COLOR("#FF0000", NULL);
76const struct ft_color ftc_log = FT_COLOR("#7F7F7F", NULL);
77const struct ft_color ftc_server = FT_COLOR("#8B0000", NULL);
78const struct ft_color ftc_client = FT_COLOR("#EF7F00", NULL);
79const struct ft_color ftc_editor = FT_COLOR("#0000FF", NULL);
80const struct ft_color ftc_command = FT_COLOR("#006400", NULL);
82const struct ft_color ftc_server_prompt = FT_COLOR("#FF0000", "#BEBEBE");
83const struct ft_color ftc_player_lost = FT_COLOR("#FFFFFF", "#000000");
84const struct ft_color ftc_game_start = FT_COLOR("#00FF00", "#115511");
85
86const struct ft_color ftc_chat_public = FT_COLOR("#00008B", NULL);
87const struct ft_color ftc_chat_ally = FT_COLOR("#551166", NULL);
88const struct ft_color ftc_chat_private = FT_COLOR("#A020F0", NULL);
89const struct ft_color ftc_chat_luaconsole = FT_COLOR("#006400", NULL);
90
91const struct ft_color ftc_vote_public = FT_COLOR("#FFFFFF", "#AA0000");
92const struct ft_color ftc_vote_team = FT_COLOR("#FFFFFF", "#5555CC");
93const struct ft_color ftc_vote_passed = FT_COLOR("#006400", "#AAFFAA");
94const struct ft_color ftc_vote_failed = FT_COLOR("#8B0000", "#FFAAAA");
95const struct ft_color ftc_vote_yes = FT_COLOR("#000000", "#C8FFD5");
96const struct ft_color ftc_vote_no = FT_COLOR("#000000", "#FFD2D2");
97const struct ft_color ftc_vote_abstain = FT_COLOR("#000000", "#E8E8E8");
98
99const struct ft_color ftc_luaconsole_input = FT_COLOR("#2B008B", NULL);
100const struct ft_color ftc_luaconsole_error = FT_COLOR("#FF0000", NULL);
101const struct ft_color ftc_luaconsole_warn = FT_COLOR("#CF2020", NULL);
102const struct ft_color ftc_luaconsole_normal = FT_COLOR("#006400", NULL);
103const struct ft_color ftc_luaconsole_verbose = FT_COLOR("#B8B8B8", NULL);
104const struct ft_color ftc_luaconsole_debug = FT_COLOR("#B87676", NULL);
105
106/**********************************************************************/
110static const char *text_tag_type_name(enum text_tag_type type)
111{
112 switch (type) {
113 case TTT_BOLD:
114 return "bold";
115 case TTT_ITALIC:
116 return "italic";
117 case TTT_STRIKE:
118 return "strike";
119 case TTT_UNDERLINE:
120 return "underline";
121 case TTT_COLOR:
122 return "color";
123 case TTT_LINK:
124 return "link";
125 };
126 /* Don't handle the default case to be warned if a new value was added. */
127 return NULL;
128}
129
130/**********************************************************************/
135{
136 switch (type) {
137 case TTT_BOLD:
138 return "b";
139 case TTT_ITALIC:
140 return "i";
141 case TTT_STRIKE:
142 return "s";
143 case TTT_UNDERLINE:
144 return "u";
145 case TTT_COLOR:
146 return "c";
147 case TTT_LINK:
148 return "l";
149 };
150 /* Don't handle the default case to be warned if a new value was added. */
151 return NULL;
152}
153
154/**********************************************************************/
158{
159 switch (type) {
160 case TLT_CITY:
161 return "city";
162 case TLT_TILE:
163 return "tile";
164 case TLT_UNIT:
165 return "unit";
166 };
167 /* Don't handle the default case to be warned if a new value was added. */
168 return NULL;
169}
170
171/**********************************************************************/
175static bool find_option(const char *buf_in, const char *option,
176 char *buf_out, size_t write_len)
177{
178 size_t option_len = strlen(option);
179
180 while (*buf_in != '\0') {
181 while (fc_isspace(*buf_in) && *buf_in != '\0') {
182 buf_in++;
183 }
184
185 if (0 == strncasecmp(buf_in, option, option_len)) {
186 /* This is this one. */
188
189 while ((fc_isspace(*buf_in) || *buf_in == '=') && *buf_in != '\0') {
190 buf_in++;
191 }
192 if (*buf_in == '"') {
193 /* Quote case. */
194 const char *end = strchr(++buf_in, '"');
195
196 if (!end) {
197 return FALSE;
198 }
199 if (end - buf_in + 1 > 0) {
201 } else {
202 *buf_out = '\0';
203 }
204 return TRUE;
205 } else {
206 while (fc_isalnum(*buf_in) && write_len > 1) {
207 *buf_out++ = *buf_in++;
208 write_len--;
209 }
210 *buf_out = '\0';
211 return TRUE;
212 }
213 }
214 buf_in++;
215 }
216
217 return FALSE;
218}
219
220/**********************************************************************/
225 enum text_tag_type type,
226 ft_offset_t start_offset,
227 const char *sequence)
228{
229 ptag->type = type;
230 ptag->start_offset = start_offset;
231 ptag->stop_offset = FT_OFFSET_UNSET;
232
233 switch (type) {
234 case TTT_BOLD:
235 case TTT_ITALIC:
236 case TTT_STRIKE:
237 case TTT_UNDERLINE:
238 return TRUE;
239 case TTT_COLOR:
240 {
241 if (!find_option(sequence, "foreground", ptag->color.foreground,
242 sizeof(ptag->color.foreground))
243 && !find_option(sequence, "fg", ptag->color.foreground,
244 sizeof(ptag->color.foreground))) {
245 ptag->color.foreground[0] = '\0';
246 }
247 if (!find_option(sequence, "background", ptag->color.background,
248 sizeof(ptag->color.background))
249 && !find_option(sequence, "bg", ptag->color.background,
250 sizeof(ptag->color.background))) {
251 ptag->color.background[0] = '\0';
252 }
253 }
254 return TRUE;
255 case TTT_LINK:
256 {
257 char buf[64];
258 const char *name;
259 int i;
260
261 if (!find_option(sequence, "target", buf, sizeof(buf))
262 && !find_option(sequence, "tgt", buf, sizeof(buf))) {
263 log_featured_text("text_tag_init_from_sequence(): "
264 "target link type not set.");
265 return FALSE;
266 }
267
268 ptag->link.type = -1;
269 for (i = 0; (name = text_link_type_name(i)); i++) {
270 if (0 == fc_strncasecmp(buf, name, strlen(name))) {
271 ptag->link.type = i;
272 break;
273 }
274 }
275 if (ptag->link.type == -1) {
276 log_featured_text("text_tag_init_from_sequence(): "
277 "target link type not supported (\"%s\").", buf);
278 return FALSE;
279 }
280
281 switch (ptag->link.type) {
282 case TLT_CITY:
283 {
284 if (!find_option(sequence, "id", buf, sizeof(buf))) {
285 log_featured_text("text_tag_init_from_sequence(): "
286 "city link without id.");
287 return FALSE;
288 }
289 if (!str_to_int(buf, &ptag->link.id)) {
290 log_featured_text("text_tag_init_from_sequence(): "
291 "city link without valid id (\"%s\").", buf);
292 return FALSE;
293 }
294
295 if (!find_option(sequence, "name", ptag->link.name,
296 sizeof(ptag->link.name))) {
297 /* Set something as name. */
298 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
299 "CITY_ID%d", ptag->link.id);
300 }
301 }
302 return TRUE;
303 case TLT_TILE:
304 {
305 struct tile *ptile;
306 int x, y;
307
308 if (!find_option(sequence, "x", buf, sizeof(buf))) {
309 log_featured_text("text_tag_init_from_sequence(): "
310 "tile link without x coordinate.");
311 return FALSE;
312 }
313 if (!str_to_int(buf, &x)) {
314 log_featured_text("text_tag_init_from_sequence(): "
315 "tile link without valid x coordinate "
316 "(\"%s\").", buf);
317 return FALSE;
318 }
319
320 if (!find_option(sequence, "y", buf, sizeof(buf))) {
321 log_featured_text("text_tag_init_from_sequence(): "
322 "tile link without y coordinate.");
323 return FALSE;
324 }
325 if (!str_to_int(buf, &y)) {
326 log_featured_text("text_tag_init_from_sequence(): "
327 "tile link without valid y coordinate "
328 "(\"%s\").", buf);
329 return FALSE;
330 }
331
332 ptile = map_pos_to_tile(&(wld.map), x, y);
333 if (!ptile) {
334 log_featured_text("text_tag_init_from_sequence(): "
335 "(%d, %d) are not valid coordinates "
336 "in this game.", x, y);
337 return FALSE;
338 }
339 ptag->link.id = tile_index(ptile);
340 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
341 "(%d, %d)", TILE_XY(ptile));
342 }
343 return TRUE;
344 case TLT_UNIT:
345 {
346 if (!find_option(sequence, "id", buf, sizeof(buf))) {
347 log_featured_text("text_tag_init_from_sequence(): "
348 "unit link without id.");
349 return FALSE;
350 }
351 if (!str_to_int(buf, &ptag->link.id)) {
352 log_featured_text("text_tag_init_from_sequence(): "
353 "unit link without valid id (\"%s\").", buf);
354 return FALSE;
355 }
356
357 if (!find_option(sequence, "name", ptag->link.name,
358 sizeof(ptag->link.name))) {
359 /* Set something as name. */
360 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
361 "UNIT_ID%d", ptag->link.id);
362 }
363 }
364 return TRUE;
365 };
366 }
367 };
368 return FALSE;
369}
370
371/**********************************************************************/
389 ft_offset_t start_offset, ft_offset_t stop_offset,
390 va_list args)
391{
392 ptag->type = type;
393 ptag->start_offset = start_offset;
394 ptag->stop_offset = stop_offset;
395
396 switch (type) {
397 case TTT_BOLD:
398 case TTT_ITALIC:
399 case TTT_STRIKE:
400 case TTT_UNDERLINE:
401 return TRUE;
402 case TTT_COLOR:
403 {
404 const struct ft_color color = va_arg(args, struct ft_color);
405
406 if ((NULL == color.foreground || '\0' == color.foreground[0])
407 && (NULL == color.background || '\0' == color.background[0])) {
408 return FALSE; /* No color at all. */
409 }
410
411 if (NULL != color.foreground && '\0' != color.foreground[0]) {
412 sz_strlcpy(ptag->color.foreground, color.foreground);
413 } else {
414 ptag->color.foreground[0] = '\0';
415 }
416
417 if (NULL != color.background && '\0' != color.background[0]) {
418 sz_strlcpy(ptag->color.background, color.background);
419 } else {
420 ptag->color.background[0] = '\0';
421 }
422 }
423 return TRUE;
424 case TTT_LINK:
425 {
426 ptag->link.type = va_arg(args, enum text_link_type);
427 switch (ptag->link.type) {
428 case TLT_CITY:
429 {
430 struct city *pcity = va_arg(args, struct city *);
431
432 if (!pcity) {
433 return FALSE;
434 }
435 ptag->link.id = pcity->id;
436 sz_strlcpy(ptag->link.name, city_name_get(pcity));
437 }
438 return TRUE;
439 case TLT_TILE:
440 {
441 struct tile *ptile = va_arg(args, struct tile *);
442
443 if (!ptile) {
444 return FALSE;
445 }
446 ptag->link.id = tile_index(ptile);
447 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
448 "(%d, %d)", TILE_XY(ptile));
449 }
450 return TRUE;
451 case TLT_UNIT:
452 {
453 struct unit *punit = va_arg(args, struct unit *);
454
455 if (!punit) {
456 return FALSE;
457 }
458 ptag->link.id = punit->id;
460 }
461 return TRUE;
462 };
463 }
464 };
465 return FALSE;
466}
467
468/**********************************************************************/
471static size_t text_tag_start_sequence(const struct text_tag *ptag,
472 char *buf, size_t len)
473{
474 switch (ptag->type) {
475 case TTT_BOLD:
476 case TTT_ITALIC:
477 case TTT_STRIKE:
478 case TTT_UNDERLINE:
479 return fc_snprintf(buf, len, "%c%s%c", SEQ_START,
481 case TTT_COLOR:
482 {
483 size_t ret = fc_snprintf(buf, len, "%c%s", SEQ_START,
485
486 if (ptag->color.foreground[0] != '\0') {
487 ret += fc_snprintf(buf + ret, len - ret, " fg=\"%s\"",
488 ptag->color.foreground);
489 }
490 if (ptag->color.background[0] != '\0') {
491 ret += fc_snprintf(buf + ret, len - ret, " bg=\"%s\"",
492 ptag->color.background);
493 }
494 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
495 }
496 case TTT_LINK:
497 {
498 size_t ret = fc_snprintf(buf, len, "%c%s tgt=\"%s\"", SEQ_START,
500 text_link_type_name(ptag->link.type));
501
502 switch (ptag->link.type) {
503 case TLT_CITY:
504 {
505 struct city *pcity = game_city_by_number(ptag->link.id);
506
507 if (pcity) {
508 ret += fc_snprintf(buf + ret, len - ret,
509 " id=%d name=\"%s\"",
510 pcity->id, city_name_get(pcity));
511 } else {
512 ret += fc_snprintf(buf + ret, len - ret,
513 " id=%d", ptag->link.id);
514 }
515 }
516 break;
517 case TLT_TILE:
518 {
519 struct tile *ptile = index_to_tile(&(wld.map), ptag->link.id);
520
521 if (ptile) {
522 ret += fc_snprintf(buf + ret, len - ret,
523 " x=%d y=%d", TILE_XY(ptile));
524 } else {
525 ret += fc_snprintf(buf + ret, len - ret,
526 " id=%d", ptag->link.id);
527 }
528 }
529 break;
530 case TLT_UNIT:
531 {
532 struct unit *punit = game_unit_by_number(ptag->link.id);
533
534 if (punit) {
535 ret += fc_snprintf(buf + ret, len - ret,
536 " id=%d name=\"%s\"",
538 } else {
539 ret += fc_snprintf(buf + ret, len - ret,
540 " id=%d", ptag->link.id);
541 }
542 }
543 break;
544 };
545
546 if (ptag->stop_offset == ptag->start_offset) {
547 /* This is a single sequence like [link ... /]. */
548 ret += fc_snprintf(buf + ret, len - ret, "%c", SEQ_END);
549 }
550
551 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
552 }
553 };
554 return 0;
555}
556
557/**********************************************************************/
560static size_t text_tag_stop_sequence(const struct text_tag *ptag,
561 char *buf, size_t len)
562{
563 if (ptag->type == TTT_LINK && ptag->stop_offset == ptag->start_offset) {
564 /* Should be already finished. */
565 return 0;
566 }
567
568 return fc_snprintf(buf, len, "%c%c%s%c", SEQ_START, SEQ_END,
570}
571
572/**********************************************************************/
575static size_t text_tag_replace_text(const struct text_tag *ptag,
576 char *buf, size_t len,
578{
579 if (ptag->type != TTT_LINK) {
580 return 0;
581 }
582
583 if (replace_link_text) {
584 /* The client might check if this should be updated or translated. */
585 switch (ptag->link.type) {
586 case TLT_CITY:
587 {
588 struct city *pcity = game_city_by_number(ptag->link.id);
589
590 /* Note that if city_tile(pcity) is NULL, then it is probably an
591 * invisible city (see client/packhand.c). Then, we don't
592 * use the current city name which is usually not complete,
593 * a dumb string using the city id. */
594 if (NULL != pcity && NULL != city_tile(pcity)) {
595 return fc_snprintf(buf, len, "%s", city_name_get(pcity));
596 }
597 }
598 break;
599 case TLT_TILE:
600 break;
601 case TLT_UNIT:
602 {
603 struct unit *punit = game_unit_by_number(ptag->link.id);
604
605 if (punit) {
607 }
608 }
609 break;
610 };
611 }
612
613 if (ptag->link.type == TLT_UNIT) {
614 /* Attempt to translate the link name (it should be a unit type name). */
615 return fc_snprintf(buf, len, "%s", _(ptag->link.name));
616 } else {
617 return fc_snprintf(buf, len, "%s", ptag->link.name);
618 }
619}
620
621/**********************************************************************/
641 ...)
642{
643 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
644 va_list args;
645 bool ok;
646
647 va_start(args, stop_offset);
649 va_end(args);
650
651 if (ok) {
652 return ptag;
653 } else {
654 free(ptag);
655 return NULL;
656 }
657}
658
659/**********************************************************************/
663struct text_tag *text_tag_copy(const struct text_tag *ptag)
664{
665 struct text_tag *pnew_tag;
666
667 if (!ptag) {
668 return NULL;
669 }
670
671 pnew_tag = fc_malloc(sizeof(struct text_tag));
672 *pnew_tag = *ptag;
673
674 return pnew_tag;
675}
676
677/**********************************************************************/
681{
682 free(ptag);
683}
684
685/**********************************************************************/
689{
690 return ptag->type;
691}
692
693/**********************************************************************/
697{
698 return ptag->start_offset;
699}
700
701/**********************************************************************/
705{
706 return ptag->stop_offset;
707}
708
709/**********************************************************************/
713const char *text_tag_color_foreground(const struct text_tag *ptag)
714{
715 if (ptag->type != TTT_COLOR) {
716 log_error("text_tag_color_foreground(): incompatible tag type.");
717 return NULL;
718 }
719
720 return ptag->color.foreground;
721}
722
723/**********************************************************************/
727const char *text_tag_color_background(const struct text_tag *ptag)
728{
729 if (ptag->type != TTT_COLOR) {
730 log_error("text_tag_color_background(): incompatible tag type.");
731 return NULL;
732 }
733
734 return ptag->color.background;
735}
736
737/**********************************************************************/
742{
743 if (ptag->type != TTT_LINK) {
744 log_error("text_tag_link_type(): incompatible tag type.");
745 return -1;
746 }
747
748 return ptag->link.type;
749}
750
751/**********************************************************************/
757{
758 if (ptag->type != TTT_LINK) {
759 log_error("text_tag_link_id(): incompatible tag type.");
760 return -1;
761 }
762
763 return ptag->link.id;
764}
765
766/**********************************************************************/
770static size_t extract_sequence_text(const char *featured_text,
771 char *buf, size_t len,
773 enum text_tag_type *type)
774{
775 const char *buf_in = featured_text;
776 const char *stop = strchr(buf_in, SEQ_STOP);
777 const char *end = stop;
778 const char *name;
779 size_t type_len;
780 size_t name_len;
781 int i;
782
783 if (!stop) {
784 return 0; /* Not valid. */
785 }
786
787 /* Check sequence type. */
788 for (buf_in++; fc_isspace(*buf_in); buf_in++);
789
790 if (*buf_in == SEQ_END) {
791 *seq_type = ST_STOP;
792 buf_in++;
793 } else {
794 for (end--; fc_isspace(*end); end--);
795
796 if (*end == SEQ_END) {
798
799 for (end--; fc_isspace(*end); end--);
800 } else {
802 }
803 }
804
805 while (fc_isspace(*buf_in)) {
806 buf_in++;
807 }
808
809 /* Check the length of the type name. */
810 for (name = buf_in; name < stop; name++) {
811 if (!fc_isalpha(*name)) {
812 break;
813 }
814 }
815 type_len = name - buf_in;
816
817 *type = -1;
818 for (i = 0; (name = text_tag_type_name(i)); i++) {
821 buf_in += name_len;
822 *type = i;
823 break;
824 }
825 }
826 if (*type == -1) {
827 /* Try with short names. */
828 for (i = 0; (name = text_tag_type_short_name(i)); i++) {
830 if (name_len == type_len
831 && 0 == fc_strncasecmp(name, buf_in, name_len)) {
832 buf_in += name_len;
833 *type = i;
834 break;
835 }
836 }
837 if (*type == -1) {
838 return 0; /* Not valid. */
839 }
840 }
841
842 while (fc_isspace(*buf_in)) {
843 buf_in++;
844 }
845
846 if (end - buf_in + 2 > 0) {
847 fc_strlcpy(buf, buf_in, MIN(end - buf_in + 2, len));
848 } else {
849 buf[0] = '\0';
850 }
851 return stop - featured_text + 1;
852}
853
854
855/**********************************************************************/
865 char *plain_text, size_t plain_text_len,
866 struct text_tag_list **tags,
868{
869 const char *text_in = featured_text;
870 char *text_out = plain_text;
872
873 if (tags) {
874 *tags = text_tag_list_new();
875 }
876
877 while (*text_in != '\0' && text_out_len > 1) {
878 if (SEQ_START == *text_in) {
879 /* Escape sequence... */
880 char buf[text_out_len];
882 enum text_tag_type type;
884 &seq_type, &type);
885
886 if (len > 0) {
887 /* Looks a valid sequence. */
888 text_in += len;
889 switch (seq_type) {
890 case ST_START:
891 if (tags) {
892 /* Create a new tag. */
893 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
894
896 text_out - plain_text, buf)) {
898 } else {
900 log_featured_text("Couldn't create a text tag with \"%s\".",
901 buf);
902 }
903 }
904 break;
905 case ST_STOP:
906 if (tags) {
907 /* Set the stop offset. */
908 struct text_tag *ptag = NULL;
909
910 /* Look up on reversed order. */
912 if (piter->type == type
913 && piter->stop_offset == FT_OFFSET_UNSET) {
914 ptag = piter;
915 break;
916 }
918
919 if (ptag) {
921 } else {
922 log_featured_text("Extra text tag end for \"%s\".",
924 }
925 }
926 break;
927 case ST_SINGLE:
928 {
929 /* In this case, we replace the sequence by some text. */
930 struct text_tag tag;
931
933 text_out - plain_text, buf)) {
934 log_featured_text("Couldn't create a text tag with \"%s\".",
935 buf);
936 } else {
939 text_out += len;
940 text_out_len -= len;
941 if (tags) {
942 /* Set it in the list. */
943 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
944
945 *ptag = tag;
948 }
949 }
950 }
951 break;
952 };
953 } else {
954 *text_out++ = *text_in++;
955 text_out_len--;
956 }
957 } else {
958 *text_out++ = *text_in++;
959 text_out_len--;
960 }
961 }
962 if (tags) {
963 /* Auto-stop all tags opened and not closed */
965 if (ptag->stop_offset == FT_OFFSET_UNSET) {
966 ptag->stop_offset = text_out - plain_text;
967 }
969 }
970 *text_out = '\0';
971
973}
974
975/**********************************************************************/
994 char *featured_text, size_t featured_text_len,
998 ...)
999{
1000 struct text_tag tag;
1001 size_t len, total_len = 0;
1002 va_list args;
1003
1007 && stop_offset < start_offset)) {
1008 log_featured_text("featured_text_apply_tag(): invalid offsets.");
1009 return 0;
1010 }
1011
1012 va_start(args, stop_offset);
1013 if (!text_tag_initv(&tag, tag_type, start_offset, stop_offset, args)) {
1014 va_end(args);
1015 return 0;
1016 }
1017 va_end(args);
1018
1019 if (start_offset > 0) {
1020 /* First part: before the sequence. */
1021 len = 0;
1022 while (len < start_offset
1023 && *text_source != '\0'
1024 && featured_text_len > 1) {
1025 *featured_text++ = *text_source++;
1027 len++;
1028 }
1029 total_len += len;
1030 }
1031
1032 /* Start sequence. */
1034 total_len += len;
1035 featured_text += len;
1037
1038 /* Second part: between the sequences. */
1039 len = start_offset;
1040 while (len < stop_offset
1041 && *text_source != '\0'
1042 && featured_text_len > 1) {
1043 *featured_text++ = *text_source++;
1045 len++;
1046 }
1047 total_len += len;
1048
1049 /* Stop sequence. */
1051 total_len += len;
1052 featured_text += len;
1054
1055 /* Third part: after the sequence. */
1056 while (*text_source != '\0'
1057 && featured_text_len > 1) {
1058 *featured_text++ = *text_source++;
1060 total_len++;
1061 }
1062 *featured_text = '\0';
1063
1064 return total_len;
1065}
1066
1067/**********************************************************************/
1072const char *city_link(const struct city *pcity)
1073{
1074 static char buf[MAX_LEN_LINK];
1075
1076 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1079 city_name_get(pcity), SEQ_END, SEQ_STOP);
1080 return buf;
1081}
1082
1083/**********************************************************************/
1089const char *city_tile_link(const struct city *pcity)
1090{
1091 static char buf[MAX_LEN_LINK];
1093
1094 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1096 TILE_XY(city_tile(pcity)), SEQ_STOP, city_name_get(pcity),
1098 return buf;
1099}
1100
1101/**********************************************************************/
1106const char *tile_link(const struct tile *ptile)
1107{
1108 static char buf[MAX_LEN_LINK];
1109
1110 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d %c%c",
1113 SEQ_END, SEQ_STOP);
1114 return buf;
1115}
1116
1117/**********************************************************************/
1122const char *unit_link(const struct unit *punit)
1123{
1124 static char buf[MAX_LEN_LINK];
1125
1126 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1130 return buf;
1131}
1132
1133/**********************************************************************/
1139const char *unit_tile_link(const struct unit *punit)
1140{
1141 static char buf[MAX_LEN_LINK];
1143
1144 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1149 return buf;
1150}
const char * city_name_get(const struct city *pcity)
Definition city.c:1137
#define city_tile(_pcity_)
Definition city.h:564
char * incite_cost
Definition comments.c:75
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
char * tag_name
Definition events.c:77
#define _(String)
Definition fcintl.h:67
static bool text_tag_init_from_sequence(struct text_tag *ptag, enum text_tag_type type, ft_offset_t start_offset, const char *sequence)
const struct ft_color ftc_chat_private
size_t featured_text_apply_tag(const char *text_source, char *featured_text, size_t featured_text_len, enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
const struct ft_color ftc_luaconsole_debug
static bool find_option(const char *buf_in, const char *option, char *buf_out, size_t write_len)
const struct ft_color ftc_vote_abstain
enum text_link_type text_tag_link_type(const struct text_tag *ptag)
const struct ft_color ftc_log
const struct ft_color ftc_player_lost
const char * city_tile_link(const struct city *pcity)
size_t featured_text_to_plain_text(const char *featured_text, char *plain_text, size_t plain_text_len, struct text_tag_list **tags, bool replace_link_text)
const struct ft_color ftc_luaconsole_verbose
struct text_tag * text_tag_copy(const struct text_tag *ptag)
#define text_tag_list_rev_iterate(tags, ptag)
#define SEQ_STOP
const char * tile_link(const struct tile *ptile)
#define SEQ_START
const struct ft_color ftc_command
ft_offset_t text_tag_stop_offset(const struct text_tag *ptag)
static bool text_tag_initv(struct text_tag *ptag, enum text_tag_type type, ft_offset_t start_offset, ft_offset_t stop_offset, va_list args)
const struct ft_color ftc_server
const struct ft_color ftc_vote_failed
void text_tag_destroy(struct text_tag *ptag)
const struct ft_color ftc_vote_yes
static size_t text_tag_start_sequence(const struct text_tag *ptag, char *buf, size_t len)
const struct ft_color ftc_luaconsole_error
const struct ft_color ftc_warning
const char * text_tag_color_foreground(const struct text_tag *ptag)
#define text_tag_list_rev_iterate_end
static const char * text_link_type_name(enum text_link_type type)
const struct ft_color ftc_client
const struct ft_color ftc_luaconsole_normal
const struct ft_color ftc_editor
static const char * text_tag_type_name(enum text_tag_type type)
static size_t text_tag_replace_text(const struct text_tag *ptag, char *buf, size_t len, bool replace_link_text)
const char * city_link(const struct city *pcity)
const struct ft_color ftc_any
const struct ft_color ftc_vote_no
const struct ft_color ftc_vote_passed
#define MAX_LEN_STR
VAR_ARG_CONST struct ft_color ftc_changed
#define log_featured_text
static size_t text_tag_stop_sequence(const struct text_tag *ptag, char *buf, size_t len)
const struct ft_color ftc_luaconsole_warn
static size_t extract_sequence_text(const char *featured_text, char *buf, size_t len, enum sequence_type *seq_type, enum text_tag_type *type)
int text_tag_link_id(const struct text_tag *ptag)
const struct ft_color ftc_chat_luaconsole
static const char * text_tag_type_short_name(enum text_tag_type type)
ft_offset_t text_tag_start_offset(const struct text_tag *ptag)
struct text_tag * text_tag_new(enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
const struct ft_color ftc_vote_team
const struct ft_color ftc_game_start
const char * unit_link(const struct unit *punit)
const struct ft_color ftc_server_prompt
const struct ft_color ftc_vote_public
sequence_type
@ ST_STOP
@ ST_SINGLE
@ ST_START
const char * unit_tile_link(const struct unit *punit)
const char * text_tag_color_background(const struct text_tag *ptag)
const struct ft_color ftc_luaconsole_input
#define SEQ_END
const struct ft_color ftc_chat_public
const struct ft_color ftc_chat_ally
#define text_tag_list_iterate_end
#define text_tag_list_iterate(tags, ptag)
#define FT_OFFSET_UNSET
#define MAX_LEN_LINK
#define text_tag_list_new()
int ft_offset_t
text_link_type
@ TLT_TILE
@ TLT_UNIT
@ TLT_CITY
text_tag_type
@ TTT_LINK
@ TTT_BOLD
@ TTT_ITALIC
@ TTT_STRIKE
@ TTT_COLOR
@ TTT_UNDERLINE
#define FT_COLOR(fg, bg)
struct world wld
Definition game.c:63
struct unit * game_unit_by_number(int id)
Definition game.c:116
struct city * game_city_by_number(int id)
Definition game.c:107
GType type
Definition repodlgs.c:1313
const char * name
Definition inputfile.c:127
#define log_error(message,...)
Definition log.h:103
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:456
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:419
#define fc_malloc(sz)
Definition mem.h:34
int len
Definition packhand.c:127
bool str_to_int(const char *str, int *pint)
Definition shared.c:517
#define MIN(x, y)
Definition shared.h:55
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
Definition city.h:320
int id
Definition city.h:326
Definition colors.h:21
char background[MAX_LEN_STR]
char name[MAX_LEN_STR]
ft_offset_t stop_offset
ft_offset_t start_offset
enum text_tag_type type
struct text_tag::@26::@28 color
char foreground[MAX_LEN_STR]
struct text_tag::@26::@29 link
enum text_link_type type
Definition tile.h:50
Definition unit.h:138
int id
Definition unit.h:145
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
bool fc_isalpha(char c)
Definition support.c:1221
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
bool fc_isspace(char c)
Definition support.c:1254
bool fc_isalnum(char c)
Definition support.c:1210
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define VAR_ARG_CONST
Definition support.h:152
#define tile_index(_pt_)
Definition tile.h:88
#define TILE_XY(ptile)
Definition tile.h:43
#define unit_tile(_pu)
Definition unit.h:397
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1569