NetSurf
nsoption.c
Go to the documentation of this file.
1/*
2 * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * Option reading and saving (implementation).
22 *
23 * Options are stored in the format key:value, one per line.
24 *
25 * For bool options, value is "0" or "1".
26 */
27
28#include <stdio.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <stdlib.h>
32#include <string.h>
33#include <strings.h>
34
35#include "netsurf/inttypes.h"
36#include "netsurf/plot_style.h"
37#include "utils/errors.h"
38#include "utils/log.h"
39#include "utils/utils.h"
40#include "utils/nsoption.h"
41
42/** Length of buffer used to read lines from input file */
43#define NSOPTION_MAX_LINE_LEN 1024
44
45struct nsoption_s *nsoptions = NULL;
47
48#define NSOPTION_BOOL(NAME, DEFAULT) \
49 { #NAME, sizeof(#NAME) - 1, OPTION_BOOL, { .b = DEFAULT } },
50
51#define NSOPTION_STRING(NAME, DEFAULT) \
52 { #NAME, sizeof(#NAME) - 1, OPTION_STRING, { .cs = DEFAULT } },
53
54#define NSOPTION_INTEGER(NAME, DEFAULT) \
55 { #NAME, sizeof(#NAME) - 1, OPTION_INTEGER, { .i = DEFAULT } },
56
57#define NSOPTION_UINT(NAME, DEFAULT) \
58 { #NAME, sizeof(#NAME) - 1, OPTION_UINT, { .u = DEFAULT } },
59
60#define NSOPTION_COLOUR(NAME, DEFAULT) \
61 { #NAME, sizeof(#NAME) - 1, OPTION_COLOUR, { .c = DEFAULT } },
62
63/** The table of compiled in default options */
64static struct nsoption_s defaults[] = {
65#include "desktop/options.h"
66
67#if defined(riscos)
68#include "riscos/options.h"
69#elif defined(nsgtk)
70#include "gtk/options.h"
71#elif defined(nsbeos)
72#include "beos/options.h"
73#elif defined(nsamiga)
74#include "amiga/options.h"
75#elif defined(nsframebuffer)
76#include "framebuffer/options.h"
77#elif defined(nsatari)
78#include "atari/options.h"
79#elif defined(nsmonkey)
80#include "monkey/options.h"
81#elif defined(nswin32)
82#include "windows/options.h"
83#endif
84 { NULL, 0, OPTION_INTEGER, { 0 } }
85};
86
87#undef NSOPTION_BOOL
88#undef NSOPTION_STRING
89#undef NSOPTION_INTEGER
90#undef NSOPTION_UINT
91#undef NSOPTION_COLOUR
92
93/**
94 * Set an option value based on a string
95 */
96static bool
97strtooption(const char *value, struct nsoption_s *option)
98{
99 bool ret = true;
100 colour rgbcolour; /* RRGGBB */
101
102 switch (option->type) {
103 case OPTION_BOOL:
104 option->value.b = (value[0] == '1');
105 break;
106
107 case OPTION_INTEGER:
108 option->value.i = atoi(value);
109 break;
110
111 case OPTION_UINT:
112 option->value.u = strtoul(value, NULL, 0);
113 break;
114
115 case OPTION_COLOUR:
116 if (sscanf(value, "%"SCNx32"", &rgbcolour) == 1) {
117 option->value.c = (((0x000000FF & rgbcolour) << 16) |
118 ((0x0000FF00 & rgbcolour) << 0) |
119 ((0x00FF0000 & rgbcolour) >> 16));
120 }
121 break;
122
123 case OPTION_STRING:
124 if (option->value.s != NULL) {
125 free(option->value.s);
126 }
127
128 if (*value == 0) {
129 /* do not allow empty strings in text options */
130 option->value.s = NULL;
131 } else {
132 option->value.s = strdup(value);
133 }
134 break;
135
136 default:
137 ret = false;
138 break;
139 }
140
141 return ret;
142}
143
144/* validate options to sane values */
145static void nsoption_validate(struct nsoption_s *opts, struct nsoption_s *defs)
146{
147 int cloop;
148 bool black = true;
149
150 if (opts[NSOPTION_treeview_font_size].value.i < 50) {
151 opts[NSOPTION_treeview_font_size].value.i = 50;
152 }
153
154 if (opts[NSOPTION_treeview_font_size].value.i > 1000) {
155 opts[NSOPTION_treeview_font_size].value.i = 1000;
156 }
157
158 if (opts[NSOPTION_font_size].value.i < 50) {
159 opts[NSOPTION_font_size].value.i = 50;
160 }
161
162 if (opts[NSOPTION_font_size].value.i > 1000) {
163 opts[NSOPTION_font_size].value.i = 1000;
164 }
165
166 if (opts[NSOPTION_font_min_size].value.i < 10) {
167 opts[NSOPTION_font_min_size].value.i = 10;
168 }
169
170 if (opts[NSOPTION_font_min_size].value.i > 500) {
171 opts[NSOPTION_font_min_size].value.i = 500;
172 }
173
174 if (opts[NSOPTION_memory_cache_size].value.i < 0) {
175 opts[NSOPTION_memory_cache_size].value.i = 0;
176 }
177
178 /* to aid migration from old, broken, configuration files this
179 * checks to see if all the system colours are set to black
180 * and returns them to defaults instead
181 */
182
183 for (cloop = NSOPTION_SYS_COLOUR_START;
185 cloop++) {
186 if (opts[cloop].value.c != 0) {
187 black = false;
188 break;
189 }
190 }
191 if (black == true && defs != NULL) {
192 for (cloop = NSOPTION_SYS_COLOUR_START;
194 cloop++) {
195 opts[cloop].value.c = defs[cloop].value.c;
196 }
197 }
198
199 /* To aid migration and ensure that timeouts don't go crazy,
200 * ensure that (a) we allow at least 1 attempt and
201 * (b) the total time that we spend should not exceed 60s
202 */
203 if (opts[NSOPTION_max_retried_fetches].value.u == 0)
204 opts[NSOPTION_max_retried_fetches].value.u = 1;
205 if (opts[NSOPTION_curl_fetch_timeout].value.u < 5)
206 opts[NSOPTION_curl_fetch_timeout].value.u = 5;
207 if (opts[NSOPTION_curl_fetch_timeout].value.u > 60)
208 opts[NSOPTION_curl_fetch_timeout].value.u = 60;
209 while (((opts[NSOPTION_curl_fetch_timeout].value.u *
210 opts[NSOPTION_max_retried_fetches].value.u) > 60) &&
211 (opts[NSOPTION_max_retried_fetches].value.u > 1))
212 opts[NSOPTION_max_retried_fetches].value.u--;
213
214 /* We ignore the result because we can't fail to validate. Yay */
216}
217
218/**
219 * Determines if an option is different between two option tables.
220 *
221 * @param opts The first table to compare.
222 * @param defs The second table to compare.
223 * @param entry The option to compare.
224 * @return true if the option differs false if not.
225 */
226static bool
227nsoption_is_set(const struct nsoption_s *opts,
228 const struct nsoption_s *defs,
229 const enum nsoption_e entry)
230{
231 bool ret = false;
232
233 switch (opts[entry].type) {
234 case OPTION_BOOL:
235 if (opts[entry].value.b != defs[entry].value.b) {
236 ret = true;
237 }
238 break;
239
240 case OPTION_INTEGER:
241 if (opts[entry].value.i != defs[entry].value.i) {
242 ret = true;
243 }
244 break;
245
246 case OPTION_UINT:
247 if (opts[entry].value.u != defs[entry].value.u) {
248 ret = true;
249 }
250 break;
251
252 case OPTION_COLOUR:
253 if (opts[entry].value.c != defs[entry].value.c) {
254 ret = true;
255 }
256 break;
257
258 case OPTION_STRING:
259 /* set if:
260 * - defs is null.
261 * - default is null but value is not.
262 * - default and value pointers are different
263 * (acts as a null check because of previous check)
264 * and the strings content differ.
265 */
266 if (((defs[entry].value.s == NULL) &&
267 (opts[entry].value.s != NULL)) ||
268 ((defs[entry].value.s != NULL) &&
269 (opts[entry].value.s == NULL)) ||
270 ((defs[entry].value.s != opts[entry].value.s) &&
271 (strcmp(opts[entry].value.s, defs[entry].value.s) != 0))) {
272 ret = true;
273 }
274 break;
275
276 }
277 return ret;
278}
279
280/**
281 * Output an option value into a file stream, in plain text format.
282 *
283 * @param option The option to output the value of.
284 * @param fp The file stream to write to.
285 * @return The number of bytes written to string or -1 on error
286 */
287static size_t nsoption_output_value_file(struct nsoption_s *option, void *ctx)
288{
289 FILE *fp = ctx;
290 size_t slen = 0; /* length added to stream */
291 colour rgbcolour; /* RRGGBB */
292
293 switch (option->type) {
294 case OPTION_BOOL:
295 slen = fprintf(fp, "%s:%c\n", option->key, option->value.b ? '1' : '0');
296 break;
297
298 case OPTION_INTEGER:
299 slen = fprintf(fp, "%s:%i\n", option->key, option->value.i);
300
301 break;
302
303 case OPTION_UINT:
304 slen = fprintf(fp, "%s:%u\n", option->key, option->value.u);
305 break;
306
307 case OPTION_COLOUR:
308 rgbcolour = (((0x000000FF & option->value.c) << 16) |
309 ((0x0000FF00 & option->value.c) << 0) |
310 ((0x00FF0000 & option->value.c) >> 16));
311 slen = fprintf(fp, "%s:%06"PRIx32"\n", option->key, rgbcolour);
312 break;
313
314 case OPTION_STRING:
315 slen = fprintf(fp, "%s:%s\n",
316 option->key,
317 ((option->value.s == NULL) ||
318 (*option->value.s == 0)) ? "" : option->value.s);
319 break;
320 }
321
322 return slen;
323}
324
325/**
326 * Output an option value into a string, in HTML format.
327 *
328 * @param option The option to output the value of.
329 * @param size The size of the string buffer.
330 * @param pos The current position in string
331 * @param string The string in which to output the value.
332 * @return The number of bytes written to string or -1 on error
333 */
334static size_t
336 size_t size,
337 size_t pos,
338 char *string)
339{
340 size_t slen = 0; /* length added to string */
341 colour rgbcolour; /* RRGGBB */
342
343 switch (option->type) {
344 case OPTION_BOOL:
345 slen = snprintf(string + pos,
346 size - pos,
347 "%s",
348 option->value.b ? "true" : "false");
349 break;
350
351 case OPTION_INTEGER:
352 slen = snprintf(string + pos,
353 size - pos,
354 "%i",
355 option->value.i);
356 break;
357
358 case OPTION_UINT:
359 slen = snprintf(string + pos,
360 size - pos,
361 "%u",
362 option->value.u);
363 break;
364
365 case OPTION_COLOUR:
366 rgbcolour = colour_rb_swap(option->value.c);
367 slen = snprintf(string + pos,
368 size - pos,
369 "<span style=\"font-family:Monospace;\">"
370 "#%06"PRIX32
371 "</span> "
372 "<span style=\"background-color: #%06"PRIx32"; "
373 "border: 1px solid #%06"PRIx32"; "
374 "display: inline-block; "
375 "width: 1em; height: 1em;\">"
376 "</span>",
377 rgbcolour,
378 rgbcolour,
379 colour_to_bw_furthest(rgbcolour));
380 break;
381
382 case OPTION_STRING:
383 if (option->value.s != NULL) {
384 slen = snprintf(string + pos, size - pos, "%s",
385 option->value.s);
386 } else {
387 slen = snprintf(string + pos, size - pos,
388 "<span class=\"null-content\">NULL"
389 "</span>");
390 }
391 break;
392 }
393
394 return slen;
395}
396
397
398/**
399 * Output an option value into a string, in plain text format.
400 *
401 * @param option The option to output the value of.
402 * @param size The size of the string buffer.
403 * @param pos The current position in string
404 * @param string The string in which to output the value.
405 * @return The number of bytes written to string or -1 on error
406 */
407static size_t
409 size_t size,
410 size_t pos,
411 char *string)
412{
413 size_t slen = 0; /* length added to string */
414 colour rgbcolour; /* RRGGBB */
415
416 switch (option->type) {
417 case OPTION_BOOL:
418 slen = snprintf(string + pos,
419 size - pos,
420 "%c",
421 option->value.b ? '1' : '0');
422 break;
423
424 case OPTION_INTEGER:
425 slen = snprintf(string + pos,
426 size - pos,
427 "%i",
428 option->value.i);
429 break;
430
431 case OPTION_UINT:
432 slen = snprintf(string + pos,
433 size - pos,
434 "%u",
435 option->value.u);
436 break;
437
438 case OPTION_COLOUR:
439 rgbcolour = (((0x000000FF & option->value.c) << 16) |
440 ((0x0000FF00 & option->value.c) << 0) |
441 ((0x00FF0000 & option->value.c) >> 16));
442 slen = snprintf(string + pos, size - pos, "%06"PRIx32, rgbcolour);
443 break;
444
445 case OPTION_STRING:
446 if (option->value.s != NULL) {
447 slen = snprintf(string + pos,
448 size - pos,
449 "%s",
450 option->value.s);
451 }
452 break;
453 }
454
455 return slen;
456}
457
458/**
459 * Duplicates an option table.
460 *
461 * Allocates a new option table and copies an existing one into it.
462 *
463 * \param[in] src The source table to copy
464 * \param[out] pdst The output table
465 * \return NSERROR_OK on success or appropriate error code.
466 */
467static nserror
468nsoption_dup(struct nsoption_s *src, struct nsoption_s **pdst)
469{
470 struct nsoption_s *dst;
471 dst = malloc(sizeof(defaults));
472 if (dst == NULL) {
473 return NSERROR_NOMEM;
474 }
475 *pdst = dst;
476
477 /* copy the source table into the destination table */
478 memcpy(dst, src, sizeof(defaults));
479
480 while (src->key != NULL) {
481 if ((src->type == OPTION_STRING) &&
482 (src->value.s != NULL)) {
483 dst->value.s = strdup(src->value.s);
484 }
485 src++;
486 dst++;
487 }
488
489 return NSERROR_OK;
490}
491
492/**
493 * frees an option table.
494 *
495 * Iterates through an option table a freeing resources as required
496 * finally freeing the option table itself.
497 *
498 * @param opts The option table to free.
499 */
500static nserror
502{
503 struct nsoption_s *cur; /* option being freed */
504
505 if (opts == NULL) {
507 }
508
509 cur = opts;
510
511 while (cur->key != NULL) {
512 if ((cur->type == OPTION_STRING) && (cur->value.s != NULL)) {
513 free(cur->value.s);
514 }
515 cur++;
516 }
517 free(opts);
518
519 return NSERROR_OK;
520}
521
522
523/**
524 * extract key/value from a line of input
525 *
526 * \retun NSERROR_OK and key_out and value_out updated
527 * NSERROR_NOT_FOUND if not a key/value input line
528 * NSERROR_INVALID if the line is and invalid format (missing colon)
529 */
530static nserror
531get_key_value(char *line, int linelen, char **key_out, char **value_out)
532{
533 char *key;
534 char *value;
535
536 /* skip leading whitespace for start of key */
537 for (key = line; *key != 0; key++) {
538 if ((*key != ' ') && (*key != '\t') && (*key != '\n')) {
539 break;
540 }
541 }
542
543 /* empty line or only whitespace */
544 if (*key == 0) {
545 return NSERROR_NOT_FOUND;
546 }
547
548 /* comment */
549 if (*key == '#') {
550 return NSERROR_NOT_FOUND;
551 }
552
553 /* get start of value */
554 for (value = key; *value != 0; value++) {
555 if (*value == ':') {
556 *value = 0;
557 value++;
558 break;
559 }
560 }
561
562 /* missing colon separator */
563 if (*value == 0) {
564 return NSERROR_INVALID;
565 }
566
567 /* remove delimiter from value */
568 if (line[linelen - 1] == '\n') {
569 linelen--;
570 line[linelen] = 0;
571 }
572
573 *key_out = key;
574 *value_out = value;
575 return NSERROR_OK;
576}
577
578
579/**
580 * Process a line from a user option file
581 */
582static nserror optionline(struct nsoption_s *opts, char *line, int linelen)
583{
584 nserror res;
585 char *key;
586 char *value;
587 int idx;
588
589 res = get_key_value(line, linelen, &key, &value);
590 if (res != NSERROR_OK) {
591 /* skip line as no valid key value pair found */
592 return res;
593 }
594
595 for (idx = 0; opts[idx].key != NULL; idx++) {
596 if (strcasecmp(key, opts[idx].key) == 0) {
597 strtooption(value, &opts[idx]);
598 break;
599 }
600 }
601
602 return res;
603}
604
605
606/* exported interface documented in utils/nsoption.h */
609 struct nsoption_s **popts,
610 struct nsoption_s **pdefs)
611{
612 nserror ret;
613 struct nsoption_s *defs;
614 struct nsoption_s *opts;
615
616 ret = nsoption_dup(&defaults[0], &defs);
617 if (ret != NSERROR_OK) {
618 return ret;
619 }
620
621 /* update the default table */
622 if (set_defaults != NULL) {
623 /** @todo it would be better if the frontends actually
624 * set values in the passed in table instead of
625 * assuming the global one.
626 */
627 opts = nsoptions;
628 nsoptions = defs;
629
630 ret = set_defaults(defs);
631
632 if (ret != NSERROR_OK) {
633 nsoptions = opts;
634 nsoption_free(defs);
635 return ret;
636 }
637 }
638
639 /* copy the default values into the working set */
640 ret = nsoption_dup(defs, &opts);
641 if (ret != NSERROR_OK) {
642 nsoption_free(defs);
643 return ret;
644 }
645
646 /* return values if wanted */
647 if (popts != NULL) {
648 *popts = opts;
649 } else {
650 nsoptions = opts;
651 }
652
653 if (pdefs != NULL) {
654 *pdefs = defs;
655 } else {
656 nsoptions_default = defs;
657 }
658
659 return NSERROR_OK;
660}
661
662/* exported interface documented in utils/nsoption.h */
664{
665 nserror res;
666
667 /* check to see if global table selected */
668 if (opts == NULL) {
670 if (res == NSERROR_OK) {
671 nsoptions = NULL;
672 }
673 } else {
674 res = nsoption_free(opts);
675 }
676 if (res != NSERROR_OK) {
677 return res;
678 }
679
680 /* check to see if global table selected */
681 if (defs == NULL) {
683 if (res == NSERROR_OK) {
684 nsoptions_default = NULL;
685 }
686 } else {
687 res = nsoption_free(defs);
688 }
689
690 return res;
691}
692
693
694/* exported interface documented in utils/nsoption.h */
696nsoption_read(const char *path, struct nsoption_s *opts)
697{
699 FILE *fp;
700 struct nsoption_s *defs;
701
702 if (path == NULL) {
704 }
705
706 /* check to see if global table selected */
707 if (opts == NULL) {
708 opts = nsoptions;
709 }
710
711 /**
712 * @todo is this an API bug not being a parameter
713 */
714 defs = nsoptions_default;
715
716 if ((opts == NULL) || (defs == NULL)) {
718 }
719
720 fp = fopen(path, "r");
721 if (!fp) {
722 NSLOG(netsurf, INFO, "Failed to open file '%s'", path);
723 return NSERROR_NOT_FOUND;
724 }
725
726 NSLOG(netsurf, INFO, "Successfully opened '%s' for Options file", path);
727
728 while (fgets(s, NSOPTION_MAX_LINE_LEN, fp)) {
729 optionline(opts, s, strlen(s));
730 }
731
732 fclose(fp);
733
734 nsoption_validate(opts, defs);
735
736 return NSERROR_OK;
737}
738
739
740/*
741 * Generate options via callback.
742 *
743 * exported interface documented in utils/nsoption.h
744 */
747 void *generate_ctx,
748 enum nsoption_generate_flags flags,
749 struct nsoption_s *opts,
750 struct nsoption_s *defs)
751{
752 unsigned int entry; /* index to option being output */
753
754 /* check to see if global table selected */
755 if (opts == NULL) {
756 opts = nsoptions;
757 }
758
759 /* check to see if global table selected */
760 if (defs == NULL) {
761 defs = nsoptions_default;
762 }
763
764 if ((opts == NULL) || (defs == NULL)) {
766 }
767
768 for (entry = 0; entry < NSOPTION_LISTEND; entry++) {
769 if (((flags & NSOPTION_GENERATE_CHANGED) != 0) &&
770 (nsoption_is_set(opts, defs, entry) == false)) {
771 continue;
772 }
773 generate_cb(opts + entry, generate_ctx);
774 }
775
776 return NSERROR_OK;
777}
778
779
780/*
781 * Write options that have changed from the defaults to a file.
782 *
783 * exported interface documented in utils/nsoption.h
784 */
787 struct nsoption_s *opts,
788 struct nsoption_s *defs)
789{
790 FILE *fp;
791 nserror ret;
792
793 if (path == NULL) {
795 }
796
797 /* check to see if global table selected */
798 if (opts == NULL) {
799 opts = nsoptions;
800 }
801
802 /* check to see if global table selected */
803 if (defs == NULL) {
804 defs = nsoptions_default;
805 }
806
807 if ((opts == NULL) || (defs == NULL)) {
809 }
810
811 fp = fopen(path, "w");
812 if (!fp) {
813 NSLOG(netsurf, INFO, "failed to open file '%s' for writing",
814 path);
815 return NSERROR_NOT_FOUND;
816 }
817
819 fp,
821 opts,
822 defs);
823
824 fclose(fp);
825
826 return ret;
827}
828
829
830/* exported interface documented in utils/nsoption.h */
832nsoption_dump(FILE *outf, struct nsoption_s *opts)
833{
834 if (outf == NULL) {
836 }
837
838 /* check to see if global table selected and available */
839 if (opts == NULL) {
840 opts = nsoptions;
841 }
842 if (opts == NULL) {
844 }
845
847 outf,
849 opts,
851}
852
853
854/* exported interface documented in utils/nsoption.h */
856nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
857{
858 char *arg;
859 char *val;
860 int arglen;
861 int idx = 1;
862 int mv_loop;
863 unsigned int entry_loop;
864
865 if ((pargc == NULL) || (argv == NULL)) {
867 }
868
869 /* check to see if global table selected and available */
870 if (opts == NULL) {
871 opts = nsoptions;
872 }
873 if (opts == NULL) {
875 }
876
877 while (idx < *pargc) {
878 arg = argv[idx];
879 arglen = strlen(arg);
880
881 /* check we have an option */
882 /* option must start -- and be as long as the shortest option*/
883 if ((arglen < (2+5) ) || (arg[0] != '-') || (arg[1] != '-'))
884 break;
885
886 arg += 2; /* skip -- */
887
888 val = strchr(arg, '=');
889 if (val == NULL) {
890 /* no equals sign - next parameter is val */
891 idx++;
892 if (idx >= *pargc)
893 break;
894 val = argv[idx];
895 } else {
896 /* equals sign */
897 arglen = val - arg ;
898 val++;
899 }
900
901 /* arg+arglen is the option to set, val is the value */
902
903 NSLOG(netsurf, INFO, "%.*s = %s", arglen, arg, val);
904
905 for (entry_loop = 0;
906 entry_loop < NSOPTION_LISTEND;
907 entry_loop++) {
908 if (strncmp(arg, opts[entry_loop].key, arglen) == 0) {
909 strtooption(val, opts + entry_loop);
910 break;
911 }
912 }
913
914 idx++;
915 }
916
917 /* remove processed options from argv */
918 for (mv_loop=0; mv_loop < (*pargc - idx); mv_loop++) {
919 argv[mv_loop + 1] = argv[mv_loop + idx];
920 }
921 *pargc -= (idx - 1);
922
924
925 return NSERROR_OK;
926}
927
928/* exported interface documented in options.h */
929int
931 size_t size,
932 enum nsoption_e option_idx,
933 const char *fmt)
934{
935 size_t slen = 0; /* current output string length */
936 int fmtc = 0; /* current index into format string */
937 struct nsoption_s *option;
938
939 if (fmt == NULL) {
940 return -1;
941 }
942
943 if (option_idx >= NSOPTION_LISTEND) {
944 return -1;
945 }
946
947 if (nsoptions == NULL) {
948 return -1;
949 }
950
951 option = &nsoptions[option_idx]; /* assume the global table */
952 if (option == NULL || option->key == NULL) {
953 return -1;
954 }
955
956 while ((slen < size) && (fmt[fmtc] != 0)) {
957 if (fmt[fmtc] == '%') {
958 fmtc++;
959 switch (fmt[fmtc]) {
960 case 'k':
961 slen += snprintf(string + slen,
962 size - slen,
963 "%s",
964 option->key);
965 break;
966
967 case 'p':
970 option_idx)) {
971 slen += snprintf(string + slen,
972 size - slen,
973 "user");
974 } else {
975 slen += snprintf(string + slen,
976 size - slen,
977 "default");
978 }
979 break;
980
981 case 't':
982 switch (option->type) {
983 case OPTION_BOOL:
984 slen += snprintf(string + slen,
985 size - slen,
986 "boolean");
987 break;
988
989 case OPTION_INTEGER:
990 slen += snprintf(string + slen,
991 size - slen,
992 "integer");
993 break;
994
995 case OPTION_UINT:
996 slen += snprintf(string + slen,
997 size - slen,
998 "unsigned integer");
999 break;
1000
1001 case OPTION_COLOUR:
1002 slen += snprintf(string + slen,
1003 size - slen,
1004 "colour");
1005 break;
1006
1007 case OPTION_STRING:
1008 slen += snprintf(string + slen,
1009 size - slen,
1010 "string");
1011 break;
1012
1013 }
1014 break;
1015
1016
1017 case 'V':
1018 slen += nsoption_output_value_html(option,
1019 size,
1020 slen,
1021 string);
1022 break;
1023 case 'v':
1024 slen += nsoption_output_value_text(option,
1025 size,
1026 slen,
1027 string);
1028 break;
1029 }
1030 fmtc++;
1031 } else {
1032 string[slen] = fmt[fmtc];
1033 slen++;
1034 fmtc++;
1035 }
1036 }
1037
1038 /* Ensure that we NUL-terminate the output */
1039 string[min(slen, size - 1)] = '\0';
1040
1041 return slen;
1042}
1043
1044/* exported interface documented in options.h */
1045nserror
1047 enum nsoption_e option_idx,
1048 char *s)
1049{
1050 struct nsoption_s *option;
1051
1052 option = &opts[option_idx];
1053
1054 /* ensure it is a string option */
1055 if (option->type != OPTION_STRING) {
1056 return NSERROR_BAD_PARAMETER;
1057 }
1058
1059 /* free any existing string */
1060 if (option->value.s != NULL) {
1061 free(option->value.s);
1062 }
1063
1064 option->value.s = s;
1065
1066 /* check for empty string */
1067 if ((option->value.s != NULL) && (*option->value.s == 0)) {
1068 free(option->value.s);
1069 option->value.s = NULL;
1070 }
1071 return NSERROR_OK;
1072}
static nserror set_defaults(struct nsoption_s *defaults)
Set option defaults for atari frontend.
Definition: gui.c:910
Option available on all platforms.
#define NSOPTION_SYS_COLOUR_END
Definition: options.h:38
#define NSOPTION_SYS_COLOUR_START
Definition: options.h:37
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_INVALID
Invalid data.
Definition: errors.h:49
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
Option specific to RISC OS.
Netsurf additional integer type formatting macros.
nserror nslog_set_filter_by_options(void)
Set the logging filter according to the options.
Definition: log.c:289
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
plotter style interfaces, generic styles and style colour helpers.
#define colour_to_bw_furthest(c0)
Definition: plot_style.h:193
#define colour_rb_swap(c)
Definition: plot_style.h:217
Interface to utility string handling.
bool b
Definition: nsoption.h:115
const char * key
Definition: nsoption.h:111
union nsoption_s::@149 value
enum nsoption_type_e type
Definition: nsoption.h:113
colour c
Definition: nsoption.h:120
unsigned int u
Definition: nsoption.h:117
char * s
Definition: nsoption.h:118
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
struct nsoption_s * nsoptions_default
global default option table.
Definition: nsoption.c:46
static bool strtooption(const char *value, struct nsoption_s *option)
Set an option value based on a string.
Definition: nsoption.c:97
#define NSOPTION_MAX_LINE_LEN
Length of buffer used to read lines from input file.
Definition: nsoption.c:43
static size_t nsoption_output_value_html(struct nsoption_s *option, size_t size, size_t pos, char *string)
Output an option value into a string, in HTML format.
Definition: nsoption.c:335
static nserror nsoption_dup(struct nsoption_s *src, struct nsoption_s **pdst)
Duplicates an option table.
Definition: nsoption.c:468
int nsoption_snoptionf(char *string, size_t size, enum nsoption_e option_idx, const char *fmt)
Fill a buffer with an option using a format.
Definition: nsoption.c:930
static bool nsoption_is_set(const struct nsoption_s *opts, const struct nsoption_s *defs, const enum nsoption_e entry)
Determines if an option is different between two option tables.
Definition: nsoption.c:227
nserror nsoption_generate(nsoption_generate_cb *generate_cb, void *generate_ctx, enum nsoption_generate_flags flags, struct nsoption_s *opts, struct nsoption_s *defs)
Generate options via acallback.
Definition: nsoption.c:746
static size_t nsoption_output_value_file(struct nsoption_s *option, void *ctx)
Output an option value into a file stream, in plain text format.
Definition: nsoption.c:287
static nserror optionline(struct nsoption_s *opts, char *line, int linelen)
Process a line from a user option file.
Definition: nsoption.c:582
nserror nsoption_set_tbl_charp(struct nsoption_s *opts, enum nsoption_e option_idx, char *s)
Set string option in specified table.
Definition: nsoption.c:1046
static struct nsoption_s defaults[]
The table of compiled in default options.
Definition: nsoption.c:64
static void nsoption_validate(struct nsoption_s *opts, struct nsoption_s *defs)
Definition: nsoption.c:145
nserror nsoption_dump(FILE *outf, struct nsoption_s *opts)
Write all options to a stream.
Definition: nsoption.c:832
nserror nsoption_read(const char *path, struct nsoption_s *opts)
Read choices file and set them in the passed table.
Definition: nsoption.c:696
struct nsoption_s * nsoptions
global active option table.
Definition: nsoption.c:45
static nserror nsoption_free(struct nsoption_s *opts)
frees an option table.
Definition: nsoption.c:501
nserror nsoption_commandline(int *pargc, char **argv, struct nsoption_s *opts)
Process commandline and set options approriately.
Definition: nsoption.c:856
nserror nsoption_init(nsoption_set_default_t *set_defaults, struct nsoption_s **popts, struct nsoption_s **pdefs)
Initialise option system.
Definition: nsoption.c:608
nserror nsoption_write(const char *path, struct nsoption_s *opts, struct nsoption_s *defs)
Write options that have changed from the defaults to a file.
Definition: nsoption.c:786
nserror nsoption_finalise(struct nsoption_s *opts, struct nsoption_s *defs)
Finalise option system.
Definition: nsoption.c:663
static nserror get_key_value(char *line, int linelen, char **key_out, char **value_out)
extract key/value from a line of input
Definition: nsoption.c:531
static size_t nsoption_output_value_text(struct nsoption_s *option, size_t size, size_t pos, char *string)
Output an option value into a string, in plain text format.
Definition: nsoption.c:408
Option reading and saving interface.
size_t() nsoption_generate_cb(struct nsoption_s *option, void *ctx)
option generate callback
Definition: nsoption.h:180
nsoption_e
Definition: nsoption.h:131
@ NSOPTION_LISTEND
Definition: nsoption.h:150
nserror() nsoption_set_default_t(struct nsoption_s *defaults)
default setting callback.
Definition: nsoption.h:174
@ OPTION_STRING
option is a heap allocated string.
Definition: nsoption.h:106
@ OPTION_COLOUR
Option is a netsurf colour.
Definition: nsoption.h:107
@ OPTION_UINT
Option is an unsigned integer.
Definition: nsoption.h:105
@ OPTION_INTEGER
Option is an integer.
Definition: nsoption.h:104
@ OPTION_BOOL
Option is a boolean.
Definition: nsoption.h:103
nsoption_generate_flags
flags to control option output in the generate call
Definition: nsoption.h:186
@ NSOPTION_GENERATE_ALL
Generate output for all options.
Definition: nsoption.h:188
@ NSOPTION_GENERATE_CHANGED
Generate output for options which differ from the default.
Definition: nsoption.h:190
Interface to a number of general purpose functionality.
#define min(x, y)
Definition: utils.h:46
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821
static nserror line(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *line)
Plots a line.
Definition: plot.c:579