Freeciv-3.3
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. */
73const struct ft_color ftc_any = FT_COLOR(nullptr, nullptr);
74
75const struct ft_color ftc_warning = FT_COLOR("#FF0000", nullptr);
76const struct ft_color ftc_log = FT_COLOR("#7F7F7F", nullptr);
77const struct ft_color ftc_server = FT_COLOR("#8B0000", nullptr);
78const struct ft_color ftc_client = FT_COLOR("#EF7F00", nullptr);
79const struct ft_color ftc_editor = FT_COLOR("#0000FF", nullptr);
80const struct ft_color ftc_command = FT_COLOR("#006400", nullptr);
81VAR_ARG_CONST struct ft_color ftc_changed = FT_COLOR("#FF0000", nullptr);
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", nullptr);
87const struct ft_color ftc_chat_ally = FT_COLOR("#551166", nullptr);
88const struct ft_color ftc_chat_private = FT_COLOR("#A020F0", nullptr);
89const struct ft_color ftc_chat_luaconsole = FT_COLOR("#006400", nullptr);
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", nullptr);
100const struct ft_color ftc_luaconsole_error = FT_COLOR("#FF0000", nullptr);
101const struct ft_color ftc_luaconsole_warn = FT_COLOR("#CF2020", nullptr);
102const struct ft_color ftc_luaconsole_normal = FT_COLOR("#006400", nullptr);
103const struct ft_color ftc_luaconsole_verbose = FT_COLOR("#B8B8B8", nullptr);
104const struct ft_color ftc_luaconsole_debug = FT_COLOR("#B87676", nullptr);
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
127 /* Don't handle the default case to be warned if a new value was added. */
128 return nullptr;
129}
130
131/**********************************************************************/
136{
137 switch (type) {
138 case TTT_BOLD:
139 return "b";
140 case TTT_ITALIC:
141 return "i";
142 case TTT_STRIKE:
143 return "s";
144 case TTT_UNDERLINE:
145 return "u";
146 case TTT_COLOR:
147 return "c";
148 case TTT_LINK:
149 return "l";
150 };
151
152 /* Don't handle the default case to be warned if a new value was added. */
153 return nullptr;
154}
155
156/**********************************************************************/
160{
161 switch (type) {
162 case TLT_CITY:
163 return "city";
164 case TLT_TILE:
165 return "tile";
166 case TLT_UNIT:
167 return "unit";
168 };
169
170 /* Don't handle the default case to be warned if a new value was added. */
171 return nullptr;
172}
173
174/**********************************************************************/
178static bool find_option(const char *buf_in, const char *option,
179 char *buf_out, size_t write_len)
180{
181 size_t option_len = strlen(option);
182
183 while (*buf_in != '\0') {
184 while (fc_isspace(*buf_in) && *buf_in != '\0') {
185 buf_in++;
186 }
187
188 if (0 == strncasecmp(buf_in, option, option_len)) {
189 /* This is this one. */
191
192 while ((fc_isspace(*buf_in) || *buf_in == '=') && *buf_in != '\0') {
193 buf_in++;
194 }
195 if (*buf_in == '"') {
196 /* Quote case. */
197 const char *end = strchr(++buf_in, '"');
198
199 if (!end) {
200 return FALSE;
201 }
202 if (end - buf_in + 1 > 0) {
204 } else {
205 *buf_out = '\0';
206 }
207 return TRUE;
208 } else {
209 while (fc_isalnum(*buf_in) && write_len > 1) {
210 *buf_out++ = *buf_in++;
211 write_len--;
212 }
213 *buf_out = '\0';
214 return TRUE;
215 }
216 }
217 buf_in++;
218 }
219
220 return FALSE;
221}
222
223/**********************************************************************/
228 enum text_tag_type type,
229 ft_offset_t start_offset,
230 const char *sequence)
231{
232 ptag->type = type;
233 ptag->start_offset = start_offset;
234 ptag->stop_offset = FT_OFFSET_UNSET;
235
236 switch (type) {
237 case TTT_BOLD:
238 case TTT_ITALIC:
239 case TTT_STRIKE:
240 case TTT_UNDERLINE:
241 return TRUE;
242 case TTT_COLOR:
243 {
244 if (!find_option(sequence, "foreground", ptag->color.foreground,
245 sizeof(ptag->color.foreground))
246 && !find_option(sequence, "fg", ptag->color.foreground,
247 sizeof(ptag->color.foreground))) {
248 ptag->color.foreground[0] = '\0';
249 }
250 if (!find_option(sequence, "background", ptag->color.background,
251 sizeof(ptag->color.background))
252 && !find_option(sequence, "bg", ptag->color.background,
253 sizeof(ptag->color.background))) {
254 ptag->color.background[0] = '\0';
255 }
256 }
257 return TRUE;
258 case TTT_LINK:
259 {
260 char buf[64];
261 const char *name;
262 int i;
263
264 if (!find_option(sequence, "target", buf, sizeof(buf))
265 && !find_option(sequence, "tgt", buf, sizeof(buf))) {
266 log_featured_text("text_tag_init_from_sequence(): "
267 "target link type not set.");
268 return FALSE;
269 }
270
271 ptag->link.type = -1;
272 for (i = 0; (name = text_link_type_name(i)); i++) {
273 if (0 == fc_strncasecmp(buf, name, strlen(name))) {
274 ptag->link.type = i;
275 break;
276 }
277 }
278 if (ptag->link.type == -1) {
279 log_featured_text("text_tag_init_from_sequence(): "
280 "target link type not supported (\"%s\").", buf);
281 return FALSE;
282 }
283
284 switch (ptag->link.type) {
285 case TLT_CITY:
286 {
287 if (!find_option(sequence, "id", buf, sizeof(buf))) {
288 log_featured_text("text_tag_init_from_sequence(): "
289 "city link without id.");
290 return FALSE;
291 }
292 if (!str_to_int(buf, &ptag->link.id)) {
293 log_featured_text("text_tag_init_from_sequence(): "
294 "city link without valid id (\"%s\").", buf);
295 return FALSE;
296 }
297
298 if (!find_option(sequence, "name", ptag->link.name,
299 sizeof(ptag->link.name))) {
300 /* Set something as name. */
301 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
302 "CITY_ID%d", ptag->link.id);
303 }
304 }
305 return TRUE;
306 case TLT_TILE:
307 {
308 struct tile *ptile;
309 int x, y;
310
311 if (!find_option(sequence, "x", buf, sizeof(buf))) {
312 log_featured_text("text_tag_init_from_sequence(): "
313 "tile link without x coordinate.");
314 return FALSE;
315 }
316 if (!str_to_int(buf, &x)) {
317 log_featured_text("text_tag_init_from_sequence(): "
318 "tile link without valid x coordinate "
319 "(\"%s\").", buf);
320 return FALSE;
321 }
322
323 if (!find_option(sequence, "y", buf, sizeof(buf))) {
324 log_featured_text("text_tag_init_from_sequence(): "
325 "tile link without y coordinate.");
326 return FALSE;
327 }
328 if (!str_to_int(buf, &y)) {
329 log_featured_text("text_tag_init_from_sequence(): "
330 "tile link without valid y coordinate "
331 "(\"%s\").", buf);
332 return FALSE;
333 }
334
335 ptile = map_pos_to_tile(&(wld.map), x, y);
336 if (!ptile) {
337 log_featured_text("text_tag_init_from_sequence(): "
338 "(%d, %d) are not valid coordinates "
339 "in this game.", x, y);
340 return FALSE;
341 }
342 ptag->link.id = tile_index(ptile);
343 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
344 "(%d, %d)", TILE_XY(ptile));
345 }
346 return TRUE;
347 case TLT_UNIT:
348 {
349 if (!find_option(sequence, "id", buf, sizeof(buf))) {
350 log_featured_text("text_tag_init_from_sequence(): "
351 "unit link without id.");
352 return FALSE;
353 }
354 if (!str_to_int(buf, &ptag->link.id)) {
355 log_featured_text("text_tag_init_from_sequence(): "
356 "unit link without valid id (\"%s\").", buf);
357 return FALSE;
358 }
359
360 if (!find_option(sequence, "name", ptag->link.name,
361 sizeof(ptag->link.name))) {
362 /* Set something as name. */
363 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
364 "UNIT_ID%d", ptag->link.id);
365 }
366 }
367 return TRUE;
368 };
369 }
370 };
371 return FALSE;
372}
373
374/**********************************************************************/
392 ft_offset_t start_offset, ft_offset_t stop_offset,
393 va_list args)
394{
395 ptag->type = type;
396 ptag->start_offset = start_offset;
397 ptag->stop_offset = stop_offset;
398
399 switch (type) {
400 case TTT_BOLD:
401 case TTT_ITALIC:
402 case TTT_STRIKE:
403 case TTT_UNDERLINE:
404 return TRUE;
405 case TTT_COLOR:
406 {
407 const struct ft_color color = va_arg(args, struct ft_color);
408
409 if ((color.foreground == nullptr || color.foreground[0] == '\0')
410 && (color.background == nullptr || color.background[0] == '\0')) {
411 return FALSE; /* No color at all. */
412 }
413
414 if (color.foreground != nullptr && color.foreground[0] != '\0') {
415 sz_strlcpy(ptag->color.foreground, color.foreground);
416 } else {
417 ptag->color.foreground[0] = '\0';
418 }
419
420 if (color.background != nullptr && color.background[0] != '\0') {
421 sz_strlcpy(ptag->color.background, color.background);
422 } else {
423 ptag->color.background[0] = '\0';
424 }
425 }
426 return TRUE;
427 case TTT_LINK:
428 {
429 ptag->link.type = va_arg(args, enum text_link_type);
430 switch (ptag->link.type) {
431 case TLT_CITY:
432 {
433 struct city *pcity = va_arg(args, struct city *);
434
435 if (!pcity) {
436 return FALSE;
437 }
438 ptag->link.id = pcity->id;
439 sz_strlcpy(ptag->link.name, city_name_get(pcity));
440 }
441 return TRUE;
442 case TLT_TILE:
443 {
444 struct tile *ptile = va_arg(args, struct tile *);
445
446 if (!ptile) {
447 return FALSE;
448 }
449 ptag->link.id = tile_index(ptile);
450 fc_snprintf(ptag->link.name, sizeof(ptag->link.name),
451 "(%d, %d)", TILE_XY(ptile));
452 }
453 return TRUE;
454 case TLT_UNIT:
455 {
456 struct unit *punit = va_arg(args, struct unit *);
457
458 if (!punit) {
459 return FALSE;
460 }
461 ptag->link.id = punit->id;
463 }
464 return TRUE;
465 };
466 }
467 };
468 return FALSE;
469}
470
471/**********************************************************************/
474static size_t text_tag_start_sequence(const struct text_tag *ptag,
475 char *buf, size_t len)
476{
477 switch (ptag->type) {
478 case TTT_BOLD:
479 case TTT_ITALIC:
480 case TTT_STRIKE:
481 case TTT_UNDERLINE:
482 return fc_snprintf(buf, len, "%c%s%c", SEQ_START,
484 case TTT_COLOR:
485 {
486 size_t ret = fc_snprintf(buf, len, "%c%s", SEQ_START,
488
489 if (ptag->color.foreground[0] != '\0') {
490 ret += fc_snprintf(buf + ret, len - ret, " fg=\"%s\"",
491 ptag->color.foreground);
492 }
493 if (ptag->color.background[0] != '\0') {
494 ret += fc_snprintf(buf + ret, len - ret, " bg=\"%s\"",
495 ptag->color.background);
496 }
497 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
498 }
499 case TTT_LINK:
500 {
501 size_t ret = fc_snprintf(buf, len, "%c%s tgt=\"%s\"", SEQ_START,
503 text_link_type_name(ptag->link.type));
504
505 switch (ptag->link.type) {
506 case TLT_CITY:
507 {
508 struct city *pcity = game_city_by_number(ptag->link.id);
509
510 if (pcity) {
511 ret += fc_snprintf(buf + ret, len - ret,
512 " id=%d name=\"%s\"",
514 } else {
515 ret += fc_snprintf(buf + ret, len - ret,
516 " id=%d", ptag->link.id);
517 }
518 }
519 break;
520 case TLT_TILE:
521 {
522 struct tile *ptile = index_to_tile(&(wld.map), ptag->link.id);
523
524 if (ptile) {
525 ret += fc_snprintf(buf + ret, len - ret,
526 " x=%d y=%d", TILE_XY(ptile));
527 } else {
528 ret += fc_snprintf(buf + ret, len - ret,
529 " id=%d", ptag->link.id);
530 }
531 }
532 break;
533 case TLT_UNIT:
534 {
535 struct unit *punit = game_unit_by_number(ptag->link.id);
536
537 if (punit) {
538 ret += fc_snprintf(buf + ret, len - ret,
539 " id=%d name=\"%s\"",
541 } else {
542 ret += fc_snprintf(buf + ret, len - ret,
543 " id=%d", ptag->link.id);
544 }
545 }
546 break;
547 };
548
549 if (ptag->stop_offset == ptag->start_offset) {
550 /* This is a single sequence like [link ... /]. */
551 ret += fc_snprintf(buf + ret, len - ret, "%c", SEQ_END);
552 }
553
554 return ret + fc_snprintf(buf + ret, len - ret, "%c", SEQ_STOP);
555 }
556 };
557 return 0;
558}
559
560/**********************************************************************/
563static size_t text_tag_stop_sequence(const struct text_tag *ptag,
564 char *buf, size_t len)
565{
566 if (ptag->type == TTT_LINK && ptag->stop_offset == ptag->start_offset) {
567 /* Should be already finished. */
568 return 0;
569 }
570
571 return fc_snprintf(buf, len, "%c%c%s%c", SEQ_START, SEQ_END,
573}
574
575/**********************************************************************/
578static size_t text_tag_replace_text(const struct text_tag *ptag,
579 char *buf, size_t len,
581{
582 if (ptag->type != TTT_LINK) {
583 return 0;
584 }
585
586 if (replace_link_text) {
587 /* The client might check if this should be updated or translated. */
588 switch (ptag->link.type) {
589 case TLT_CITY:
590 {
591 struct city *pcity = game_city_by_number(ptag->link.id);
592
593 /* Note that if city_tile(pcity) is nullptr, then it is probably an
594 * invisible city (see client/packhand.c). Then, we don't
595 * use the current city name which is usually not complete,
596 * a dumb string using the city id. */
597 if (pcity != nullptr && city_tile(pcity) != nullptr) {
598 return fc_snprintf(buf, len, "%s", city_name_get(pcity));
599 }
600 }
601 break;
602 case TLT_TILE:
603 break;
604 case TLT_UNIT:
605 {
606 struct unit *punit = game_unit_by_number(ptag->link.id);
607
608 if (punit) {
610 }
611 }
612 break;
613 };
614 }
615
616 if (ptag->link.type == TLT_UNIT) {
617 /* Attempt to translate the link name (it should be a unit type name). */
618 return fc_snprintf(buf, len, "%s", _(ptag->link.name));
619 } else {
620 return fc_snprintf(buf, len, "%s", ptag->link.name);
621 }
622}
623
624/**********************************************************************/
644 ...)
645{
646 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
647 va_list args;
648 bool ok;
649
650 va_start(args, stop_offset);
652 va_end(args);
653
654 if (ok) {
655 return ptag;
656 } else {
657 free(ptag);
658
659 return nullptr;
660 }
661}
662
663/**********************************************************************/
667struct text_tag *text_tag_copy(const struct text_tag *ptag)
668{
669 struct text_tag *pnew_tag;
670
671 if (ptag == nullptr) {
672 return nullptr;
673 }
674
675 pnew_tag = fc_malloc(sizeof(struct text_tag));
676 *pnew_tag = *ptag;
677
678 return pnew_tag;
679}
680
681/**********************************************************************/
685{
686 free(ptag);
687}
688
689/**********************************************************************/
693{
694 return ptag->type;
695}
696
697/**********************************************************************/
701{
702 return ptag->start_offset;
703}
704
705/**********************************************************************/
709{
710 return ptag->stop_offset;
711}
712
713/**********************************************************************/
717const char *text_tag_color_foreground(const struct text_tag *ptag)
718{
719 if (ptag->type != TTT_COLOR) {
720 log_error("text_tag_color_foreground(): incompatible tag type.");
721 return nullptr;
722 }
723
724 return ptag->color.foreground;
725}
726
727/**********************************************************************/
731const char *text_tag_color_background(const struct text_tag *ptag)
732{
733 if (ptag->type != TTT_COLOR) {
734 log_error("text_tag_color_background(): incompatible tag type.");
735 return nullptr;
736 }
737
738 return ptag->color.background;
739}
740
741/**********************************************************************/
746{
747 if (ptag->type != TTT_LINK) {
748 log_error("text_tag_link_type(): incompatible tag type.");
749 return -1;
750 }
751
752 return ptag->link.type;
753}
754
755/**********************************************************************/
761{
762 if (ptag->type != TTT_LINK) {
763 log_error("text_tag_link_id(): incompatible tag type.");
764 return -1;
765 }
766
767 return ptag->link.id;
768}
769
770/**********************************************************************/
774static size_t extract_sequence_text(const char *featured_text,
775 char *buf, size_t len,
777 enum text_tag_type *type)
778{
779 const char *buf_in = featured_text;
780 const char *stop = strchr(buf_in, SEQ_STOP);
781 const char *end = stop;
782 const char *name;
783 size_t type_len;
784 size_t name_len;
785 int i;
786
787 if (stop == nullptr) {
788 return 0; /* Not valid. */
789 }
790
791 /* Check sequence type. */
792 for (buf_in++; fc_isspace(*buf_in); buf_in++);
793
794 if (*buf_in == SEQ_END) {
795 *seq_type = ST_STOP;
796 buf_in++;
797 } else {
798 for (end--; fc_isspace(*end); end--);
799
800 if (*end == SEQ_END) {
802
803 for (end--; fc_isspace(*end); end--);
804 } else {
806 }
807 }
808
809 while (fc_isspace(*buf_in)) {
810 buf_in++;
811 }
812
813 /* Check the length of the type name. */
814 for (name = buf_in; name < stop; name++) {
815 if (!fc_isalpha(*name)) {
816 break;
817 }
818 }
819 type_len = name - buf_in;
820
821 *type = -1;
822 for (i = 0; (name = text_tag_type_name(i)); i++) {
825 buf_in += name_len;
826 *type = i;
827 break;
828 }
829 }
830 if (*type == -1) {
831 /* Try with short names. */
832 for (i = 0; (name = text_tag_type_short_name(i)); i++) {
834 if (name_len == type_len
835 && 0 == fc_strncasecmp(name, buf_in, name_len)) {
836 buf_in += name_len;
837 *type = i;
838 break;
839 }
840 }
841 if (*type == -1) {
842 return 0; /* Not valid. */
843 }
844 }
845
846 while (fc_isspace(*buf_in)) {
847 buf_in++;
848 }
849
850 if (end - buf_in + 2 > 0) {
851 fc_strlcpy(buf, buf_in, MIN(end - buf_in + 2, len));
852 } else {
853 buf[0] = '\0';
854 }
855 return stop - featured_text + 1;
856}
857
858
859/**********************************************************************/
869 char *plain_text, size_t plain_text_len,
870 struct text_tag_list **tags,
872{
873 const char *text_in = featured_text;
874 char *text_out = plain_text;
876
877 if (tags) {
878 *tags = text_tag_list_new();
879 }
880
881 while (*text_in != '\0' && text_out_len > 1) {
882 if (SEQ_START == *text_in) {
883 /* Escape sequence... */
884 char buf[text_out_len];
886 enum text_tag_type type;
888 &seq_type, &type);
889
890 if (len > 0) {
891 /* Looks a valid sequence. */
892 text_in += len;
893 switch (seq_type) {
894 case ST_START:
895 if (tags) {
896 /* Create a new tag. */
897 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
898
900 text_out - plain_text, buf)) {
902 } else {
904 log_featured_text("Couldn't create a text tag with \"%s\".",
905 buf);
906 }
907 }
908 break;
909 case ST_STOP:
910 if (tags) {
911 /* Set the stop offset. */
912 struct text_tag *ptag = nullptr;
913
914 /* Look up on reversed order. */
916 if (piter->type == type
917 && piter->stop_offset == FT_OFFSET_UNSET) {
918 ptag = piter;
919 break;
920 }
922
923 if (ptag) {
925 } else {
926 log_featured_text("Extra text tag end for \"%s\".",
928 }
929 }
930 break;
931 case ST_SINGLE:
932 {
933 /* In this case, we replace the sequence by some text. */
934 struct text_tag tag;
935
937 text_out - plain_text, buf)) {
938 log_featured_text("Couldn't create a text tag with \"%s\".",
939 buf);
940 } else {
943 text_out += len;
944 text_out_len -= len;
945 if (tags) {
946 /* Set it in the list. */
947 struct text_tag *ptag = fc_malloc(sizeof(struct text_tag));
948
949 *ptag = tag;
952 }
953 }
954 }
955 break;
956 };
957 } else {
958 *text_out++ = *text_in++;
959 text_out_len--;
960 }
961 } else {
962 *text_out++ = *text_in++;
963 text_out_len--;
964 }
965 }
966 if (tags) {
967 /* Auto-stop all tags opened and not closed */
969 if (ptag->stop_offset == FT_OFFSET_UNSET) {
970 ptag->stop_offset = text_out - plain_text;
971 }
973 }
974 *text_out = '\0';
975
977}
978
979/**********************************************************************/
998 char *featured_text, size_t featured_text_len,
1002 ...)
1003{
1004 struct text_tag tag;
1005 size_t len, total_len = 0;
1006 va_list args;
1007
1011 && stop_offset < start_offset)) {
1012 log_featured_text("featured_text_apply_tag(): invalid offsets.");
1013 return 0;
1014 }
1015
1016 va_start(args, stop_offset);
1017 if (!text_tag_initv(&tag, tag_type, start_offset, stop_offset, args)) {
1018 va_end(args);
1019 return 0;
1020 }
1021 va_end(args);
1022
1023 if (start_offset > 0) {
1024 /* First part: before the sequence. */
1025 len = 0;
1026 while (len < start_offset
1027 && *text_source != '\0'
1028 && featured_text_len > 1) {
1029 *featured_text++ = *text_source++;
1031 len++;
1032 }
1033 total_len += len;
1034 }
1035
1036 /* Start sequence. */
1038 total_len += len;
1039 featured_text += len;
1041
1042 /* Second part: between the sequences. */
1043 len = start_offset;
1044 while (len < stop_offset
1045 && *text_source != '\0'
1046 && featured_text_len > 1) {
1047 *featured_text++ = *text_source++;
1049 len++;
1050 }
1051 total_len += len;
1052
1053 /* Stop sequence. */
1055 total_len += len;
1056 featured_text += len;
1058
1059 /* Third part: after the sequence. */
1060 while (*text_source != '\0'
1061 && featured_text_len > 1) {
1062 *featured_text++ = *text_source++;
1064 total_len++;
1065 }
1066 *featured_text = '\0';
1067
1068 return total_len;
1069}
1070
1071/**********************************************************************/
1076const char *city_link(const struct city *pcity)
1077{
1078 static char buf[MAX_LEN_LINK];
1079
1080 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1084 return buf;
1085}
1086
1087/**********************************************************************/
1093const char *city_tile_link(const struct city *pcity)
1094{
1095 static char buf[MAX_LEN_LINK];
1097
1098 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1102 return buf;
1103}
1104
1105/**********************************************************************/
1110const char *tile_link(const struct tile *ptile)
1111{
1112 static char buf[MAX_LEN_LINK];
1113
1114 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d %c%c",
1117 SEQ_END, SEQ_STOP);
1118 return buf;
1119}
1120
1121/**********************************************************************/
1126const char *unit_link(const struct unit *punit)
1127{
1128 static char buf[MAX_LEN_LINK];
1129
1130 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1134 return buf;
1135}
1136
1137/**********************************************************************/
1143const char *unit_tile_link(const struct unit *punit)
1144{
1145 static char buf[MAX_LEN_LINK];
1147
1148 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1153 return buf;
1154}
const char * city_name_get(const struct city *pcity)
Definition city.c:1137
#define city_tile(_pcity_)
Definition city.h:561
char * incite_cost
Definition comments.c:76
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
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 int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
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:62
struct unit * game_unit_by_number(int id)
Definition game.c:115
struct city * game_city_by_number(int id)
Definition game.c:106
GType type
Definition repodlgs.c:1313
const char * name
Definition inputfile.c:127
#define log_error(message,...)
Definition log.h:104
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:471
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:434
#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:515
#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:317
Definition colors.h:21
struct text_tag::@27::@30 link
char background[MAX_LEN_STR]
char name[MAX_LEN_STR]
struct text_tag::@27::@29 color
ft_offset_t stop_offset
ft_offset_t start_offset
enum text_tag_type type
char foreground[MAX_LEN_STR]
enum text_link_type type
Definition tile.h:50
Definition unit.h:140
int id
Definition unit.h:147
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
bool fc_isalpha(char c)
Definition support.c:1207
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
bool fc_isspace(char c)
Definition support.c:1240
bool fc_isalnum(char c)
Definition support.c:1196
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:235
#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:89
#define TILE_XY(ptile)
Definition tile.h:43
#define unit_tile(_pu)
Definition unit.h:404
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1575