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