1 /*
2 * This file is part of XForms.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "fd_main.h"
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <limits.h>
28 #include <float.h>
29 #include <ctype.h>
30 #include <stdarg.h>
31
32
33 static struct
34 {
35 FILE * fp;
36 char * fname;
37 size_t line_no;
38 char * line;
39 char * pos;
40 int merge;
41 } ff = { NULL, NULL, 0, NULL, NULL, 0 };
42
43
44
45 /***************************************
46 * Returns a pointer to the first position in a string
47 * that's not a white-space character
48 ***************************************/
49
50 static char *
ff_skip_spaces(const char * cp)51 ff_skip_spaces( const char * cp )
52 {
53 while ( *cp && isspace( ( unsigned char ) *cp ) )
54 cp++;
55
56 return ( char * ) cp;
57 }
58
59
60 /***************************************
61 ***************************************/
62
63 char *
ff_get_filename_copy(void)64 ff_get_filename_copy( void )
65 {
66 if ( ! ff.fname || ! ff.fp )
67 return NULL;
68
69 return fl_strdup( ff.fname );
70 }
71
72
73 /***************************************
74 ***************************************/
75
76 static int
ff_is_comment(void)77 ff_is_comment( void )
78 {
79 ff.pos = ff_skip_spaces( ff.pos );
80
81 return ! *ff.pos
82 || *ff.pos == ';'
83 || *ff.pos == '#'
84 || *ff.pos == '-'
85 || *ff.pos == '=';
86 }
87
88
89 /***************************************
90 ***************************************/
91
92 void
ff_close(void)93 ff_close( void )
94 {
95 if ( ff.fp )
96 {
97 fclose( ff.fp );
98 ff.fp = NULL;
99 }
100
101 fli_safe_free( ff.fname );
102 fli_safe_free( ff.line );
103
104 ff.pos = NULL;
105 ff.line_no = 0;
106 ff.merge = 0;
107 }
108
109
110 /***************************************
111 ***************************************/
112
113 int
ff_err(const char * message)114 ff_err( const char * message )
115 {
116 if ( message )
117 {
118 if ( ! fdopt.conv_only )
119 fl_show_alert_f( 0, "Error:\f%s\n%s:%lu.%lu",
120 message, ff.fname, ( unsigned long ) ff.line_no,
121 ff.line ?
122 ( unsigned long ) ( ff.pos - ff.line ) : 0 );
123 else
124 M_err( "Error", "%s at %s:%lu.%lu",
125 message, ff.fname, ( unsigned long ) ff.line_no,
126 ff.line ? ( unsigned long ) ( ff.pos - ff.line ) : 0 );
127 }
128
129 ff_close( );
130 return FF_READ_FAILURE;
131 }
132
133
134 /***************************************
135 ***************************************/
136
137 static int
ff_get_line(void)138 ff_get_line( void )
139 {
140 if ( ff.fp )
141 do
142 {
143 fli_safe_free( ff.line );
144
145 if ( ! ( ff.line = fli_read_line( ff.fp ) ) )
146 {
147 if ( feof( ff.fp ) )
148 {
149 ff.line_no++;
150 return 0;
151 }
152 return ff_err( "Error while reading from file" );
153 }
154
155 ff.line_no++;
156 ff.pos = ff.line;
157 } while ( ff_is_comment( ) );
158
159 return 0;
160 }
161
162
163 /***************************************
164 ***************************************/
165
166 int
ff_get_fd_file(const char * str,int merge)167 ff_get_fd_file( const char * str,
168 int merge )
169 {
170 ff_close( );
171
172 ff.merge = merge;
173
174 fl_use_fselector( LOAD_FSELECTOR );
175
176 /* Get the filename if necessary */
177
178 if ( ! str || ! *str )
179 {
180 str = fl_show_fselector( merge ? "Filename to merge forms from" :
181 "Filename to load forms from",
182 "", "*.fd", "" );
183
184 if ( ! str || ! *str )
185 return -1;
186 }
187
188 /* Append ".fd" if required. */
189
190 ff.fname = append_fd_suffix( str );
191
192 /* Open the file for reading */
193
194 if ( ! ( ff.fp = fopen( ff.fname, "r" ) ) )
195 {
196 if ( ! fdopt.conv_only )
197 fl_show_alert( "Can't open file for reading", ff.fname, "", 0 );
198 else
199 M_err( "ff_get_fd_file", "Can't open '%s' for reading", ff.fname );
200 ff_close( );
201 return -1;
202 }
203
204 if ( ff_get_line( ) < 0 )
205 {
206 if ( ! fdopt.conv_only )
207 fl_show_alert( "Nothing to be read from", ff.fname, "", 0 );
208 else
209 M_err( "ff_get_fd_file", "Nothing to be read from '%s'",
210 ff.fname );
211 ff_close( );
212 return -1;
213 }
214
215 return 0;
216 }
217
218
219 /***************************************
220 * Checks if an input text matches text read from the file
221 * - with multiple white-spaces treated as a single space
222 ***************************************/
223
224 static const char *
ff_match_text(const char * txt)225 ff_match_text( const char *txt )
226 {
227 char *src = ff.pos;
228
229 txt = ff_skip_spaces( txt );
230
231 while ( *src && *txt )
232 {
233 if ( *src != *txt
234 && ! ( isspace( ( unsigned char ) *src )
235 && isspace( ( unsigned char ) *txt ) ) )
236 return NULL;
237
238 if ( isspace( ( unsigned char ) *src ) )
239 {
240 src = ff_skip_spaces( src );
241 txt = ff_skip_spaces( txt );
242 }
243 else
244 {
245 src++;
246 txt++;
247 }
248 }
249
250 txt = ff_skip_spaces( txt );
251 if ( *txt )
252 return NULL;
253
254 ff.pos = src;
255
256 return txt;
257 }
258
259
260 /***************************************
261 ***************************************/
262
263 static int
ff_match_long(long * p)264 ff_match_long( long * p )
265 {
266 long val;
267 char *ep;
268
269 val = strtol( ff.pos, &ep, 10 );
270
271 if ( ep == ff.pos )
272 return -1;
273
274 if ( *ep != '\0' && ! isspace( ( unsigned char ) *ep ) )
275 return -1;
276
277 if ( ( val == LONG_MAX || val == LONG_MIN ) && errno == ERANGE )
278 return -1;
279
280 ff.pos = ep;
281
282 *p = val;
283 return 0;
284 }
285
286
287 /***************************************
288 ***************************************/
289
290 static int
ff_match_ulong(unsigned long * p)291 ff_match_ulong( unsigned long * p )
292 {
293 unsigned long val;
294 char *ep;
295
296 if ( *ff.pos == '-' )
297 return -1;
298
299 val = strtoul( ff.pos, &ep, 10 );
300
301 if ( ep == ff.pos
302 || ( *ep != '\0' && ! isspace( ( unsigned char ) *ep ) )
303 || ( val == ULONG_MAX && errno == ERANGE ) )
304 return -1;
305
306 ff.pos = ep;
307
308 *p = val;
309 return 0;
310 }
311
312
313 /***************************************
314 ***************************************/
315
316 static int
ff_match_int(int * p)317 ff_match_int( int * p )
318 {
319 long val;
320 char *old_pos = ff.pos;
321
322 if ( ff_match_long( &val ) < 0 )
323 return -1;
324
325 if ( ( val > INT_MAX || val < INT_MIN ) )
326 {
327 ff.pos = old_pos;
328 return -1;
329 }
330
331 *p = val;
332 return 0;
333 }
334
335
336 /***************************************
337 ***************************************/
338
339 static int
ff_match_uint(unsigned int * p)340 ff_match_uint( unsigned int * p )
341 {
342 unsigned long val;
343 char *old_pos = ff.pos;
344
345 if ( ff_match_ulong( &val ) < 0 )
346 return -1;
347
348 if ( val > UINT_MAX )
349 {
350 ff.pos = old_pos;
351 return -1;
352 }
353
354 *p = val;
355 return 0;
356 }
357
358
359 /***************************************
360 ***************************************/
361
362 static int
ff_match_double(double * p)363 ff_match_double( double * p )
364 {
365 double val;
366 char *ep;
367
368 val = strtod( ff.pos, &ep );
369
370 if ( ep == ff.pos
371 || ( *ep != '\0' && ! isspace( ( unsigned char ) *ep ) )
372 || ( ( val == HUGE_VAL || val == - HUGE_VAL ) && errno == ERANGE ) )
373 return -1;
374
375 ff.pos = ep;
376
377 *p = val;
378 return 0;
379 }
380
381
382 /***************************************
383 ***************************************/
384
385 static int
ff_match_float(float * p)386 ff_match_float( float * p )
387 {
388 double val;
389 char *old_pos = ff.pos;
390
391 if ( ff_match_double( &val ) < 0 || val < - FLT_MAX || val > FLT_MAX)
392 {
393 ff.pos = old_pos;
394 return -1;
395 }
396
397 *p = val;
398 return 0;
399 }
400
401
402 /***************************************
403 ***************************************/
404
405 static int
ff_match_coord(FL_Coord * p,int need_positive)406 ff_match_coord( FL_Coord * p,
407 int need_positive )
408 {
409 int val;
410 char *old_pos = ff.pos;
411
412 if ( ff_match_int( &val ) < 0 || ( need_positive && val < 0 ) )
413 {
414 ff.pos = old_pos;
415 return -1;
416 }
417
418 *p = val;
419 return 0;
420 }
421
422
423 /***************************************
424 ***************************************/
425
426 static int
ff_match_string(char ** p)427 ff_match_string( char ** p )
428 {
429 /* Backtrack to start of line or last ':' */
430
431 while ( ff.pos > ff.line && isspace( ( unsigned char ) *--ff.pos ) )
432 /* empty */ ;
433
434 /* If we're at a ':' skip the next space if if exists */
435
436 if ( ff.pos > ff.line
437 && *ff.pos == ':'
438 && isspace( ( unsigned char ) *++ff.pos ) )
439 ff.pos++;
440
441 *p = ff.pos + strlen( ff.pos ) - 1;
442 if ( **p == '\n' )
443 **p = '\0';
444
445 *p = fl_strdup( ff.pos );
446
447 while ( *ff.pos )
448 ff.pos++;
449
450 return 0;
451 }
452
453
454 /***************************************
455 ***************************************/
456
457 static int
ff_match_trimmed_string(char ** p)458 ff_match_trimmed_string( char ** p )
459 {
460 char *ep = ff.pos + strlen( ff.pos ) - 1,
461 *fp = ep + 1;
462 char old_c;
463
464 if ( ! *ff.pos )
465 {
466 *p = fl_strdup( ff.pos );
467 return 0;
468 }
469
470 *p = NULL;
471
472 while ( ep > ff.pos && isspace( ( unsigned char ) *ep ) )
473 ep--;
474
475 old_c = *ep;
476 *++ep = '\0';
477
478 *p = fl_strdup( ff.pos );
479 *ep = old_c;
480 ff.pos = fp;
481
482 return 0;
483 }
484
485
486 /***************************************
487 ***************************************/
488
489 static int
ff_match_spaceless_string(char ** p)490 ff_match_spaceless_string( char ** p )
491 {
492 char *ep = ff.pos;
493
494 while ( *ep && ! isspace( ( unsigned char ) *ep ) )
495 ep++;
496
497 if ( ep == ff.pos )
498 *p = fl_strdup( "" );
499 else if ( ( *p = fl_malloc( ep - ff.pos + 2 ) ) )
500 {
501 fli_sstrcpy( *p, ff.pos, ep - ff.pos + 1 );
502 ff.pos = ep;
503 }
504
505 return p ? 0 : -1;
506 }
507
508
509 /***************************************
510 ***************************************/
511
512 static int
ff_match_var(char ** p)513 ff_match_var( char ** p )
514 {
515 char *ep = ff.pos;
516 char old_c;
517
518 if ( ! *ep )
519 {
520 *p = fl_strdup( ff.pos );
521 return -1;
522 }
523
524 *p = NULL;
525
526 if ( ! isascii( ( unsigned char ) *ep )
527 || ! ( isalpha( ( unsigned char ) *ep ) || *ep == '_' ) )
528 {
529 *p = fl_strdup( "" );
530 return -1;
531 }
532
533 while ( *++ep
534 && isascii( ( unsigned char ) *ep )
535 && ( isalnum( ( unsigned char ) *ep ) || *ep == '_' ) )
536 /* empty */ ;
537
538 if ( *ep && ! isspace( ( unsigned char ) *ep ) )
539 {
540 *p = fl_strdup( "" );
541 return -1;
542 }
543
544 /* Currently variable, function etc. names can't be longer... */
545
546 if ( ep - ff.pos >= MAX_VAR_LEN )
547 {
548 *p = fl_strdup( "" );
549 return -1;
550 }
551
552 old_c = *ep;
553 *ep = '\0';
554
555 *p = fl_strdup( ff.pos );
556
557 *ep = old_c;
558 ff.pos = ep + 1;
559
560 return 0;
561 }
562
563
564 /***************************************
565 ***************************************/
566
567 static int
ff_match_objclass(int * p)568 ff_match_objclass( int * p )
569 {
570 char *class_name;
571 int class;
572 char * old_pos = ff.pos;
573
574
575 if ( ff_match_spaceless_string( &class_name ) < 0 )
576 return -1;
577
578 if ( ! *class_name || ( class = class_val( class_name ) ) == -1 )
579 {
580 ff.pos = old_pos;
581 fl_free( class_name );
582 return -1;
583 }
584
585 *p = class;
586 fl_free( class_name );
587 return 0;
588 }
589
590
591 /***************************************
592 ***************************************/
593
594 static int
ff_match_boxtype(int * p)595 ff_match_boxtype( int * p )
596 {
597 char *boxtype_name;
598 char *old_pos = ff.pos;
599 int boxtype;
600
601 if ( ff_match_spaceless_string( &boxtype_name ) < 0 )
602 return -1;
603
604 if ( ! *boxtype_name || ( boxtype = boxtype_val( boxtype_name ) ) == -1 )
605 {
606 ff.pos = old_pos;
607 fl_free( boxtype_name );
608 return -1;
609 }
610
611 *p = boxtype;
612 fl_free( boxtype_name );
613 return 0;
614 }
615
616
617 /***************************************
618 ***************************************/
619
620 static int
ff_match_color(FL_COLOR * p)621 ff_match_color( FL_COLOR * p )
622 {
623 char *color_name;
624 char *old_pos = ff.pos;
625 FL_COLOR color;
626
627 if ( ff_match_spaceless_string( &color_name ) < 0 )
628 return -1;
629
630 if ( ! *color_name
631 || ( ( color = fli_query_namedcolor( color_name ) ) > FL_MAX_COLORS
632 && color != FL_NoColor ) )
633 {
634 ff.pos = old_pos;
635 fl_free( color_name );
636 return -1;
637 }
638
639 *p = color;
640 if ( *p == 0x8fffffff )
641 *p = FL_NoColor;
642
643 fl_free( color_name );
644 return 0;
645 }
646
647
648 /***************************************
649 * align may consist of two values, separated by a '|' or '+'
650 ***************************************/
651
652 static int
ff_match_align(int * p)653 ff_match_align( int * p )
654 {
655 char *align_name;
656 char *old_pos = ff.pos;
657 char *sp = strchr( ff.pos, '|' );
658 int align;
659
660 if ( ! sp )
661 sp = strchr( ff.pos, '+' );
662
663 if ( ! sp
664 || ( sp > ff.pos
665 && ! isspace( ( unsigned char ) sp[ -1 ] )
666 && ! isspace( ( unsigned char ) sp[ 1 ] ) ) )
667 {
668 if ( ff_match_spaceless_string( &align_name ) < 0 )
669 return -1;
670 }
671 else
672 {
673 char *a1,
674 *a2,
675 o = *sp;
676
677 *sp = '\0';
678 if ( ff_match_spaceless_string( &a1 ) < 0 || ! *a1 )
679 {
680 fl_free( a1 );
681 ff.pos = old_pos;
682 *sp = o;
683 return -1;
684 }
685
686 *sp = o;
687 ff.pos = sp + 1;
688 ff.pos = ff_skip_spaces( ff.pos );
689
690 if ( ff_match_spaceless_string( &a2 ) < 0 || ! *a2 )
691 {
692 fl_free( a1 );
693 fl_free( a2 );
694 ff.pos = old_pos;
695 return -1;
696 }
697
698 align_name = fl_malloc( strlen( a1 ) + strlen( a2 ) + 2 );
699 if ( align_name )
700 sprintf( align_name, "%s|%s", a1, a2 );
701
702 fl_free( a1 );
703 fl_free( a2 );
704 }
705
706 if ( ! align_name
707 || ! *align_name
708 || ( align = align_val( align_name ) ) == -1 )
709 {
710 ff.pos = old_pos;
711 fl_free( align_name );
712 return -1;
713 }
714
715 *p = align;
716 fl_free( align_name );
717 return 0;
718 }
719
720
721 /***************************************
722 * lstyle may consist of two values, separated by '|' or '+'
723 ***************************************/
724
725 static int
ff_match_lstyle(int * p)726 ff_match_lstyle( int * p )
727 {
728 char *lstyle_name = NULL;
729 int lstyle;
730 char *old_pos = ff.pos;
731 char *sp = strchr( ff.pos, '|' );
732
733 if ( ! sp )
734 sp = strchr( ff.pos, '+' );
735
736 if ( ! sp
737 || ( sp > ff.pos
738 && ! isspace( ( unsigned char ) sp[ -1 ] )
739 && ! isspace( ( unsigned char ) sp[ 1 ] ) ) )
740 {
741 if ( ff_match_spaceless_string( &lstyle_name ) < 0 )
742 return -1;
743 }
744 else
745 {
746 char *l1,
747 *l2,
748 *old_pos = ff.pos,
749 o = *sp;
750
751 *sp = '\0';
752 if ( ff_match_spaceless_string( &l1 ) < 0 )
753 {
754 fl_free( l1 );
755 *sp = o;
756 return -1;
757 }
758
759 *sp = o;
760 ff.pos = sp + 1;
761 ff.pos = ff_skip_spaces( ff.pos );
762
763 if ( ff_match_spaceless_string( &l2 ) < 0 || ! *l2 )
764 {
765 ff.pos = old_pos;
766 fl_free( l1 );
767 fl_free( l2 );
768 return -1;
769 }
770
771 lstyle_name = fl_malloc( strlen( l1 ) + strlen( l2 ) + 2 );
772 if ( lstyle_name )
773 sprintf( lstyle_name, "%s|%s", l1, l2 );
774
775 fl_free( l1 );
776 fl_free( l2 );
777 }
778
779 if ( ! lstyle_name
780 || ! *lstyle_name
781 || ( lstyle = style_val( lstyle_name ) ) == -1 )
782 {
783 ff.pos = old_pos;
784 fl_free( lstyle_name );
785 return -1;
786 }
787
788 *p = lstyle;
789 fl_free( lstyle_name );
790 return 0;
791 }
792
793
794 /***************************************
795 ***************************************/
796
797 static int
ff_match_lsize(int * p)798 ff_match_lsize( int * p )
799 {
800 char *lsize_name;
801 char *old_pos = ff.pos;
802 int lsize;
803
804 if ( ff_match_spaceless_string( &lsize_name ) < 0 )
805 return -1;
806
807 if ( ! *lsize_name || ( lsize = lsize_val( lsize_name ) ) == -1 )
808 {
809 fl_free( lsize_name );
810 ff.pos = old_pos;
811 return -1;
812 }
813
814 *p = lsize;
815 fl_free( lsize_name );
816 return 0;
817 }
818
819
820 /***************************************
821 ***************************************/
822
823 static int
ff_match_resize(int * p)824 ff_match_resize( int * p )
825 {
826 char *resize_name;
827 char *old_pos = ff.pos;
828 int resize;
829
830 if ( ff_match_spaceless_string( &resize_name ) < 0 )
831 return -1;
832
833 if ( ! *resize_name || ( resize = resize_val( resize_name ) ) == -1 )
834 {
835 fl_free( resize_name );
836 ff.pos = old_pos;
837 return -1;
838 }
839
840 *p = resize;
841 fl_free( resize_name );
842 return 0;
843 }
844
845
846 /***************************************
847 ***************************************/
848
849 static int
ff_match_gravity(int * p)850 ff_match_gravity( int * p )
851 {
852 char *gravity_name;
853 char *old_pos = ff.pos;
854 int gravity;
855
856 if ( ff_match_spaceless_string( &gravity_name ) < 0 )
857 return -1;
858
859 if ( ! *gravity_name || ( gravity = gravity_val( gravity_name ) ) == -1 )
860 {
861 ff.pos = old_pos;
862 fl_free( gravity_name );
863 return -1;
864 }
865
866 *p = gravity;
867 fl_free( gravity_name );
868 return 0;
869 }
870
871
872 /***************************************
873 ***************************************/
874
875 static int
ff_match_unit(int * p)876 ff_match_unit( int * p )
877 {
878 char *unit_name;
879 char *old_pos = ff.pos;
880 int unit;
881
882 if ( ff_match_spaceless_string( &unit_name ) < 0 )
883 return -1;
884
885 if ( ! *unit_name || ( unit = unit_val( unit_name ) ) == -1 )
886 {
887 ff.pos = old_pos;
888 fl_free( unit_name );
889 return -1;
890 }
891
892 *p = unit;
893 fl_free( unit_name );
894 return 0;
895 }
896
897 /***************************************
898 ***************************************/
899
900 static int
ff_match_key(char ** p)901 ff_match_key( char ** p )
902 {
903 char *ep = ff.pos;
904 char *np;
905 char old_c;
906
907 *p = NULL;
908
909 while ( *ep && *ep != ':' )
910 ep++;
911
912 if ( ! *ep )
913 return -1;
914
915 np = ep-- + 1;
916
917 while ( ep > ff.pos && isspace( ( unsigned char ) *ep ) )
918 ep--;
919
920 if ( ep == ff.pos )
921 return -1;
922
923 old_c = *++ep;
924 *ep = '\0';
925
926 *p = fl_strdup( ff.pos );
927
928 *ep = old_c;
929 ff.pos = np;
930
931 return 0;
932 }
933
934
935 /***************************************
936 ***************************************/
937
938 static int
ff_match_type(char ** p)939 ff_match_type( char ** p )
940 {
941 return ff_match_var( p );
942 }
943
944
945 /***************************************
946 * Function for reading data from .fd files in a fscanf()-like way.
947 *
948 * The format string may contain the following:
949 * a) text which must match the text in the string at that position
950 * b) %l match long (requires long *)
951 * b) %d match int (requires int *)
952 * c) %u match unsigned int (requires int *)
953 * d) %D match FL_Coord (requires FL_Coord *)
954 * e) %U match FL_Coord with positive value (requires FL_Coord *)
955 * f) %s match string (trimmed of spaces at start and end) (requires char **)
956 * g) %S match string (with all spaces) (requires char **)
957 * h) %h match string, stopping at the first space (requires char **)
958 * i) %f match single-precision floating point value (requires float *)
959 * j) %D match double floating point value (requires double *)
960 * k) %o match object class (requires int *)
961 * l) %t match type (requires char **)
962 * m) %b match boxtype (requires int *)
963 * n) %c match color (requires FL_COLOR *)
964 * o) %a match align (requires int *)
965 * p) %p match lstyle (requires int *)
966 * q) %q match lsize (requires int *)
967 * r) %r match resize (requires int *)
968 * s) %g match gravity (requires int *)
969 * t) %x match unit (requires int *)
970 * u) %v match C variable (requires char **)
971 * v) %k match a key (word(s) with a final colon) (requires char **)
972 *
973 * In case a string gets returned a copy must be made before the next
974 * call of this function.
975 * The function returns the number of items matched or a negative
976 * value on failure (in that case an error message is output).
977 ***************************************/
978
979 int
ff_read(const char * format,...)980 ff_read( const char * format,
981 ... )
982 {
983 va_list ap;
984 char *fmt;
985 const char *fp;
986 int cnt = 0;
987 char last = '\0';
988
989 if ( ! ff.line )
990 return -1;
991
992 format = ff_skip_spaces( format );
993
994 if ( ! format || ! *format )
995 {
996 M_err( "ff_read", "Invalid argument(s)" );
997 return FF_READ_FAILURE;
998 }
999
1000 fp = fmt = fl_strdup( format );
1001
1002 va_start( ap, format );
1003
1004 while ( *fp )
1005 {
1006 if ( *fp != '%' )
1007 {
1008 if ( ! ( fp = ff_match_text( fp ) ) )
1009 {
1010 va_end( ap );
1011 return FF_READ_FAILURE;
1012 }
1013
1014 last = '\0';
1015 }
1016 else
1017 {
1018 int r;
1019
1020 switch ( *++fp )
1021 {
1022 case 'l' : /* long int */
1023 r = ff_match_long( va_arg( ap, long * ) );
1024 break;
1025
1026 case 'd' : /* int */
1027 r = ff_match_int( va_arg( ap, int * ) );
1028 break;
1029
1030 case 'u' : /* unsigned int */
1031 r = ff_match_uint( va_arg( ap, unsigned int * ) );
1032 break;
1033
1034 case 'D' : /* FL_Coord ('U' for positive) */
1035 case 'U' :
1036 r = ff_match_coord( va_arg( ap, FL_Coord * ), *fp == 'U' );
1037 break;
1038
1039 case 's' : /* trimmed string */
1040 r = ff_match_trimmed_string( va_arg( ap, char ** ) );
1041 break;
1042
1043 case 'S' : /* string (with spaces) */
1044 r = ff_match_string( va_arg( ap, char ** ) );
1045 break;
1046
1047 case 'h' : /* string (without embedded spaces) */
1048 r = ff_match_spaceless_string( va_arg( ap, char ** ) );
1049 break;
1050
1051 case 'f' : /* float */
1052 r = ff_match_float( va_arg( ap, float * ) );
1053 break;
1054
1055 case 'F' : /* double */
1056 r = ff_match_double( va_arg( ap, double * ) );
1057 break;
1058
1059 case 'o' : /* object class */
1060 r = ff_match_objclass( va_arg( ap, int * ) );
1061 break;
1062
1063 case 't' : /* object type */
1064 r = ff_match_type( va_arg( ap, char ** ) );
1065 break;
1066
1067 case 'b' : /* box type */
1068 r = ff_match_boxtype( va_arg( ap, int * ) );
1069 break;
1070
1071 case 'c' : /* color */
1072 r = ff_match_color( va_arg( ap, FL_COLOR * ) );
1073 break;
1074
1075 case 'a' : /* alignment value */
1076 r = ff_match_align( va_arg( ap, int * ) );
1077 break;
1078
1079 case 'p' : /* lstyle value */
1080 r = ff_match_lstyle( va_arg( ap, int * ) );
1081 break;
1082
1083 case 'q' : /* lsize value */
1084 r = ff_match_lsize( va_arg( ap, int * ) );
1085 break;
1086
1087 case 'r' : /* resize value */
1088 r = ff_match_resize( va_arg( ap, int * ) );
1089 break;
1090
1091 case 'g' : /* gravity value */
1092 r = ff_match_gravity( va_arg( ap, int * ) );
1093 break;
1094
1095 case 'x' : /* unit value */
1096 r = ff_match_unit( va_arg( ap, int * ) );
1097 break;
1098
1099 case 'v' : /* C variable name */
1100 r = ff_match_var( va_arg( ap, char ** ) );
1101 break;
1102
1103 case 'k' : /* key with trailing colon */
1104 r = ff_match_key( va_arg( ap, char ** ) );
1105 break;
1106
1107 default : /* error, wrong format */
1108 va_end( ap );
1109 fl_free( fmt );
1110 M_err( "ff_read", "Invalid argument(s)" );
1111 return FF_READ_FAILURE;
1112 }
1113
1114 last = *fp;
1115
1116 if ( r < 0 )
1117 break;
1118
1119 cnt++;
1120 fp++;
1121 }
1122
1123 ff.pos = ff_skip_spaces( ff.pos );
1124 fp = ff_skip_spaces( fp );
1125 }
1126
1127 va_end( ap );
1128 fl_free( fmt );
1129
1130 /* If we're at the end of the line read in the next - except when the
1131 last request was for a key, in that case the next one will be for
1132 a value and it's allowed that no value exists even when there's a
1133 key... */
1134
1135 if ( last != 'k' && ! *ff.pos )
1136 ff_get_line( );
1137
1138 return cnt;
1139 }
1140
1141
1142 /*
1143 * Local variables:
1144 * tab-width: 4
1145 * indent-tabs-mode: nil
1146 * End:
1147 */
1148