Freeciv-3.1: /fast/freeciv/nightly/S3_1/common/featured_text.c Source File

Freeciv-3.1

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. */
49 struct 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. */
57 } color;
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. */
62 } link;
63 };
64};
65
66 enum sequence_type {
67 ST_START, /* e.g. [sequence]. */
68 ST_STOP, /* e.g. [/sequence]. */
69 ST_SINGLE /* e.g. [sequence/]. */
70};
71
72/* Predefined colors. */
73 const struct ft_color ftc_any = FT_COLOR(NULL, NULL);
74
75 const struct ft_color ftc_warning = FT_COLOR("#FF0000", NULL);
76 const struct ft_color ftc_log = FT_COLOR("#7F7F7F", NULL);
77 const struct ft_color ftc_server = FT_COLOR("#8B0000", NULL);
78 const struct ft_color ftc_client = FT_COLOR("#EF7F00", NULL);
79 const struct ft_color ftc_editor = FT_COLOR("#0000FF", NULL);
80 const struct ft_color ftc_command = FT_COLOR("#006400", NULL);
81 struct ft_color ftc_changed = FT_COLOR("#FF0000", NULL);
82 const struct ft_color ftc_server_prompt = FT_COLOR("#FF0000", "#BEBEBE");
83 const struct ft_color ftc_player_lost = FT_COLOR("#FFFFFF", "#000000");
84 const struct ft_color ftc_game_start = FT_COLOR("#00FF00", "#115511");
85
86 const struct ft_color ftc_chat_public = FT_COLOR("#00008B", NULL);
87 const struct ft_color ftc_chat_ally = FT_COLOR("#551166", NULL);
88 const struct ft_color ftc_chat_private = FT_COLOR("#A020F0", NULL);
89 const struct ft_color ftc_chat_luaconsole = FT_COLOR("#006400", NULL);
90
91 const struct ft_color ftc_vote_public = FT_COLOR("#FFFFFF", "#AA0000");
92 const struct ft_color ftc_vote_team = FT_COLOR("#FFFFFF", "#5555CC");
93 const struct ft_color ftc_vote_passed = FT_COLOR("#006400", "#AAFFAA");
94 const struct ft_color ftc_vote_failed = FT_COLOR("#8B0000", "#FFAAAA");
95 const struct ft_color ftc_vote_yes = FT_COLOR("#000000", "#C8FFD5");
96 const struct ft_color ftc_vote_no = FT_COLOR("#000000", "#FFD2D2");
97 const struct ft_color ftc_vote_abstain = FT_COLOR("#000000", "#E8E8E8");
98
99 const struct ft_color ftc_luaconsole_input = FT_COLOR("#2B008B", NULL);
100 const struct ft_color ftc_luaconsole_error = FT_COLOR("#FF0000", NULL);
101 const struct ft_color ftc_luaconsole_warn = FT_COLOR("#CF2020", NULL);
102 const struct ft_color ftc_luaconsole_normal = FT_COLOR("#006400", NULL);
103 const struct ft_color ftc_luaconsole_verbose = FT_COLOR("#B8B8B8", NULL);
104 const struct ft_color ftc_luaconsole_debug = FT_COLOR("#B87676", NULL);
105
106/**********************************************************************/
110 static 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/**********************************************************************/
134 static const char *text_tag_type_short_name(enum text_tag_type type)
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/**********************************************************************/
157 static const char *text_link_type_name(enum text_link_type type)
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/**********************************************************************/
175 static 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. */
187 buf_in += option_len;
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) {
200 fc_strlcpy(buf_out, buf_in, MIN(end - buf_in + 1, write_len));
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/**********************************************************************/
224 static bool text_tag_init_from_sequence(struct text_tag *ptag,
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/**********************************************************************/
388 static bool text_tag_initv(struct text_tag *ptag, enum text_tag_type type,
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;
459 sz_strlcpy(ptag->link.name, unit_name_translation(punit));
460 }
461 return TRUE;
462 };
463 }
464 };
465 return FALSE;
466}
467
468/**********************************************************************/
471 static 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,
480 text_tag_type_short_name(ptag->type), SEQ_STOP);
481 case TTT_COLOR:
482 {
483 size_t ret = fc_snprintf(buf, len, "%c%s", SEQ_START,
484 text_tag_type_short_name(ptag->type));
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,
499 text_tag_type_short_name(ptag->type),
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\"",
537 punit->id, unit_name_translation(punit));
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/**********************************************************************/
560 static 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,
569 text_tag_type_short_name(ptag->type), SEQ_STOP);
570}
571
572/**********************************************************************/
575 static size_t text_tag_replace_text(const struct text_tag *ptag,
576 char *buf, size_t len,
577 bool replace_link_text)
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) {
606 return fc_snprintf(buf, len, "%s", unit_name_translation(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/**********************************************************************/
638 struct text_tag *text_tag_new(enum text_tag_type tag_type,
639 ft_offset_t start_offset,
640 ft_offset_t stop_offset,
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);
648 ok = text_tag_initv(ptag, tag_type, start_offset, stop_offset, args);
649 va_end(args);
650
651 if (ok) {
652 return ptag;
653 } else {
654 free(ptag);
655 return NULL;
656 }
657}
658
659/**********************************************************************/
663 struct 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/**********************************************************************/
680 void text_tag_destroy(struct text_tag *ptag)
681{
682 free(ptag);
683}
684
685/**********************************************************************/
688 enum text_tag_type text_tag_type(const struct text_tag *ptag)
689{
690 return ptag->type;
691}
692
693/**********************************************************************/
696 ft_offset_t text_tag_start_offset(const struct text_tag *ptag)
697{
698 return ptag->start_offset;
699}
700
701/**********************************************************************/
704 ft_offset_t text_tag_stop_offset(const struct text_tag *ptag)
705{
706 return ptag->stop_offset;
707}
708
709/**********************************************************************/
713 const 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/**********************************************************************/
727 const 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/**********************************************************************/
741 enum text_link_type text_tag_link_type(const struct text_tag *ptag)
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/**********************************************************************/
756 int text_tag_link_id(const struct text_tag *ptag)
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/**********************************************************************/
770 static size_t extract_sequence_text(const char *featured_text,
771 char *buf, size_t len,
772 enum sequence_type *seq_type,
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) {
797 *seq_type = ST_SINGLE;
798
799 for (end--; fc_isspace(*end); end--);
800 } else {
801 *seq_type = ST_START;
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++) {
819 name_len = strlen(name);
820 if (name_len == type_len && 0 == fc_strncasecmp(name, buf_in, name_len)) {
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++) {
829 name_len = strlen(name);
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/**********************************************************************/
864 size_t featured_text_to_plain_text(const char *featured_text,
865 char *plain_text, size_t plain_text_len,
866 struct text_tag_list **tags,
867 bool replace_link_text)
868{
869 const char *text_in = featured_text;
870 char *text_out = plain_text;
871 size_t text_out_len = plain_text_len;
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];
881 enum sequence_type seq_type;
882 enum text_tag_type type;
883 size_t len = extract_sequence_text(text_in, buf, text_out_len,
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
895 if (text_tag_init_from_sequence(ptag, type,
896 text_out - plain_text, buf)) {
897 text_tag_list_append(*tags, ptag);
898 } else {
899 text_tag_destroy(ptag);
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. */
911 text_tag_list_rev_iterate(*tags, piter) {
912 if (piter->type == type
913 && piter->stop_offset == FT_OFFSET_UNSET) {
914 ptag = piter;
915 break;
916 }
917 } text_tag_list_rev_iterate_end;
918
919 if (ptag) {
920 ptag->stop_offset = text_out - plain_text;
921 } else {
922 log_featured_text("Extra text tag end for \"%s\".",
923 text_tag_type_name(type));
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
932 if (!text_tag_init_from_sequence(&tag, type,
933 text_out - plain_text, buf)) {
934 log_featured_text("Couldn't create a text tag with \"%s\".",
935 buf);
936 } else {
937 len = text_tag_replace_text(&tag, text_out, text_out_len,
938 replace_link_text);
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;
946 ptag->stop_offset = text_out - plain_text;
947 text_tag_list_append(*tags, ptag);
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 */
964 text_tag_list_iterate(*tags, ptag) {
965 if (ptag->stop_offset == FT_OFFSET_UNSET) {
966 ptag->stop_offset = text_out - plain_text;
967 }
968 } text_tag_list_iterate_end;
969 }
970 *text_out = '\0';
971
972 return plain_text_len - text_out_len;
973}
974
975/**********************************************************************/
993 size_t featured_text_apply_tag(const char *text_source,
994 char *featured_text, size_t featured_text_len,
995 enum text_tag_type tag_type,
996 ft_offset_t start_offset,
997 ft_offset_t stop_offset,
998 ...)
999{
1000 struct text_tag tag;
1001 size_t len, total_len = 0;
1002 va_list args;
1003
1004 if (start_offset == FT_OFFSET_UNSET
1005 || start_offset > strlen(text_source)
1006 || (stop_offset != FT_OFFSET_UNSET
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++;
1026 featured_text_len--;
1027 len++;
1028 }
1029 total_len += len;
1030 }
1031
1032 /* Start sequence. */
1033 len = text_tag_start_sequence(&tag, featured_text, featured_text_len);
1034 total_len += len;
1035 featured_text += len;
1036 featured_text_len -= 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++;
1044 featured_text_len--;
1045 len++;
1046 }
1047 total_len += len;
1048
1049 /* Stop sequence. */
1050 len = text_tag_stop_sequence(&tag, featured_text, featured_text_len);
1051 total_len += len;
1052 featured_text += len;
1053 featured_text_len -= len;
1054
1055 /* Third part: after the sequence. */
1056 while (*text_source != '\0'
1057 && featured_text_len > 1) {
1058 *featured_text++ = *text_source++;
1059 featured_text_len--;
1060 total_len++;
1061 }
1062 *featured_text = '\0';
1063
1064 return total_len;
1065}
1066
1067/**********************************************************************/
1072 const 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",
1077 SEQ_START, text_tag_type_short_name(TTT_LINK),
1078 text_link_type_name(TLT_CITY), pcity->id,
1079 city_name_get(pcity), SEQ_END, SEQ_STOP);
1080 return buf;
1081}
1082
1083/**********************************************************************/
1089 const char *city_tile_link(const struct city *pcity)
1090{
1091 static char buf[MAX_LEN_LINK];
1092 const char *tag_name = text_tag_type_short_name(TTT_LINK);
1093
1094 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1095 SEQ_START, tag_name, text_link_type_name(TLT_TILE),
1096 TILE_XY(city_tile(pcity)), SEQ_STOP, city_name_get(pcity),
1097 SEQ_START, SEQ_END, tag_name, SEQ_STOP);
1098 return buf;
1099}
1100
1101/**********************************************************************/
1106 const 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",
1111 SEQ_START, text_tag_type_short_name(TTT_LINK),
1112 text_link_type_name(TLT_TILE), TILE_XY(ptile),
1113 SEQ_END, SEQ_STOP);
1114 return buf;
1115}
1116
1117/**********************************************************************/
1122 const char *unit_veteran_level_string(const struct unit *punit)
1123{
1124 static char buf[MAX_LEN_LINK];
1125 const struct veteran_level *vlevel;
1126
1127 if (!punit) {
1128 buf[0] = '\0'; /* If no unit, return empty string */
1129 return buf;
1130 }
1131
1132 vlevel = utype_veteran_level(unit_type_get(punit), punit->veteran);
1133 fc_snprintf(buf, sizeof(buf), "%s", name_translation_get(&vlevel->name));
1134 return buf;
1135}
1136
1137/**********************************************************************/
1142 const char *unit_achieved_rank_string(const struct unit *punit)
1143{
1144 static char buf[MAX_LEN_LINK];
1145
1146 fc_snprintf(buf, sizeof(buf),
1147 /* TRANS: " and achieved the rank of <veteran level>";
1148 * preserve leading space */
1149 _(" and achieved the rank of %s"),
1150 unit_veteran_level_string(punit));
1151 return buf;
1152}
1153
1154/**********************************************************************/
1159 const char *unit_tired_attack_string(const struct unit *punit)
1160{
1161 static char buf[MAX_LEN_LINK];
1162
1163 if (is_tired_attack(punit->moves_left)) {
1164 fc_snprintf(buf, sizeof(buf),
1165 /* TRANS: tired; note trailing space */
1166 _("tired "));
1167 } else {
1168 buf[0] = '\0';
1169 }
1170 return buf;
1171}
1172
1173/**********************************************************************/
1180 const char *unit_firepower_if_not_one(int firepower)
1181{
1182 static char buf[MAX_LEN_LINK];
1183
1184 if (firepower == 1) {
1185 buf[0] = '\0';
1186 } else {
1187 fc_snprintf(buf, sizeof(buf),
1188 /* TRANS: FP = Firepower of a unit; note trailing space */
1189 _("FP:%d "),
1190 firepower);
1191 }
1192 return buf;
1193}
1194
1195/**********************************************************************/
1200 const char *unit_link(const struct unit *punit)
1201{
1202 static char buf[MAX_LEN_LINK];
1203
1204 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" id=%d name=\"%s\" %c%c",
1205 SEQ_START, text_tag_type_short_name(TTT_LINK),
1206 text_link_type_name(TLT_UNIT), punit->id,
1207 unit_name_translation(punit), SEQ_END, SEQ_STOP);
1208 return buf;
1209}
1210
1211/**********************************************************************/
1217 const char *unit_tile_link(const struct unit *punit)
1218{
1219 static char buf[MAX_LEN_LINK];
1220 const char *tag_name = text_tag_type_short_name(TTT_LINK);
1221
1222 fc_snprintf(buf, sizeof(buf), "%c%s tgt=\"%s\" x=%d y=%d%c%s%c%c%s%c",
1223 SEQ_START, tag_name, text_link_type_name(TLT_TILE),
1224 TILE_XY(unit_tile(punit)), SEQ_STOP,
1225 unit_name_translation(punit),
1226 SEQ_START, SEQ_END, tag_name, SEQ_STOP);
1227 return buf;
1228}
city_name_get
const char * city_name_get(const struct city *pcity)
Definition city.c:1111
city.h
city_tile
#define city_tile(_pcity_)
Definition city.h:544
is_tired_attack
bool is_tired_attack(int moves_left)
Definition combat.c:486
combat.h
punit
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:73
tag_name
char * tag_name
Definition events.c:77
fcintl.h
_
#define _(String)
Definition fcintl.h:67
text_tag_init_from_sequence
static bool text_tag_init_from_sequence(struct text_tag *ptag, enum text_tag_type type, ft_offset_t start_offset, const char *sequence)
Definition featured_text.c:224
ftc_chat_private
const struct ft_color ftc_chat_private
Definition featured_text.c:88
featured_text_apply_tag
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,...)
Definition featured_text.c:993
ftc_luaconsole_debug
const struct ft_color ftc_luaconsole_debug
Definition featured_text.c:104
find_option
static bool find_option(const char *buf_in, const char *option, char *buf_out, size_t write_len)
Definition featured_text.c:175
ftc_vote_abstain
const struct ft_color ftc_vote_abstain
Definition featured_text.c:97
unit_tired_attack_string
const char * unit_tired_attack_string(const struct unit *punit)
Definition featured_text.c:1159
unit_veteran_level_string
const char * unit_veteran_level_string(const struct unit *punit)
Definition featured_text.c:1122
text_tag_link_type
enum text_link_type text_tag_link_type(const struct text_tag *ptag)
Definition featured_text.c:741
ftc_log
const struct ft_color ftc_log
Definition featured_text.c:76
ftc_player_lost
const struct ft_color ftc_player_lost
Definition featured_text.c:83
city_tile_link
const char * city_tile_link(const struct city *pcity)
Definition featured_text.c:1089
featured_text_to_plain_text
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)
Definition featured_text.c:864
ftc_luaconsole_verbose
const struct ft_color ftc_luaconsole_verbose
Definition featured_text.c:103
text_tag_copy
struct text_tag * text_tag_copy(const struct text_tag *ptag)
Definition featured_text.c:663
text_tag_list_rev_iterate
#define text_tag_list_rev_iterate(tags, ptag)
Definition featured_text.c:44
SEQ_STOP
#define SEQ_STOP
Definition featured_text.c:38
tile_link
const char * tile_link(const struct tile *ptile)
Definition featured_text.c:1106
SEQ_START
#define SEQ_START
Definition featured_text.c:37
ftc_command
const struct ft_color ftc_command
Definition featured_text.c:80
text_tag_stop_offset
ft_offset_t text_tag_stop_offset(const struct text_tag *ptag)
Definition featured_text.c:704
text_tag_initv
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)
Definition featured_text.c:388
unit_firepower_if_not_one
const char * unit_firepower_if_not_one(int firepower)
Definition featured_text.c:1180
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
ftc_vote_failed
const struct ft_color ftc_vote_failed
Definition featured_text.c:94
text_tag_destroy
void text_tag_destroy(struct text_tag *ptag)
Definition featured_text.c:680
ftc_vote_yes
const struct ft_color ftc_vote_yes
Definition featured_text.c:95
text_tag_start_sequence
static size_t text_tag_start_sequence(const struct text_tag *ptag, char *buf, size_t len)
Definition featured_text.c:471
ftc_luaconsole_error
const struct ft_color ftc_luaconsole_error
Definition featured_text.c:100
ftc_warning
const struct ft_color ftc_warning
Definition featured_text.c:75
text_tag_color_foreground
const char * text_tag_color_foreground(const struct text_tag *ptag)
Definition featured_text.c:713
text_tag_list_rev_iterate_end
#define text_tag_list_rev_iterate_end
Definition featured_text.c:46
text_link_type_name
static const char * text_link_type_name(enum text_link_type type)
Definition featured_text.c:157
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
ftc_luaconsole_normal
const struct ft_color ftc_luaconsole_normal
Definition featured_text.c:102
ftc_editor
const struct ft_color ftc_editor
Definition featured_text.c:79
text_tag_type_name
static const char * text_tag_type_name(enum text_tag_type type)
Definition featured_text.c:110
text_tag_replace_text
static size_t text_tag_replace_text(const struct text_tag *ptag, char *buf, size_t len, bool replace_link_text)
Definition featured_text.c:575
city_link
const char * city_link(const struct city *pcity)
Definition featured_text.c:1072
ftc_any
const struct ft_color ftc_any
Definition featured_text.c:73
ftc_vote_no
const struct ft_color ftc_vote_no
Definition featured_text.c:96
ftc_vote_passed
const struct ft_color ftc_vote_passed
Definition featured_text.c:93
MAX_LEN_STR
#define MAX_LEN_STR
Definition featured_text.c:41
log_featured_text
#define log_featured_text
Definition featured_text.c:42
text_tag_stop_sequence
static size_t text_tag_stop_sequence(const struct text_tag *ptag, char *buf, size_t len)
Definition featured_text.c:560
ftc_luaconsole_warn
const struct ft_color ftc_luaconsole_warn
Definition featured_text.c:101
extract_sequence_text
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)
Definition featured_text.c:770
text_tag_link_id
int text_tag_link_id(const struct text_tag *ptag)
Definition featured_text.c:756
ftc_chat_luaconsole
const struct ft_color ftc_chat_luaconsole
Definition featured_text.c:89
text_tag_type_short_name
static const char * text_tag_type_short_name(enum text_tag_type type)
Definition featured_text.c:134
text_tag_start_offset
ft_offset_t text_tag_start_offset(const struct text_tag *ptag)
Definition featured_text.c:696
text_tag_new
struct text_tag * text_tag_new(enum text_tag_type tag_type, ft_offset_t start_offset, ft_offset_t stop_offset,...)
Definition featured_text.c:638
ftc_vote_team
const struct ft_color ftc_vote_team
Definition featured_text.c:92
ftc_game_start
const struct ft_color ftc_game_start
Definition featured_text.c:84
unit_link
const char * unit_link(const struct unit *punit)
Definition featured_text.c:1200
ftc_server_prompt
const struct ft_color ftc_server_prompt
Definition featured_text.c:82
ftc_changed
struct ft_color ftc_changed
Definition featured_text.c:81
ftc_vote_public
const struct ft_color ftc_vote_public
Definition featured_text.c:91
sequence_type
sequence_type
Definition featured_text.c:66
ST_STOP
@ ST_STOP
Definition featured_text.c:68
ST_SINGLE
@ ST_SINGLE
Definition featured_text.c:69
ST_START
@ ST_START
Definition featured_text.c:67
unit_tile_link
const char * unit_tile_link(const struct unit *punit)
Definition featured_text.c:1217
text_tag_color_background
const char * text_tag_color_background(const struct text_tag *ptag)
Definition featured_text.c:727
ftc_luaconsole_input
const struct ft_color ftc_luaconsole_input
Definition featured_text.c:99
SEQ_END
#define SEQ_END
Definition featured_text.c:39
ftc_chat_public
const struct ft_color ftc_chat_public
Definition featured_text.c:86
unit_achieved_rank_string
const char * unit_achieved_rank_string(const struct unit *punit)
Definition featured_text.c:1142
ftc_chat_ally
const struct ft_color ftc_chat_ally
Definition featured_text.c:87
featured_text.h
text_tag_list_iterate_end
#define text_tag_list_iterate_end
Definition featured_text.h:116
text_tag_list_iterate
#define text_tag_list_iterate(tags, ptag)
Definition featured_text.h:114
FT_OFFSET_UNSET
#define FT_OFFSET_UNSET
Definition featured_text.h:104
MAX_LEN_LINK
#define MAX_LEN_LINK
Definition featured_text.h:138
text_tag_list_new
#define text_tag_list_new()
Definition featured_text.h:213
ft_offset_t
int ft_offset_t
Definition featured_text.h:102
text_link_type
text_link_type
Definition featured_text.h:131
TLT_TILE
@ TLT_TILE
Definition featured_text.h:133
TLT_UNIT
@ TLT_UNIT
Definition featured_text.h:134
TLT_CITY
@ TLT_CITY
Definition featured_text.h:132
text_tag_type
text_tag_type
Definition featured_text.h:120
TTT_LINK
@ TTT_LINK
Definition featured_text.h:126
TTT_BOLD
@ TTT_BOLD
Definition featured_text.h:121
TTT_ITALIC
@ TTT_ITALIC
Definition featured_text.h:122
TTT_STRIKE
@ TTT_STRIKE
Definition featured_text.h:123
TTT_COLOR
@ TTT_COLOR
Definition featured_text.h:125
TTT_UNDERLINE
@ TTT_UNDERLINE
Definition featured_text.h:124
FT_COLOR
#define FT_COLOR(fg, bg)
Definition featured_text.h:145
wld
struct world wld
Definition game.c:58
game_unit_by_number
struct unit * game_unit_by_number(int id)
Definition game.c:111
game_city_by_number
struct city * game_city_by_number(int id)
Definition game.c:102
game.h
type
GType type
Definition repodlgs.c:1312
name
const char * name
Definition inputfile.c:127
log.h
log_error
#define log_error(message,...)
Definition log.h:103
index_to_tile
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:454
map_pos_to_tile
struct tile * map_pos_to_tile(const struct civ_map *nmap, int map_x, int map_y)
Definition map.c:417
map.h
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
name_translation_get
static const char * name_translation_get(const struct name_translation *ptrans)
Definition name_translation.h:121
len
int len
Definition packhand.c:125
str_to_int
bool str_to_int(const char *str, int *pint)
Definition shared.c:512
shared.h
MIN
#define MIN(x, y)
Definition shared.h:55
city
Definition city.h:309
city::id
int id
Definition city.h:315
color
Definition colors.h:20
ft_color
Definition featured_text.h:141
option
Definition options.c:454
text_tag
Definition featured_text.c:49
text_tag::id
int id
Definition featured_text.c:60
text_tag::background
char background[MAX_LEN_STR]
Definition featured_text.c:56
text_tag::name
char name[MAX_LEN_STR]
Definition featured_text.c:61
text_tag::link
struct text_tag::@25::@28 link
text_tag::stop_offset
ft_offset_t stop_offset
Definition featured_text.c:52
text_tag::start_offset
ft_offset_t start_offset
Definition featured_text.c:51
text_tag::type
enum text_tag_type type
Definition featured_text.c:50
text_tag::foreground
char foreground[MAX_LEN_STR]
Definition featured_text.c:55
text_tag::color
struct text_tag::@25::@27 color
text_tag::type
enum text_link_type type
Definition featured_text.c:59
tile
Definition tile.h:49
unit
Definition unit.h:138
unit::moves_left
int moves_left
Definition unit.h:150
unit::id
int id
Definition unit.h:145
unit::veteran
int veteran
Definition unit.h:152
veteran_level
Definition unittype.h:467
veteran_level::name
struct name_translation name
Definition unittype.h:468
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
fc_isalpha
bool fc_isalpha(char c)
Definition support.c:1216
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
fc_isspace
bool fc_isspace(char c)
Definition support.c:1249
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1205
fc_strncasecmp
int fc_strncasecmp(const char *str0, const char *str1, size_t n)
Definition support.c:238
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:161
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tile.h
tile_index
#define tile_index(_pt_)
Definition tile.h:87
TILE_XY
#define TILE_XY(ptile)
Definition tile.h:42
unit.h
unit_tile
#define unit_tile(_pu)
Definition unit.h:388
unit_type_get
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:123
unit_name_translation
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1621
utype_veteran_level
const struct veteran_level * utype_veteran_level(const struct unit_type *punittype, int level)
Definition unittype.c:2631