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 /**
20  * \file fd_forms.c
21  *
22  *  This file is part of XForms package
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  * This file is part of the Forms Designer.
27  *
28  * It contains the routines that maintain the collection of
29  * forms on which the program is working. It contains the callback
30  * routines to add forms, change their name, remove them ,etc.
31  * It also contains the routine to draw them and the  basic routines
32  * for loading and saving forms.
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <ctype.h>
43 
44 #include "fd_main.h"
45 
46 static FRM *forms = NULL;   /* The list of forms */
47 static int fnumb = 0;       /* number of forms */
48 
49 FL_FORM *cur_form = NULL;   /* The current form */
50 
51 
52 /***************************************
53  * Returns the number of the form
54  ***************************************/
55 
56 static int
get_form_numb(FL_FORM * form)57 get_form_numb( FL_FORM * form )
58 {
59     int i;
60 
61     for ( i = 0; i < fnumb; i++ )
62         if ( forms[ i ].form == form )
63             return i;
64     return -1;
65 }
66 
67 
68 /***************************************
69  ***************************************/
70 
71 const char *
get_form_name(FL_FORM * form)72 get_form_name( FL_FORM * form )
73 {
74     int i;
75 
76     for ( i = 0; i < fnumb; i++ )
77         if ( forms[ i ].form == form )
78             return *forms[ i ].fname ? forms[ i ].fname : NULL;
79 
80     return NULL;
81 }
82 
83 
84 /***************************************
85  * Sets the current form to 'numb' or to NULL when 'numb' is -1
86  ***************************************/
87 
88 static void
set_form(int numb)89 set_form( int numb )
90 {
91     if ( numb == -1 )
92     {
93         cur_form = NULL;
94         fl_deselect_browser( fd_control->formbrowser );
95     }
96     else
97     {
98         cur_form = forms[ numb ].form;
99         set_bounding_box( 0, 0, cur_form->w, cur_form->h );
100         fl_select_browser_line( fd_control->formbrowser, numb + 1 );
101         fl_winstepsize( main_window, 1, 1 );
102         fl_winresize( main_window, cur_form->w, cur_form->h );
103         if ( fl_display )
104             XSync( fl_display, 0 );
105     }
106 
107     fl_deselect_browser( fd_control->objectbrowser );
108     reset_pallette( );
109     cur_class = -1;
110 
111     clear_selection( );
112     fillin_groups( );
113     redraw_the_form( 1 );
114 }
115 
116 
117 /***************************************
118  * Change the current forms background. Called when the main window is resized
119  ***************************************/
120 
121 void
reshape_form_background(FL_Coord neww,FL_Coord newh)122 reshape_form_background( FL_Coord neww,
123                          FL_Coord newh )
124 {
125     if ( cur_form && cur_form->first )
126     {
127         cur_form->w_hr = cur_form->w =
128         cur_form->first->next->w = cur_form->first->next->fr1 =
129         cur_form->first->next->fl2 = neww;
130         cur_form->h_hr = cur_form->h =
131         cur_form->first->next->h = cur_form->first->next->fb1 =
132         cur_form->first->next->ft2 = newh;
133 
134         set_bounding_box( 0, 0, neww, newh );
135     }
136 }
137 
138 
139 /****
140   CALLBACK ROUTINES
141 ****/
142 
143 /***************************************
144  * Callback routine that is called when the user selects another form
145  * to work on.
146  ***************************************/
147 
148 void
form_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)149 form_cb( FL_OBJECT * obj  FL_UNUSED_ARG,
150          long        arg  FL_UNUSED_ARG )
151 {
152     set_form( fl_get_browser( fd_control->formbrowser ) - 1 );
153 }
154 
155 
156 /***************************************
157  * Callback routine called when the user adds a form.
158  ***************************************/
159 
160 void
addform_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)161 addform_cb( FL_OBJECT * obj  FL_UNUSED_ARG,
162             long        arg  FL_UNUSED_ARG )
163 {
164     double w = 0,
165            h = 0;
166     FL_Coord xx,
167              yy;
168     static int form_seq;
169     const char *s;
170     const char *sp;
171     FRM *new_forms;
172     int cc = cur_class;
173     static int busy = 0;
174 
175     if ( busy )
176         return;
177     else
178         busy = 1;
179 
180     new_forms = fl_realloc( forms, ( fnumb + 1 ) * sizeof *forms );
181 
182     if ( ! new_forms )
183     {
184         fl_show_alert( "Too many forms", "Running out of memory for forms",
185                        NULL, 0 );
186         busy = 0;
187         return;
188     }
189     else
190         forms = new_forms;
191 
192     /* Make old form invisible */
193 
194     set_form( -1 );
195 
196     /* Get boundary */
197 
198     fl_get_win_size( main_window, &xx, &yy );
199     set_bounding_box( 0, 0, xx, yy );
200 
201     w = xx;
202     h = yy;
203 
204  get_new_form_name:
205 
206     if (    ! ( s = fl_show_input( "Enter form name (must be usable as "
207                                    "a C variable):", "" ) )
208          || ! *s )
209     {
210         busy = 0;
211         return;
212     }
213 
214     if (    ! isascii( ( unsigned char ) *s )
215          || ! ( isalpha( ( unsigned char ) *s ) || *s == '_' ) )
216     {
217         fl_show_alert( "Error", "Invalid C identifier for form name:", s, 0 );
218         goto get_new_form_name;
219     }
220 
221     for ( sp = s + 1; *sp; sp++ )
222         if (    ! isascii( ( unsigned char ) *sp )
223              || ! ( isalnum( ( unsigned char ) *sp ) || *sp == '_' ) )
224         {
225             fl_show_alert( "Error", "Invalid C identifier for form name:",
226                            s, 0 );
227             goto get_new_form_name;
228         }
229 
230     /* Create the form */
231 
232     cur_form = forms[ fnumb ].form = fl_bgn_form( FL_NO_BOX, w, h );
233     fl_end_form( );
234 
235     add_an_object( FL_BOX, FL_FLAT_BOX, 0, 0, w, h );
236     fl_set_form_dblbuffer( cur_form, 1 );
237 
238     /* Get form name and add it */
239 
240     strcpy( forms[ fnumb ].fname, s );
241 
242     if ( ! forms[ fnumb ].fname[ 0 ] )
243         sprintf( forms[ fnumb ].fname, "form%d", form_seq++ );
244     fl_add_browser_line( fd_control->formbrowser, forms[ fnumb ].fname );
245 
246     /* Finish off */
247 
248     set_form( fnumb++ );
249     changed = FL_TRUE;
250 
251     if ( cc >= 0 )
252         select_object_by_class( cc );
253 
254     busy = 0;
255 }
256 
257 
258 /***************************************
259  * Callback routine invoked when the user wants to change the name
260  * of the current form
261  ***************************************/
262 
263 void
changename_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)264 changename_cb( FL_OBJECT * obj  FL_UNUSED_ARG,
265                long        arg  FL_UNUSED_ARG )
266 {
267     int fn = get_form_numb( cur_form );
268     const char *s, *cn;
269     int i;
270     FL_OBJECT *o;
271 
272     if ( cur_form == NULL || fn == -1 )
273         return;
274 
275  get_changed_form_name:
276 
277     if (    ! ( s = fl_show_input( "Enter form name (must be usable as "
278                                    "a C variable):", forms[ fn ].fname ) )
279          || ! *s )
280         return;
281 
282     if ( ! is_valid_c_name( s ) )
283     {
284         fl_show_alert( "Error", "Invalid C identifier for form name:", s, 0 );
285         goto get_changed_form_name;
286     }
287 
288     for ( i = 0; i < fnumb; i++ )
289     {
290         if ( i == fn )
291             continue;
292 
293         if ( ! strcmp( forms[ i ].fname, s ) )
294         {
295             fl_show_alert( "Error", "New name is already in use for another "
296                            "form", NULL, 0 );
297             goto get_changed_form_name;
298         }
299     }
300 
301     for ( o = forms[ fn ].form->first; o; o = o->next )
302         if ( ( cn = get_object_c_name( o ) ) && ! strcmp( s, cn ) )
303         {
304             fl_show_alert( "Error", "New name is already used for one of the ",
305                            "forms objects", 0 );
306             goto get_changed_form_name;
307         }
308 
309     fli_sstrcpy( forms[ fn ].fname, s, MAX_VAR_LEN );
310 
311     fl_replace_browser_line( fd_control->formbrowser, fn + 1,
312                              forms[ fn ].fname );
313     changed = FL_TRUE;
314 }
315 
316 
317 /***************************************
318  * Callback routine invoked when the user wants to change the forms size
319  ***************************************/
320 
321 void
changesize_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)322 changesize_cb( FL_OBJECT * obj  FL_UNUSED_ARG,
323                long        arg  FL_UNUSED_ARG )
324 {
325     FL_OBJECT *retobj;
326     int fn = get_form_numb( cur_form );
327 
328     if ( cur_form == NULL || fn == -1 )
329         return;
330 
331     /* While this form is shown no other should be operational (the user
332        still can resize the forms window, that will automatically set the
333        width and height spinners) */
334 
335     fl_deactivate_all_forms( );
336 
337     /* Set up the width and height spinner objects to show the sizes of
338        the current form */
339 
340     fl_set_spinner_value( fd_resize->width,  cur_form->w );
341     fl_set_spinner_value( fd_resize->height, cur_form->h );
342 
343     fl_show_form( fd_resize->resize, FL_PLACE_HOTSPOT, FL_TRANSIENT,
344                   "Form size" );
345 
346     fl_update_display( 0 );
347     fl_winfocus( fd_resize->resize->window );
348 
349     /* Loop until user clicks the "Dismiss" button */
350 
351     while ( ( retobj = fl_do_only_forms( ) ) != fd_resize->quit )
352     {
353         int w;
354         int h;
355 
356         if ( retobj != fd_resize->set_size )
357             continue;
358 
359         /* User has clicked on the "Set new size" button */
360 
361         w = FL_nint( fl_get_spinner_value( fd_resize->width  ) );
362         h = FL_nint( fl_get_spinner_value( fd_resize->height ) );
363         fl_set_spinner_value( fd_resize->width, w  );
364         fl_set_spinner_value( fd_resize->height, h );
365 
366         if ( w == cur_form->w && h == cur_form->h )
367             continue;
368 
369         XResizeWindow( flx->display, main_window, w, h );
370 
371         if ( cur_form && ( cur_form->w > w || cur_form->h > h ) )
372         {
373             reshape_form_background( w, h );
374             redraw_the_form( 1 );
375         }
376 
377         changed = FL_TRUE;
378     }
379 
380     fl_hide_form( fd_resize->resize );
381     fl_activate_all_forms( );
382 }
383 
384 
385 /***************************************
386  * Callback routine for deleting a form
387  ***************************************/
388 
389 void
deleteform_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)390 deleteform_cb( FL_OBJECT * obj  FL_UNUSED_ARG,
391                long        arg  FL_UNUSED_ARG )
392 {
393     int i,
394         fn = get_form_numb( cur_form );
395 
396     if ( cur_form == NULL || fn == -1 )
397         return;
398 
399     if ( ! fl_show_question( "Delete current form?", 1 ) )
400         return;
401 
402     fl_delete_browser_line( fd_control->formbrowser, fn + 1 );
403 
404     for ( i = fn; i < fnumb - 1; i++ )
405         forms[ i ] = forms[ i + 1 ];
406 
407     fnumb--;
408     set_form( -1 );
409     changed = FL_TRUE;
410 }
411 
412 
413 /****
414   DRAWING FORMS
415 ****/
416 
417 /***************************************
418  * Redraws the form in main window. 'back' indicates whether the background
419  * should be redrawn (when not double-buffering). This avoids flashing.
420  ***************************************/
421 
422 void
redraw_the_form(int back)423 redraw_the_form( int back )
424 {
425     if ( main_window == 0 )
426         return;
427 
428     fl_winset( main_window );
429 
430     /* It's possible to have a NULL cur_form, e.g. when adding */
431 
432     if ( back && ! cur_form )
433         fd_clear( 0, 0, winw + 1, winh + 1 );
434 
435     if ( cur_form != NULL )
436     {
437         cur_form->window = main_window;
438         cur_form->visible = 1;
439         fl_set_form_dblbuffer( cur_form, 1 );
440         fl_redraw_form( cur_form );
441         cur_form->window = 0;
442         cur_form->visible = 0;
443         draw_selbox( );
444     }
445 }
446 
447 
448 /****
449   LOADING AND SAVING
450 ****/
451 
452 int fd_magic;
453 
454 /***************************************
455  ***************************************/
456 
457 char *
append_fd_suffix(const char * fn)458 append_fd_suffix( const char * fn )
459 {
460     size_t l = strlen( fn );
461     char *fname = fl_malloc( l + 4 );
462 
463     strcpy( fname, fn );
464     if ( l < 3 || strcmp( fname + l - 3, ".fd" ) )
465         strcat( fname, ".fd" );
466     return fname;
467 }
468 
469 
470 /***************************************
471  * Reads in the very first part of a .fd file
472  ***************************************/
473 
474 static int
load_fd_header(void)475 load_fd_header( void )
476 {
477     char *p;
478     int nforms = -1;
479 
480     /* Line with "magic" number must come first, followed by some
481        boilerplate text */
482 
483     if (    ff_read( "%k", &p ) <= 0
484          || strcmp( p, "Magic" )
485          || ff_read( "%d", &fd_magic ) <= 0
486          || (    fd_magic != MAGIC2 && fd_magic != MAGIC3
487               && fd_magic != MAGIC4 && fd_magic != MAGIC5
488               && fd_magic != MAGIC6 ) )
489         return ff_err( "Wrong type of file" );
490 
491     if ( fd_magic < MAGIC6 )
492     {
493         char *tmp = ff_get_filename_copy( );
494 
495         if ( ! fdopt.conv_only )
496             fl_show_alert_f( 0, "Warning:\fFile %s\nwas created with an older "
497                              "fdesign version,\nthe new output file may not be "
498                              "compatible.", tmp );
499         else
500             M_warn( "", "Warning: File %s was created with an older fdesign "
501                     "version, the new output file may not be compatible",
502                     tmp );
503 
504         fli_safe_free( tmp );
505     }
506 
507     if (    ff_read( "Internal Form Definition File" ) < 0
508          || ff_read( "(do not change)" ) < 0 )
509         return ff_err( "Invalid format of file" );
510 
511     /* Now follows a set of keyword/value pairs. The key "Name" marks
512        the end of the header and the start of the first form definition */
513 
514     while ( 1 )
515     {
516         if ( ff_read( "%k", &p ) <= 0 )
517             return ff_err( "Invalid format of file" );
518 
519         if ( ! strcmp( p, "Number of forms" ) )
520         {
521             if ( ff_read( "%d", &nforms ) <= 0 )
522                 return ff_err( "Expected number of forms" );
523 
524             if ( nforms <= 0 )
525                 return ff_err( "Invalid number of forms" );
526         }
527         else if ( ! strcmp( p, "Unit of measure" ) )
528         {
529             if ( ff_read( "%x", &fdopt.unit ) < 0 )
530                 return ff_err( "Expected valid unit of measure" );
531 
532             fli_cntl.coordUnit = fdopt.unit;        /* make_obj uses this */
533         }
534         else if ( ! strcmp( p, "SnapGrid" ) || ! strcmp( p, "Snap" ) )
535         {
536             int snap_size;
537 
538             if ( ff_read( "%d", &snap_size ) < 0 )
539                 return ff_err( "Expected snap size" );
540 
541             if ( snap_size < 0 )
542                 return ff_err( "Invalid snap size" );
543 
544             set_snap_size( snap_size, 1 );
545         }
546         else if ( ! strcmp( p, "Border Width" ) )
547         {
548             int bw;
549 
550             if ( ff_read( "%d", &bw ) < 0 )
551                 return ff_err( "Expected border width" );
552 
553             if ( bw != FL_BOUND_WIDTH )
554                 fl_set_border_width( fd_bwidth = bw );
555         }
556         else if ( ! strcmp( p, "Name" ) )
557         {
558             if ( nforms < 0 )
559                 return ff_err( "Number of forms is missing" );
560 
561             return nforms;
562         }
563         else
564             return ff_err( "Invalid format of file" );
565     }
566 
567     return ff_err( "Invalid format of file" );
568 }
569 
570 
571 /***************************************
572  * Loads or merges a file with form definitions
573  ***************************************/
574 
575 int
load_forms(int merge,const char * str)576 load_forms( int          merge,
577             const char * str )
578 {
579     int i,
580         saved_unit = fdopt.unit,
581         r,
582         nforms;
583     FRM *new_forms;
584     char *fname;
585 
586     /* Try to open the .fd file */
587 
588     if ( ff_get_fd_file( str, merge ) < 0 )
589         return -1;
590 
591     if ( ! merge )
592     {
593         fnumb = 0;
594         fl_clear_browser( fd_control->formbrowser );
595     }
596 
597     /* Try to read the header of the file (must indicate that there's at
598        least one form */
599 
600     if ( ( nforms = load_fd_header( ) ) <= 0 )
601         return -1;
602 
603     if ( ! ( new_forms = fl_realloc( forms,
604                                      ( fnumb + nforms ) * sizeof *forms ) ) )
605         return ff_err( "Can't load file, running out of memory" );
606 
607     forms = new_forms;
608 
609     fname = ff_get_filename_copy( );
610 
611     /* Now read in all forms - we have already read in the "Name:" key that
612        starts a new form */
613 
614     r = FF_AT_START_OF_FORM;
615 
616     for ( i = 0; i < nforms && r == FF_AT_START_OF_FORM; i++ )
617     {
618         char *p;
619 
620         /* First thing to read is the name of the form (which must not be an
621            empty string) */
622 
623         if ( ff_read( "%v", &p ) < 1 )
624         {
625             fl_free( fname );
626             return ff_err( "Failed to read expected form name" );
627         }
628 
629         if ( ! p || ! *p )
630         {
631             fli_safe_free( p );
632             return ff_err( "Expected name of the form" );
633         }
634 
635         fli_sstrcpy( forms[ fnumb ].fname, p, sizeof forms[ fnumb ].fname );
636         fli_safe_free( p );
637 
638         /* Having gotten the name read all the remaining information. We then
639            should either end up at the start of a new form or at the end of
640            the file */
641 
642         if (    ( r = read_form( ) ) == FF_AT_START_OF_FORM
643              || r == FF_AT_END_OF_FILE )
644         {
645             forms[ fnumb ].form = cur_form;
646             fl_add_browser_line( fd_control->formbrowser,
647                                  forms[ fnumb ].fname );
648             fnumb++;
649         }
650     }
651 
652     /* Check if we're really at the end of the file and as many forms have
653        been found as we were led to expect */
654 
655     if ( r == FF_AT_START_OF_FORM )
656     {
657         fl_free( fname );
658         return ff_err( "More forms found than expected" );
659     }
660     else if ( r != FF_READ_FAILURE && i < nforms )
661     {
662         ff_err( "Less forms found than expected" );
663         fl_free( fname );
664         return -1;
665     }
666 
667     /* Everything's dandy and we're done with the file */
668 
669     ff_close( );
670 
671     set_form( fnumb > 0 ? 0 : -1 );
672 
673     fli_safe_free( loadedfile );
674 
675     if ( ! merge )
676     {
677         loadedfile = rel2abs( fname );
678         changed = FL_FALSE;
679     }
680     else
681         changed = FL_TRUE;
682 
683     fl_free( fname );
684 
685     /* Reset active coordinate system to pixel */
686 
687     fli_cntl.coordUnit = FL_COORD_PIXEL;
688 
689     /* Force output to use the same unit as used in the input when converting
690        directly. The reason is that we don't know the screen DPI. */
691 
692     if ( ! fdopt.conv_only )
693         fdopt.unit = saved_unit;
694 
695     fd_magic = 0;
696     return 0;
697 }
698 
699 
700 /***************************************
701  * Saves the form definitions, returns whether saved
702  ***************************************/
703 
704 int
save_forms(const char * str)705 save_forms( const char *str )
706 {
707     int i,
708         snap;
709     FILE *fp;
710     char fname[ 1024 ],
711          filename[ 1024 ];
712     Conv *conv;
713 
714     fl_use_fselector( SAVE_FSELECTOR );
715 
716     /* Get the filename if necessary */
717 
718     if ( ! str || ! * str )
719     {
720         char *dir = NULL;
721 
722         if ( loadedfile && strchr( loadedfile, '/' ) )
723         {
724             dir = fl_strdup( loadedfile );
725             *strrchr( dir, '/' ) = '\0';
726         }
727         else
728             dir = fl_strdup( "" );
729 
730         str = fl_show_fselector( "Filename to save forms to", dir, "*.fd", "" );
731 
732         fl_free( dir );
733     }
734 
735     if ( ! str )
736         return 0;       /* cancel */
737 
738     if ( ! *str )
739     {
740         fl_show_alert( "Warning", "No forms were saved.", "", 0 );
741         return 0;
742     }
743 
744     /* Remove .fd if required */
745 
746     strcpy( filename, str );
747     i = strlen( filename ) - 1;
748     if ( ! strcmp( filename + i - 2, ".fd" ) )
749         filename[ i - 2 ] = '\0';
750 
751     strcpy( fname, filename );
752 
753     /* In simple convert mode (i.e. not migrate) there's no need to (re)save
754        the .fd file */
755 
756     if ( fdopt.conv_only == 1 )
757         goto emit_code;
758 
759     /* Make the .fd file */
760 
761     strcat( fname, ".fd" );
762     make_backup( fname );
763 
764     if ( ( fp = fopen( fname, "w" ) ) == 0 )
765     {
766         fl_show_alert_f( 1, "Error\fCannot open file\n%s\nfor writing",
767                          fname );
768         return 0;
769     }
770 
771     snap = get_step_size( ) + 0.1;
772     fprintf( fp, "Magic: %d\n\n"
773                  "Internal Form Definition File\n"
774                  "    (do not change)\n\n"
775                  "Number of forms: %d\n"
776                  "Unit of measure: %s\n",
777              MAGIC6, fnumb, unit_name( fdopt.unit ) );
778 
779     if ( fd_bwidth != FL_BOUND_WIDTH && fd_bwidth )
780         fprintf( fp, "Border Width: %d\n", fd_bwidth );
781 
782     if ( snap != 10 )
783         fprintf( fp, "SnapGrid: %d\n", snap );
784 
785     for ( i = 0; i < fnumb; i++ )
786         write_form( fp, forms[ i ].form, forms[ i ].fname );
787 
788     fprintf( fp, "\n==============================\n%s\n", main_name );
789     fclose( fp );
790 
791  emit_code:
792 
793     /* If no code is desired, return */
794 
795     if ( ! fdopt.emit_code )
796         return 1;
797 
798     conv = convertor + fdopt.language;
799 
800     /* Some converter works on the c code */
801 
802     if ( conv->need_c_code )
803         convertor[ FD_C ].convert( filename, forms, fnumb );
804 
805     if ( conv->convert )
806         return conv->convert( filename, forms, fnumb );
807     else if ( conv->extern_convertor )
808     {
809         char cmdbuf[ 1024 ];
810         char optbuf[ 512 ];
811         int status;
812 
813         *optbuf = '\0';
814 
815         if ( fdopt.emit_main )
816             strcat( optbuf, "-main " );
817         if ( fdopt.emit_cb )
818             strcat( optbuf, "-callback " );
819         if ( fdopt.altformat )
820             strcat( optbuf, "-altformat " );
821         if ( fdopt.compensate )
822             strcat( optbuf, "-compensate " );
823         if ( fdopt.output_dir ) {
824             strcat( optbuf, "-dir " );
825             strcat( optbuf, fdopt.output_dir );
826         }
827 
828         sprintf( cmdbuf, "%s %s%s", conv->extern_convertor, optbuf, filename );
829         M_warn( "Convert", "Executing %s", cmdbuf );
830 
831         if ( fdopt.conv_only )
832         {
833             if ( ( status = system( cmdbuf ) ) )
834                 M_err( "Output", "Error executing %s\n", cmdbuf );
835         }
836         else
837         {
838             fl_clear_command_log( );
839             if ( ( status = fl_exe_command( cmdbuf, 1 ) ) )
840             {
841                 fl_addto_command_log( "\nerror executing " );
842                 fl_addto_command_log( cmdbuf );
843                 fl_show_command_log( FL_FULLBORDER );
844             }
845         }
846 
847         return status == 0;
848     }
849     else
850     {
851         fprintf( stderr, "Convertor %s for %s not found\n",
852                  conv->extern_convertor, conv->lang_name );
853         return 0;
854     }
855 
856     return 1;
857 }
858 
859 
860 /*
861  * Local variables:
862  * tab-width: 4
863  * indent-tabs-mode: nil
864  * End:
865  */
866