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 <ctype.h>
24 
25 #include "fd_main.h"
26 #include "fd_iconinfo.h"
27 
28 
29 /***************************************
30  ***************************************/
31 
32 static int
is_blank(char c)33 is_blank( char c )
34 {
35     return c == ' ' || c == '\t';
36 }
37 
38 
39 /***************************************
40  ***************************************/
41 
42 IconInfo *
get_iconinfo(FL_OBJECT * obj)43 get_iconinfo( FL_OBJECT * obj )
44 {
45 	IconInfo *info = obj->c_vdata;
46 
47     if (    obj->objclass != FL_PIXMAPBUTTON
48          && obj->objclass != FL_BITMAPBUTTON
49          && obj->objclass != FL_PIXMAP
50          && obj->objclass != FL_BITMAP )
51 		return NULL;
52 
53 	if ( ! info )
54 	{
55 		info = obj->c_vdata = fl_malloc( sizeof *info );
56 
57         info->use_data        = 0;
58 		info->show_focus      = 1;
59 		info->dx              = 0;
60         info->dy              = 0;
61 		info->align           = FL_ALIGN_CENTER;
62 		info->fullpath        = 1;
63 		*info->filename       = '\0';
64 		*info->focus_filename = '\0';
65 		*info->data           = '\0';
66 		*info->focus_data     = '\0';
67 		*info->width          = '\0';
68 		*info->height         = '\0';
69 	}
70 
71 	return info;
72 }
73 
74 
75 /***************************************
76  ***************************************/
77 
78 void
copy_iconinfo(FL_OBJECT * target,FL_OBJECT * src)79 copy_iconinfo( FL_OBJECT * target,
80 			   FL_OBJECT * src )
81 {
82 	IconInfo *si = get_iconinfo( src ),
83 		     *ti;
84 
85 	fli_safe_free( target->c_vdata );
86 
87 	if ( ! si )
88 		return;
89 
90 	ti = get_iconinfo( target );
91 	*ti = *si;
92 }
93 
94 
95 /***************************************
96  ***************************************/
97 
98 void
free_iconinfo(FL_OBJECT * obj)99 free_iconinfo( FL_OBJECT * obj )
100 {
101 	fli_safe_free( obj->c_vdata );
102 }
103 
104 
105 /***************************************
106  * Function tries to read a line (of arbirary length) from a file
107  * On failure (either due to read error or missing memory) NULL is
108  * returned, otherwise a pointer to an allocated buffer that must
109  * be freed by the caller.
110  ***************************************/
111 
112 #define STRING_TRY_LENGTH 128
113 
114 static char *
read_line(FILE * fp)115 read_line( FILE * fp )
116 {
117     char *line = NULL;
118     char *old_line = NULL;
119     size_t len = STRING_TRY_LENGTH;
120     size_t old_len = 0;
121 
122     while ( 1 )
123     {
124         if ( ( line = fl_realloc( line, len ) ) == NULL )
125         {
126             fli_safe_free( old_line );
127             return NULL;
128         }
129 
130         if ( ! fgets( line + old_len, len - old_len, fp ) )
131         {
132             if ( ferror( fp ) )
133             {
134                 fl_free( line );
135                 return NULL;
136             }
137 
138             if ( old_len == 0 )
139             {
140                 fl_free( line );
141                 return NULL;
142             }
143 
144             break;
145         }
146 
147         if ( strchr( line + old_len, '\n' ) )
148             break;
149 
150         old_line = line;
151         old_len = len - 1;
152         len *= 2;
153     }
154 
155     old_line = line;
156     if ( ( line = fl_realloc( line, strlen( line ) + 1 ) ) == NULL )
157         return old_line;
158     return line;
159 }
160 
161 
162 /***************************************
163  ***************************************/
164 
165 static const char *
check_for_define(const char * line)166 check_for_define( const char * line )
167 {
168     while ( *line && is_blank( *line ) )
169         line++;
170 
171     if ( ! *line || *line != '#' )
172         return NULL;
173 
174     while ( *++line && is_blank( *line ) )
175         /* empty */ ;
176 
177     if ( ! *line )
178         return NULL;
179 
180     if ( strncmp( line, "define", 6 ) )
181         return NULL;
182 
183     line += 6;
184 
185     while ( *line && is_blank( *line ) )
186         line++;
187 
188     if ( ! ( isupper( *line ) || islower( *line ) || *line == '_' ) )
189         return NULL;
190 
191     return line;
192 }
193 
194 
195 /***************************************
196  ***************************************/
197 
198 static char *
check_for_end(const char * line,const char * what)199 check_for_end( const char * line,
200                const char * what )
201 {
202     static char name[ MAX_VAR_LEN ];
203     const char *start;
204     size_t len;
205 
206     if ( ( ! ( start = check_for_define( line ) ) ) )
207         return NULL;
208 
209     line = start;
210 
211     while ( *line
212             && (    isupper( *line )
213                  || islower( *line )
214                  || isdigit( *line )
215                  || *line == '_' ) )
216         line++;
217 
218     if ( ! is_blank( *line ) )
219         return NULL;
220 
221     len = line - start;
222     if ( len > MAX_VAR_LEN - 1 || len <= strlen( what ) )
223         return NULL;
224 
225     strncpy( name, start, len );
226     name[ len ] = '\0';
227 
228     if ( strcmp( name + len - strlen( what ), what ) )
229         return NULL;
230 
231     return name;
232 }
233 
234 
235 /***************************************
236  ***************************************/
237 
238 static char *
check_for_data(const char * line,const char * what)239 check_for_data( const char * line,
240                 const char * what )
241 {
242     static char name[ MAX_VAR_LEN ];
243     const char *start;
244     size_t len;
245 
246     /* Skip leading blanks */
247 
248     while ( *line && is_blank( *line ) )
249         line++;
250 
251     /* First word must be 'static', followed by a blank */
252 
253     if ( ! *line || strncmp( line, "static", 6 ) )
254         return NULL;
255 
256     line += 6;
257 
258     if ( ! *line || ! is_blank( *line ) )
259         return NULL;
260 
261     while ( *++line && is_blank( *line ) )
262         /* empty */ ;
263 
264     /* Skip optional 'const', followed by a blank */
265 
266     if ( ! strncmp( line, "const", 5 ) )
267     {
268         line += 5;
269 
270         if ( ! *line || ! is_blank( *line ) )
271             return NULL;
272 
273         while ( *++line && is_blank( *line ) )
274             /* empty */ ;
275     }
276 
277     /* Skip optional 'unsigned', followed by a blank */
278 
279     if ( ! strncmp( line, "unsigned", 8 ) )
280     {
281         line += 8;
282 
283         if ( ! *line || ! is_blank( *line ) )
284             return NULL;
285 
286         while ( *++line && is_blank( *line ) )
287             /* empty */ ;
288     }
289 
290     /* Now 'char', followed by at least one blank must follow */
291 
292     if ( ! *line || strncmp( line, "char", 4 ) )
293         return NULL;
294 
295     line += 4;
296 
297     if ( ! *line || ! ( is_blank( *line ) || *line == '*' ) )
298         return NULL;
299 
300     while ( *++line && is_blank( *line ) )
301         /* empty */ ;
302 
303     /* Skip optional 'const', followed by a blank */
304 
305     if ( ! strncmp( line, "const", 5 ) )
306     {
307         line += 5;
308 
309         while ( *line && is_blank( *line ) )
310             line++;
311     }
312 
313     /* When reading an xpm file a '*' must come next */
314 
315     if ( ! strcmp( what, "_pixels" ) )
316     {
317         if ( ! *line || *line != '*' )
318             return NULL;
319 
320         while ( ++line && is_blank( *line ) )
321             /* empty */ ;
322     }
323 
324     /* Now we should have arrived at the variable name */
325 
326     start = line;
327 
328     while (    *line
329             && (    isupper( *line )
330                  || islower( *line )
331                  || isdigit( *line )
332                  || *line == '_' ) )
333         line++;
334 
335     /* Check that the variable name is ok */
336 
337     len = line - start;
338     if ( len > MAX_VAR_LEN - 1 || ( ! strcmp( what, "_bits" ) && len < 6 ) )
339         return NULL;
340 
341     strncpy( name, start, len );
342     name[ len ] = '\0';
343 
344     /* A blank or a '[' must immediately followe the variable name */
345 
346     if ( ! *line || ! ( is_blank( *line ) || *line == '[' ) )
347         return NULL;
348 
349     /* Make sure that the next non-blank char is a '[' */
350 
351     while ( *line && is_blank( *line ) )
352         line++;
353 
354     return *line == '[' ? name : NULL;
355 }
356 
357 
358 /***************************************
359  * Tries to guess the names of the variables used for width, height
360  * and data in a xbm file from the file name.
361  ***************************************/
362 
363 void
get_xbm_stuff(IconInfo * info,FILE * fp)364 get_xbm_stuff( IconInfo * info,
365                FILE     * fp )
366 {
367     char *line;
368     char *res;
369     int found = 0;
370 
371     *info->width = *info->height = *info->data = '\0';
372 
373     while ( found < 3 && ( line = read_line( fp ) ) )
374     {
375         if ( ( res = check_for_end( line, "_width" ) ) )
376         {
377             strcpy( info->width, res );
378             found++;
379         }
380         else if ( ( res = check_for_end( line, "_height" ) ) )
381         {
382             strcpy( info->height, res );
383             found++;
384         }
385         else if ( ( res = check_for_data( line, "_bits" ) ) )
386         {
387             strcpy( info->data, res );
388             found++;
389         }
390 
391         fl_free( line );
392     }
393 
394     if ( found < 3 )
395     {
396         fprintf( stderr, "Failed to parse xbm file\n" );
397         *info->width = *info->height = *info->data = '\0';
398     }
399 }
400 
401 
402 /***************************************
403  * Read in an (already opened) xpm file and return via 'in'
404  * the name of the variable for the data.
405  ***************************************/
406 
407 void
get_xpm_stuff(char * in,FILE * fp)408 get_xpm_stuff( char * in,
409                FILE * fp )
410 {
411     char *line;
412     char *res;
413 
414     *in = '\0';
415 
416     while ( ( line = read_line( fp ) ) )
417     {
418         if ( ( res = check_for_data( line, "_pixels" ) ) )
419         {
420             strcpy( in, res );
421             fl_free( line );
422             return;
423         }
424 
425         fl_free( line );
426     }
427 }
428 
429 
430 /*
431  * Local variables:
432  * tab-width: 4
433  * indent-tabs-mode: nil
434  * End:
435  */
436