Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / DataBaseLoad.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: DataBaseLoad.c /main/9 1998/01/12 16:46:23 cshi $ */
24 /*****************************************************************************
25  *
26  *   File:         DataBaseLoad.c
27  *
28  *   Project:      CDE
29  *
30  *   Description:  This file contains the functions which load and parse
31  *                 the front panel databases.
32  *
33  * (c) Copyright 1993, 1994 Hewlett-Packard Company
34  * (c) Copyright 1993, 1994 International Business Machines Corp.
35  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
36  * (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of Novell, Inc.
37  *
38  *
39  ****************************************************************************/
40
41 #include <X11/Xlib.h>
42 #include <X11/Xresource.h>         /* XrmQuark */
43 #include <Dt/DtP.h>                /* required for DtDirPaths type */
44 #include <Dt/DbReader.h>           /* required for DtDbPathId type */
45 #include <Dt/Connect.h>            /* required for DtDbPathId type */
46 #include <Dt/Dts.h>
47 #include <Dt/Utility.h>
48 #include <Dt/IconFile.h>
49 #include <Dt/Icon.h>
50 #include <Dt/UserMsg.h>
51
52 #include "WmParse.h"
53 #include "DataBaseLoad.h"
54 #include "Parse.h"
55 #include "UI.h"
56
57 #include <pwd.h>
58 #include <fcntl.h>
59 #include <sys/stat.h>
60
61
62 /************************************************************************
63  *
64  *  panel is the global top of the panel tree structure.
65  *
66  *  switch is a local that is held until the hierary is built.
67  *
68  ************************************************************************/
69  
70 PanelData panel;
71 static SwitchData * switch1;
72 static ElementValue * control_element_values = NULL;
73 static Boolean control_element_value_found = False;
74
75
76
77 #define ANY_CONTAINER_TYPE      99
78
79 static char * TYPES_DIR = "/.dt/types/fp_dynamic/";
80 static char * TYPES_DIR_NO_SLASH = "/.dt/types/fp_dynamic";
81 static char * HOME_DIR = NULL;
82 static char * RM = "/bin/rm";
83
84
85 typedef Boolean (*FieldParse)(char *, void **);
86 typedef void (*FieldFree)(void **);
87
88 typedef struct
89 {
90    FieldParse   parse_function;
91    void       * default_value;
92    FieldFree    free_function;
93 } ParseFunction;
94
95
96
97
98 /************************************************************************
99  *
100  *  Definitions and structure initializations for PANEL record type.
101  *
102  ************************************************************************/
103
104 static char * panel_keywords[] =
105 {
106    "PANEL",
107    "PANEL_GEOMETRY",
108    "DISPLAY_HANDLES",
109    "DISPLAY_MENU",
110    "DISPLAY_MINIMIZE",
111    "RESOLUTION",
112    "CONTROL_BEHAVIOR",
113    "DISPLAY_CONTROL_LABELS",
114    "SUBPANEL_UNPOST",
115    "LOCKED",
116    "HELP_STRING",
117    "HELP_VOLUME",
118    "HELP_TOPIC",
119 };
120
121 static ParseFunction panel_parse_functions[] =
122 {
123    { StringToString,   NULL,               FreeString},   /* Name             */
124    { StringToString, NULL,               FreeString},   /* Panel Geometry   */
125    { StringToBoolean,  (void *) True,      NULL},         /* Display Handles  */
126    { StringToBoolean,  (void *) True,      NULL},         /* Display Menu     */
127    { StringToBoolean,  (void *) True,      NULL},         /* Display Minimize */
128    { StringToResolution, (void *) 3,       NULL},         /* Resolution       */
129    { StringToControlBehavior, (void *) 0,  NULL},         /* Control Behavior */
130    { StringToBoolean,  (void *) False,     NULL},   /* Display Control Labels */
131    { StringToBoolean,  (void *) True,      NULL},         /* Subpanel Unpost  */
132    { StringToBoolean,  (void *) False,     NULL},         /* Locked           */
133    { StringToString,   NULL,               FreeString},   /* Help String      */
134    { StringToString,   NULL,               FreeString},   /* Help Volume      */
135    { StringToString,   NULL,               FreeString},   /* Help Topic       */
136 };
137
138
139 /************************************************************************
140  *
141  *  Definitions and structure initializations for BOX record type.
142  *
143  ************************************************************************/
144
145 static char * box_keywords[] =
146 {
147    "BOX",
148    "CONTAINER_NAME",
149    "POSITION_HINTS",
150    "LOCKED",
151    "DELETE",
152    "HELP_STRING",
153    "HELP_VOLUME",
154    "HELP_TOPIC",
155 };
156
157 static ParseFunction box_parse_functions[] =
158 {
159    {StringToString,         NULL,              FreeString}, /* Name           */
160    {StringToString,         NULL,              FreeString}, /* Container Name */
161    {StringToPositionHints, (void *) 0,         NULL},       /* Position Hints */
162    {StringToBoolean,       (void *) False,     NULL},       /* Locked         */
163    {StringToBoolean,       (void *) False,     NULL},       /* Delete         */
164    {StringToString,         NULL,              FreeString}, /* Help String    */
165    {StringToString,         NULL,              FreeString}, /* Help Volume    */
166    {StringToString,         NULL,              FreeString}, /* Help Topic     */
167 };
168
169
170 /************************************************************************
171  *
172  *  Definitions and structure initializations for SUBPANEL record type.
173  *
174  ************************************************************************/
175
176 static char * subpanel_keywords[] =
177 {
178    "SUBPANEL",
179    "CONTAINER_NAME",
180    "CONTROL_INSTALL",
181    "TITLE",
182    "LOCKED",
183    "DELETE",
184    "HELP_STRING",
185    "HELP_VOLUME",
186    "HELP_TOPIC",
187 };
188
189 static ParseFunction subpanel_parse_functions[] =
190 {
191    {  StringToString,   NULL,           FreeString},    /*  Name             */
192    {  StringToString,   NULL,           FreeString},    /*  Container Name   */
193    {  StringToBoolean,  (void *) True,  NULL},          /*  Control Install  */
194    {  StringToString,   NULL,           FreeString},    /*  Title            */
195    {  StringToBoolean,  (void *) False, NULL},          /*  Locked           */
196    {  StringToBoolean,  (void *) False, NULL},          /*  Delete           */
197    {  StringToString,   NULL,           FreeString},    /*  Help String      */
198    {  StringToString,   NULL,           FreeString},    /*  Help Volume      */
199    {  StringToString,   NULL,           FreeString},    /*  Help Topic       */
200 };
201
202
203 /************************************************************************
204  *
205  *  Definitions and structure initializations for SWITCH record type.
206  *
207  ************************************************************************/
208
209 static char * switch_keywords[] = 
210 {
211    "SWITCH",
212    "CONTAINER_NAME",
213    "POSITION_HINTS",
214    "NUMBER_OF_ROWS",
215    "LOCKED",
216    "DELETE",
217    "HELP_STRING",
218    "HELP_VOLUME",
219    "HELP_TOPIC",
220 };
221
222
223 static ParseFunction switch_parse_functions[] =
224 {
225    { StringToString,        NULL,            FreeString}, /* Name            */
226    { StringToString,        NULL,            FreeString}, /* Container Name  */
227    { StringToPositionHints, (void *) 0,      NULL},       /* Position Hints  */
228    { StringToInt,           (void *) 2,      NULL},       /* Number of Rows  */
229    { StringToBoolean,       (void *) False,  NULL},       /* Locked          */
230    { StringToBoolean,       (void *) False,  NULL},       /* Delete          */
231    { StringToString,        NULL,            FreeString}, /* Help String     */
232    { StringToString,        NULL,            FreeString}, /* Help Volume     */
233    { StringToString,        NULL,            FreeString}, /* Help Topic      */
234 };
235
236
237 /************************************************************************
238  *
239  *  Definitions and structure initializations for CONTROL record type.
240  *
241  ************************************************************************/
242
243 static char * control_keywords[] =
244 {
245    "CONTROL",
246    "TYPE",
247    "CONTAINER_TYPE",
248    "CONTAINER_NAME",
249    "POSITION_HINTS",
250    "ICON",
251    "ALTERNATE_ICON",
252    "LABEL",
253    "PUSH_ACTION",
254    "PUSH_ANIMATION",
255    "DROP_ACTION",
256    "DROP_ANIMATION",
257    "PUSH_RECALL",
258    "MONITOR_TYPE",
259    "CLIENT_NAME",
260    "CLIENT_GEOMETRY",
261    "FILE_NAME",
262    "DATE_FORMAT",
263    "LOCKED",
264    "DELETE",
265    "HELP_STRING",
266    "HELP_VOLUME",
267    "HELP_TOPIC",
268 };
269
270 static ParseFunction control_parse_functions[] =
271 {
272    {StringToString,               NULL,   FreeString},   /* Name            */
273    {StringToControlType,  (void *)CONTROL_ICON, NULL},   /* Type            */
274    {StringToControlContainerType, NULL,   NULL},         /* Container Type  */
275    {StringToString,               NULL,   FreeString},   /* Container Name  */
276    {StringToPositionHints,(void *) 0,     NULL},         /* Position Hints  */
277    {StringToString,               NULL,   FreeString},   /* Image           */
278    {StringToString,               NULL,   FreeString},   /* Altername Image */
279    {StringToString,               NULL,   FreeString},   /* Label           */
280    {StringToAction,               NULL,   FreeAction},   /* Push Action     */
281    {StringToString,               NULL,   FreeString},   /* Push Animation  */
282    {StringToAction,               NULL,   FreeAction},   /* Drop Action     */
283    {StringToString,               NULL,   FreeString},   /* Drop Animation  */
284    {StringToBoolean,      (void *) False, NULL},         /* Push Recall     */
285    {StringToMonitorType,  (void *) MONITOR_NONE,NULL},   /* Monitor Type    */
286    {StringToString,               NULL,   FreeString},   /* Client Name     */
287    {StringToGeometry,             NULL,   FreeGeometry}, /* Client Geometry */
288    {StringToFileName,             NULL,   FreeString},   /* File Name       */
289    {StringToString,               NULL,   FreeString},   /* Date Format     */
290    {StringToBoolean,      (void *) False, NULL},         /* Locked          */
291    {StringToBoolean,      (void *) False, NULL},         /* Delete          */
292    {StringToString,               NULL,   FreeString},   /* Help String     */
293    {StringToString,               NULL,   FreeString},   /* Help Volume     */
294    {StringToString,               NULL,   FreeString},   /* Help Topic      */
295 };
296
297
298
299 /************************************************************************
300  *
301  *  Structure definition and initialization for the front panel
302  *  keyword lists.
303  *
304  ************************************************************************/
305
306 char * entry_types[] =
307 {
308    "PANEL",
309    "BOX",
310    "SUBPANEL",
311    "SWITCH",
312    "CONTROL"
313 };
314
315 char * control_types[] =
316 {
317    "blank",
318    "busy",
319    "icon",
320    "client",
321    "clock",
322    "date",
323    "file",
324 };
325
326
327 char * resolution_types[] =
328 {
329    "high",
330    "medium",
331    "low",
332    "match_display"
333 };
334
335 char * monitor_types[] =
336 {
337    "none",
338    "mail",
339    "file",
340 };
341
342 #define ANIMATION "ANIMATION"
343
344 typedef struct
345 {
346    char           * record_keyword;
347    int              keyword_count;
348    char          ** field_keywords;
349    ParseFunction  * parse_functions;
350 } RecordKeywords;
351
352
353 static RecordKeywords record_keywords[] =
354 {
355    {   "PANEL",           PANEL_KEYWORD_COUNT,
356        panel_keywords,    panel_parse_functions      },
357
358    {   "BOX",             BOX_KEYWORD_COUNT,
359        box_keywords,      box_parse_functions        },
360
361    {   "SUBPANEL",        SUBPANEL_KEYWORD_COUNT,
362        subpanel_keywords, subpanel_parse_functions   },
363
364    {   "SWITCH",          SWITCH_KEYWORD_COUNT,
365        switch_keywords,   switch_parse_functions     },
366
367    {   "CONTROL",         CONTROL_KEYWORD_COUNT,  
368        control_keywords,  control_parse_functions    },
369 };
370
371
372 /************************************************************************
373  *
374  *  Static and external function definitions
375  *
376  ************************************************************************/
377  
378
379 extern void WmFrontPanelSetBusy (Boolean);
380 extern char * _DtDbGetDataBaseEnv (void);
381
382 static Boolean PanelParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
383 static Boolean BoxParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
384 static Boolean SubpanelParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
385 static Boolean SwitchParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
386 static Boolean ControlParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
387 static Boolean AnimationParseCB (DtDtsDbField *, DtDbPathId, char *, Boolean);
388 static Boolean ControlSingleParseCB(DtDtsDbField *, DtDbPathId, char *, Boolean);
389 static void ProcessRecord (DtDtsDbField *, ElementValue *);
390 static void AllocateRecordData (RecordData **, int, int *, int *);
391 static void ReorderByContainerType(RecordData *, int , int);
392 static void ReorderByContainerName(RecordData *, int , int, int);
393 static void ReorderByName(RecordData *, int , int, int);
394 static void ReorderByPosition(RecordData *, int , int, int, int);
395 static void OrderRecord (RecordData *, int, int);
396 static char ** GetNameList (RecordData *, int, int, int, int);
397 static void EliminateUnused (RecordData *, int *, char **, int, int, int, int);
398 static void EliminateDeleted (RecordData *, int *, int, int, int, int, int);
399 static void ResolveDuplicates (RecordData *, int *, int, int, int, int, int);
400 static void InitializeField (ElementValue *, int, ParseFunction *);
401 static void ProcessBox (BoxData *);
402 static int ProcessBoxControl (ControlData *);
403 static void ProcessSubpanel (SubpanelData *);
404 static void ProcessSwitch (SwitchData *);
405 static void ProcessControl (XtPointer, char, ControlData ***, int *, ElementValue *);
406 static void InitializePrimaryControlFields (ElementValue *);
407 static void InitializeSecondaryControlFields (ElementValue *);
408 static void InitializeFileControlFields (ElementValue *, char *);
409
410
411
412 /************************************************************************
413  *
414  *  Variable and record declarations and initializations to keep track
415  *  of the data base info as it is read and to be used as storage for
416  *  subsequent parsing and reprocessing.
417  *
418  ************************************************************************/
419
420 static panel_count = 0;
421 static panel_data_count = 0;
422 static RecordData * panel_data = NULL;
423
424 static box_count = 0;
425 static box_data_count = 0;
426 static RecordData * box_data = NULL;
427
428 static subpanel_count = 0;
429 static subpanel_data_count = 0;
430 static RecordData * subpanel_data = NULL;
431
432 static switch_count = 0;
433 static switch_data_count = 0;
434 static RecordData * switch_data = NULL;
435
436 static control_count = 0;
437 static control_data_count = 0;
438 static RecordData * control_data = NULL;
439
440
441
442 static DtDbConverter panel_converter[] =    {  (DtDbConverter) PanelParseCB,
443                                                NULL  };
444 static DtDbConverter box_converter[] =      {  (DtDbConverter) BoxParseCB,
445                                                NULL  };
446 static DtDbConverter subpanel_converter[] = {  (DtDbConverter) SubpanelParseCB,
447                                                NULL  };
448 static DtDbConverter switch_converter[] =   {  (DtDbConverter) SwitchParseCB,
449                                                NULL  };
450 static DtDbConverter control_converter[] =  {  (DtDbConverter) ControlParseCB,
451                                                NULL  };
452 static DtDbConverter animation_converter[] ={  (DtDbConverter) AnimationParseCB,
453                                                NULL  };
454
455 static DtDbRecordDesc record_descriptor[] =
456 {
457    {  "PANEL",     PANEL_KEYWORD_COUNT,    panel_converter     },
458    {  "BOX",       BOX_KEYWORD_COUNT,      box_converter       },
459    {  "SUBPANEL",  SUBPANEL_KEYWORD_COUNT, subpanel_converter  },
460    {  "SWITCH",    SWITCH_KEYWORD_COUNT,   switch_converter    },
461    {  "CONTROL",   CONTROL_KEYWORD_COUNT,  control_converter   },
462    {  "ANIMATION", DTUNLIMITEDFIELDS,      animation_converter }
463 };
464
465 static DtDbConverter control_single_converter[] =
466                                { (DtDbConverter) ControlSingleParseCB, NULL};
467
468 static DtDbRecordDesc control_record_descriptor[] =
469 {
470    {  "CONTROL",   CONTROL_KEYWORD_COUNT, control_single_converter  },
471    {  "ANIMATION", DTUNLIMITEDFIELDS,     animation_converter       }
472 };
473
474
475
476
477
478 /************************************************************************
479  *
480  *  FrontPanelReadDatabases
481  *     Read in the front panel database, parse out each line, build 
482  *     the internal data structures that are then used to create the 
483  *     visual representation.
484  *
485  *     Processing occurs in a series of steps:
486  *
487  *       1. Read in all of the database records and copy the unparsed
488  *          string information into a structure.
489  *            a. Group the records according to type.
490  *            b. Group the records according to container.
491  *            c. Ensure the original read order is maintained to process
492  *               overrides.
493  *
494  *          This step occurs out of the callback for each of the component
495  *          types.
496  *
497  *       2. Eliminate the unused component definitions by working top-down
498  *          throught the lists.  Select the PANEL and SWITCH definition
499  *          to be used at this time.
500  *          
501  *       3. Eliminate overridden components by either selecting the first
502  *          locked definition or if none are locked, selecting the last
503  *          definition.
504  *
505  *       4. Reorder the component groups according to the position hints
506  *
507  *       5. Build hierarchical data structure from record sets, top-down.
508  *          Fully parse each record as the structure is built.
509  *
510  *
511  *       6. Return.
512  *
513  ************************************************************************/
514  
515 Boolean
516 FrontPanelReadDatabases (void)
517
518
519 {
520    char * search_paths;
521    char * new_search_paths;
522    struct passwd * pw_info;
523
524    char * dynamic_dir;
525    struct stat stat_info;
526    int fd;   
527
528    int    i;
529    char * fp_database;
530    int    num_entries;
531    char ** name_list;
532    DtDirPaths * dir_paths;
533
534
535    panel.animation_data = NULL;
536    panel.animation_count = 0;
537
538
539
540    /*  Before reading the databases, add the front panel dynamic  */
541    /*  directory to the search path.                              */
542    
543    search_paths = _DtDbGetDataBaseEnv();
544
545    if ((HOME_DIR = (char *) getenv ("HOME")) == NULL)
546    {
547       pw_info = getpwuid (getuid());
548       HOME_DIR = pw_info->pw_dir;
549    }
550
551    HOME_DIR = XtNewString (HOME_DIR);
552    
553    new_search_paths = 
554       XtMalloc (strlen ("DTDATABASESEARCHPATH") + strlen (HOME_DIR) + 
555                 strlen (TYPES_DIR_NO_SLASH) + strlen (search_paths) + 3);
556    sprintf (new_search_paths, "%s=%s%s,%s", 
557             "DTDATABASESEARCHPATH", HOME_DIR, TYPES_DIR_NO_SLASH, search_paths);
558    putenv (new_search_paths);
559
560    XtFree (search_paths);
561
562
563    /*  See if the fp_dynamic directory exists.  If not, create it  */
564
565    dynamic_dir =  XtMalloc (strlen (HOME_DIR) + strlen (TYPES_DIR) + 3);
566    sprintf (dynamic_dir, "%s%s", HOME_DIR, TYPES_DIR);
567
568    if (lstat (dynamic_dir, &stat_info) != 0)
569       if ((fd=mkdir (dynamic_dir, S_IRWXU | S_IRGRP | S_IROTH | 
570                                   S_IXGRP | S_IXOTH)) != 0)
571       {
572          
573       }
574
575    XtFree ((char *) dynamic_dir);
576
577
578    /*  Read the database and do the initial set of processing on  */
579    /*  the file based information.  This work occurs within the   */
580    /*  callback function referenced in the data read call.        */
581
582    dir_paths = _DtGetDatabaseDirPaths();
583
584 #ifdef DT_PERFORMANCE
585 _DtPerfChkpntMsgSend("Begin Front panel database read");
586 #endif
587
588    _DtDbRead (dir_paths, FILE_TYPE_SUFFIX, record_descriptor, 6);
589
590 #ifdef DT_PERFORMANCE
591 _DtPerfChkpntMsgSend("End   Front panel database read");
592 #endif
593
594    if (panel_count == 0)
595    {
596       _DtFreeDatabaseDirPaths (dir_paths);
597       return False;
598    }
599
600    /*  Once all of the PANEL records have been read in, select the panel   */
601    /*  record that is to be used to build the front panel.                 */
602    /*                                                                      */
603    /*  This selection is done by first scanning the list to find a LOCKED  */
604    /*  panel.  The first one found is selected.  If none are found, the    */
605    /*  last panel read is selectd.                                         */
606    
607    for (i = panel_count - 1; i > 0; i--)
608    {
609       if ((Boolean)(panel_data[i].element_values[PANEL_LOCKED].parsed_value))
610          break;
611    }
612
613    panel.element_values = panel_data[i].element_values;
614
615
616    /*  Parse out additional panel element values  */
617
618    InitializeField (panel.element_values, PANEL_GEOMETRY, panel_parse_functions);
619    InitializeField (panel.element_values, PANEL_DISPLAY_HANDLES, panel_parse_functions);
620    InitializeField (panel.element_values, PANEL_DISPLAY_MENU, panel_parse_functions);
621    InitializeField (panel.element_values, PANEL_DISPLAY_MINIMIZE, panel_parse_functions);
622    InitializeField (panel.element_values, PANEL_RESOLUTION, panel_parse_functions);
623    InitializeField (panel.element_values, PANEL_CONTROL_BEHAVIOR, panel_parse_functions);
624    InitializeField (panel.element_values, PANEL_DISPLAY_CONTROL_LABELS, panel_parse_functions);
625    InitializeField (panel.element_values, PANEL_SUBPANEL_UNPOST, panel_parse_functions);
626    InitializeField (panel.element_values, PANEL_HELP_STRING, panel_parse_functions);
627    InitializeField (panel.element_values, PANEL_HELP_TOPIC, panel_parse_functions);
628    InitializeField (panel.element_values, PANEL_HELP_VOLUME, panel_parse_functions);
629
630    XtFree ((char *) panel_data);
631
632
633    /*  Eliminate the records within the other component types that  */
634    /*  are not part of this selected panel.                         */
635    /*                                                               */
636    /*  This elimination occurs top down because boxes have to be    */
637    /*  removed before controls can be removed...                    */
638    
639    name_list = (char **) XtMalloc (sizeof (char **) * 2);
640    name_list[0] = panel.element_values[PANEL_NAME].parsed_value;
641    name_list[1] = NULL;
642    EliminateUnused (box_data, &box_count, name_list, BOX_CONTAINER_NAME,
643                     ANY_CONTAINER_TYPE, PANEL, BOX);
644    XtFree ((char *) name_list);
645
646    /* Remove entries that have the deleted keyword set to True unless */
647    /* it is a locked file.                                            */
648    EliminateDeleted (box_data, &box_count, BOX_CONTAINER_NAME,
649                      BOX_NAME, BOX, BOX_DELETE, BOX_LOCKED);
650    EliminateDeleted (switch_data, &switch_count, SWITCH_CONTAINER_NAME,
651                      SWITCH_NAME, SWITCH, SWITCH_DELETE, SWITCH_LOCKED);
652    EliminateDeleted (subpanel_data, &subpanel_count, SUBPANEL_CONTAINER_NAME,
653                      SUBPANEL_NAME, SUBPANEL, SUBPANEL_DELETE, SUBPANEL_LOCKED);
654    EliminateDeleted (control_data, &control_count, CONTROL_CONTAINER_NAME,
655                      CONTROL_NAME, CONTROL, CONTROL_DELETE, CONTROL_LOCKED);
656
657    name_list = GetNameList (box_data, box_count, 
658                             BOX_NAME, ANY_CONTAINER_TYPE, 0);
659
660    EliminateUnused(switch_data, &switch_count, name_list,
661                    SWITCH_CONTAINER_NAME, ANY_CONTAINER_TYPE,
662                    BOX, SWITCH);
663
664    EliminateUnused(control_data, &control_count, name_list,
665                    CONTROL_CONTAINER_NAME, CONTROL_CONTAINER_TYPE,
666                    BOX, CONTROL);
667
668    XtFree ((char *) name_list);
669
670
671    /*  Once the elimination of superfluous switch definitions is complete,  */
672    /*  make the selection of the single Switch.  This makes the elimination */
673    /*  of the switch based controls efficient.                              */
674    /*                                                                       */
675    /*  This selection is done by first scanning the list to find a LOCKED   */
676    /*  switch.  The first one found is selected.  If none are found, the    */
677    /*  last switch read is selected.                                        */
678
679    if (switch_count != 0) {
680      for (i = switch_count - 1; i > 0; i--)
681      {
682        if ((Boolean)(switch_data[i].element_values[SWITCH_LOCKED].parsed_value))
683             break;
684      }
685
686      switch1 = (SwitchData *) XtMalloc (sizeof (SwitchData));
687      switch1->element_values = switch_data[i].element_values;
688      switch1->control_data = NULL;
689      switch1->control_data_count = 0;
690      switch1->rc = NULL;
691      switch1->buttons = NULL;
692      switch1->atom_names = NULL;
693      switch1->switch_names = NULL;
694      switch1->switch_count = 0;
695      switch1->active_switch = 0;
696      switch1->popup_data = NULL;
697
698
699       /*  Parse the remaining database values for the switch  */
700    
701      InitializeField (switch1->element_values, SWITCH_POSITION_HINTS, switch_parse_functions);
702      InitializeField (switch1->element_values, SWITCH_NUMBER_OF_ROWS, switch_parse_functions);
703      InitializeField (switch1->element_values, SWITCH_HELP_STRING, switch_parse_functions);
704      InitializeField (switch1->element_values, SWITCH_HELP_TOPIC, switch_parse_functions);
705      InitializeField (switch1->element_values, SWITCH_HELP_STRING, switch_parse_functions);
706    }
707
708    XtFree ((char *) switch_data);
709
710
711    /*  Continue the elimination of unused records  */
712
713    name_list = (char **) XtMalloc (sizeof (char **) * 2);
714    if (switch_count != 0)
715       name_list[0] = switch1->element_values[SWITCH_NAME].parsed_value;
716    else
717       name_list[0] = NULL;
718    name_list[1] = NULL;
719    EliminateUnused (control_data, &control_count, name_list,
720                     CONTROL_CONTAINER_NAME, CONTROL_CONTAINER_TYPE,
721                     SWITCH, CONTROL);
722    XtFree ((char *)name_list);
723
724    name_list = GetNameList (control_data, control_count, 
725                             CONTROL_NAME, CONTROL_CONTAINER_TYPE, BOX);
726
727    EliminateUnused (subpanel_data, &subpanel_count, name_list,
728                     SUBPANEL_CONTAINER_NAME, ANY_CONTAINER_TYPE,
729                     CONTROL, SUBPANEL);
730    XtFree ((char *)name_list);
731
732    name_list = GetNameList (subpanel_data, subpanel_count, 
733                             SUBPANEL_NAME, ANY_CONTAINER_TYPE, SUBPANEL);
734
735    EliminateUnused (control_data, &control_count, name_list,
736                    CONTROL_CONTAINER_NAME, CONTROL_CONTAINER_TYPE,
737                    SUBPANEL, CONTROL);
738
739    XtFree ((char *)name_list);
740                     
741
742    /*  The record types of CONTROL, SUBPANEL and BOX still have need  */
743    /*  several steps of processing.                                   */
744
745    ReorderByContainerType(control_data, control_count, CONTROL_CONTAINER_TYPE);
746
747    ReorderByContainerName(control_data, control_count, CONTROL_CONTAINER_NAME,
748                           CONTROL_CONTAINER_TYPE);
749
750    ReorderByName(box_data, box_count, BOX_NAME, BOX_CONTAINER_NAME);
751
752    ReorderByName(control_data, control_count, CONTROL_NAME,
753                  CONTROL_CONTAINER_NAME);
754
755 #ifdef DEBUG
756    for (i = 0; i < control_count; i++) {
757        printf("control %s, %d, %s\n",
758             control_data[i].element_values[CONTROL_CONTAINER_NAME].parsed_value,
759             control_data[i].element_values[CONTROL_CONTAINER_TYPE].parsed_value,
760             control_data[i].element_values[CONTROL_NAME].parsed_value);
761    }
762 #endif
763
764
765    /*  Reprocess each of these groups to eliminate overridden     */
766    /*  components.  If a component is locked, use the first lock  */
767    /*  encountered.  Otherwise, use the last component read.      */
768
769    ResolveDuplicates (box_data, &box_count, BOX_NAME,
770                       ANY_CONTAINER_TYPE, BOX_CONTAINER_NAME,
771                       BOX_LOCKED, BOX);
772    ResolveDuplicates (subpanel_data, &subpanel_count, SUBPANEL_NAME,
773                       ANY_CONTAINER_TYPE, SUBPANEL_CONTAINER_NAME, 
774                       SUBPANEL_LOCKED, SUBPANEL);
775    ResolveDuplicates (control_data, &control_count, CONTROL_NAME,
776                       CONTROL_CONTAINER_TYPE, CONTROL_CONTAINER_NAME, 
777                       CONTROL_LOCKED, CONTROL);
778    
779    /*  Now that the elimination has been completed, initialize the  */
780    /*  remaining values for each of the components.                 */
781
782    for (i = 0; i < box_count; i++) 
783    {
784       InitializeField (box_data[i].element_values,
785                        BOX_POSITION_HINTS, box_parse_functions);
786       InitializeField (box_data[i].element_values,
787                        BOX_HELP_STRING, box_parse_functions);
788       InitializeField (box_data[i].element_values,
789                        BOX_HELP_TOPIC, box_parse_functions);
790       InitializeField (box_data[i].element_values,
791                        BOX_HELP_VOLUME, box_parse_functions);
792    }
793
794    for (i = 0; i < subpanel_count; i++)
795    {
796       InitializeField (subpanel_data[i].element_values,
797                        SUBPANEL_CONTROL_INSTALL, subpanel_parse_functions);
798       InitializeField (subpanel_data[i].element_values,
799                        SUBPANEL_TITLE, subpanel_parse_functions);
800       InitializeField (subpanel_data[i].element_values,
801                        SUBPANEL_HELP_STRING, subpanel_parse_functions);
802       InitializeField (subpanel_data[i].element_values,
803                        SUBPANEL_HELP_TOPIC, subpanel_parse_functions);
804       InitializeField (subpanel_data[i].element_values,
805                        SUBPANEL_HELP_VOLUME, subpanel_parse_functions);
806    }
807
808    for (i = 0; i < control_count; i++)
809    {
810       InitializeSecondaryControlFields (control_data[i].element_values);
811       InitializeFileControlFields (control_data[i].element_values, NULL);
812    }
813
814 #ifdef DEBUG
815    for (i = 0; i < box_count; i++) {
816        printf("box %d = %s\n",
817              box_data[i].element_values[BOX_POSITION_HINTS].parsed_value,
818              box_data[i].element_values[BOX_NAME].parsed_value);
819    }
820
821    for (i = 0; i < subpanel_count; i++) {
822        printf("subpanel = %s\n",
823              subpanel_data[i].element_values[SUBPANEL_NAME].parsed_value);
824    }
825
826    for (i = 0; i < control_count; i++) {
827        printf("control %d = %s\n",
828             control_data[i].element_values[CONTROL_POSITION_HINTS].parsed_value,
829             control_data[i].element_values[CONTROL_NAME].parsed_value);
830    }
831 #endif
832
833    /*  Reorder subgroups according to position hints.  */
834
835    ReorderByPosition (box_data, box_count, BOX_POSITION_HINTS,
836                       ANY_CONTAINER_TYPE, BOX_CONTAINER_NAME);
837    ReorderByPosition (control_data, control_count, CONTROL_POSITION_HINTS,
838                       CONTROL_CONTAINER_TYPE, CONTROL_CONTAINER_NAME);
839  
840 #ifdef DEBUG
841    printf("**************************************************************\n\n");
842
843    for (i = 0; i < box_count; i++) {
844        printf("box %d = %s\n", (int)
845              box_data[i].element_values[BOX_POSITION_HINTS].parsed_value,
846              box_data[i].element_values[BOX_NAME].parsed_value);
847    }
848
849    for (i = 0; i < control_count; i++) {
850        printf("control %d = %s\n", (int)
851             control_data[i].element_values[CONTROL_POSITION_HINTS].parsed_value,
852             control_data[i].element_values[CONTROL_NAME].parsed_value);
853    }
854 #endif
855
856
857    /*  Build hierarchical data structure from record sets, top-down.  */
858    /*  Fully parse each record as the structure is built.             */
859
860    panel.box_data = (BoxData **) XtMalloc (sizeof (BoxData *) * box_count);
861    panel.box_data_count = box_count;
862    
863    for (i = 0; i < box_count; i++)
864    {
865        BoxData * box;
866        
867        panel.box_data[i] = (BoxData *) XtMalloc (sizeof (BoxData));
868        box = panel.box_data[i];
869        
870        box->element_values = box_data[i].element_values;
871        box->control_data = NULL;
872        box->control_data_count = 0;
873        box->form = NULL;
874        box->left_arrow_form = NULL;
875        box->left_control_form = NULL;
876        box->right_arrow_form = NULL;
877        box->right_control_form = NULL;
878        box->switch_data = NULL;
879        box->switch_form = NULL;
880        box->switch_edit = NULL;
881        box->subpanel_count = 0;
882
883        
884        if (switch_count != 0 &&
885            strcmp ((char *) box->element_values[BOX_NAME].parsed_value,
886                    (char *) switch1->element_values[SWITCH_CONTAINER_NAME].parsed_value) == 0)
887        {
888           box->switch_data = switch1;
889           switch1->box_data = box;
890           ProcessSwitch (box->switch_data);
891        }
892
893
894        /*  Call a function to process each box, allocating the control  */
895        /*  data structures needed for them and calling functions to     */
896        /*  further process each control.                                */
897        
898        ProcessBox (box);
899    }
900
901    XtFree ((char *) box_data);
902    _DtFreeDatabaseDirPaths (dir_paths);
903
904    return True;
905 }
906
907
908  
909  
910 /************************************************************************
911  *
912  *  PanelParseCB
913  *      Allocate a structure to contain the Panel record returned by
914  *      the database read code and copy the record information into the
915  *      structure.
916  *
917  ************************************************************************/
918
919 static Boolean
920 PanelParseCB (DtDtsDbField  * fields,
921               DtDbPathId   path_id, 
922               char        * host_prefix,
923               Boolean       rejection)
924
925 {
926    AllocateRecordData (&panel_data, 
927                        sizeof (ElementValue) * PANEL_KEYWORD_COUNT,
928                        &panel_data_count, &panel_count);
929
930    ProcessRecord (fields, (ElementValue *) 
931                   panel_data[panel_count - 1].element_values);
932
933    InitializeField (panel_data[panel_count - 1].element_values,
934                     PANEL_NAME, panel_parse_functions);
935    InitializeField (panel_data[panel_count - 1].element_values,
936                     PANEL_LOCKED, panel_parse_functions);
937
938    return (True);
939 }
940
941
942
943
944 /************************************************************************
945  *
946  *  BoxParseCB
947  *      Allocate a structure to contain the Box record returned by
948  *      the database read code and copy the record information into the
949  *      structure.
950  *
951  ************************************************************************/
952
953 static Boolean
954 BoxParseCB (DtDtsDbField  * fields,
955             DtDbPathId   path_id, 
956             char        * host_prefix,
957             Boolean       rejection)
958
959
960 {
961    AllocateRecordData (&box_data, 
962                        sizeof (ElementValue) * BOX_KEYWORD_COUNT,
963                        &box_data_count, &box_count);
964
965    ProcessRecord (fields, box_data[box_count - 1].element_values);
966
967    InitializeField (box_data[box_count - 1].element_values,
968                     BOX_NAME, box_parse_functions);
969    InitializeField (box_data[box_count - 1].element_values,
970                     BOX_CONTAINER_NAME, box_parse_functions);
971    InitializeField (box_data[box_count - 1].element_values,
972                     BOX_LOCKED, box_parse_functions);
973    InitializeField (box_data[box_count - 1].element_values,
974                     BOX_DELETE, box_parse_functions);
975
976    OrderRecord (box_data, box_count, BOX_CONTAINER_NAME);
977
978    return (True);
979
980
981
982
983  
984 /************************************************************************
985  *
986  *  SubpanelParseCB
987  *      Allocate a structure to contain the Subpanel record returned by
988  *      the database read code and copy the record information into the
989  *      structure.
990  *
991  ************************************************************************/
992
993 static Boolean
994 SubpanelParseCB (DtDtsDbField  * fields,
995                  DtDbPathId   path_id, 
996                  char        * host_prefix,
997                  Boolean       rejection)
998
999 {
1000    AllocateRecordData (&subpanel_data,
1001                        sizeof (ElementValue) * SUBPANEL_KEYWORD_COUNT,
1002                        &subpanel_data_count, &subpanel_count);
1003
1004    ProcessRecord (fields, subpanel_data[subpanel_count - 1].element_values);
1005
1006    InitializeField (subpanel_data[subpanel_count - 1].element_values,
1007                     SUBPANEL_NAME, subpanel_parse_functions);
1008    InitializeField (subpanel_data[subpanel_count - 1].element_values,
1009                     SUBPANEL_CONTAINER_NAME, subpanel_parse_functions);
1010    InitializeField (subpanel_data[subpanel_count - 1].element_values,
1011                     SUBPANEL_LOCKED, subpanel_parse_functions);
1012    InitializeField (subpanel_data[subpanel_count - 1].element_values,
1013                     SUBPANEL_DELETE, subpanel_parse_functions);
1014
1015    OrderRecord (subpanel_data, subpanel_count, SUBPANEL_CONTAINER_NAME);
1016
1017    return (True);
1018 }
1019  
1020
1021
1022  
1023 /************************************************************************
1024  *
1025  *  SwitchParseCB
1026  *      Allocate a structure to contain the Switch record returned by
1027  *      the database read code and copy the record information into the
1028  *      structure.
1029  *
1030  ************************************************************************/
1031
1032 static Boolean
1033 SwitchParseCB (DtDtsDbField  * fields,
1034                DtDbPathId   path_id, 
1035                char        * host_prefix,
1036                Boolean       rejection)
1037
1038 {
1039    AllocateRecordData (&switch_data,
1040                        sizeof (ElementValue) * SWITCH_KEYWORD_COUNT,
1041                        &switch_data_count, &switch_count);
1042
1043    ProcessRecord (fields, switch_data[switch_count - 1].element_values);
1044
1045    InitializeField (switch_data[switch_count - 1].element_values,
1046                     SWITCH_NAME, switch_parse_functions);
1047    InitializeField (switch_data[switch_count - 1].element_values,
1048                     SWITCH_CONTAINER_NAME, switch_parse_functions);
1049    InitializeField (switch_data[switch_count - 1].element_values,
1050                     SWITCH_LOCKED, switch_parse_functions);
1051    InitializeField (switch_data[switch_count - 1].element_values,
1052                     SWITCH_DELETE, switch_parse_functions);
1053
1054    OrderRecord (switch_data, switch_count, SWITCH_CONTAINER_NAME);
1055
1056    return (True);
1057
1058
1059
1060
1061 /************************************************************************
1062  *
1063  *  ControlParseCB
1064  *      Allocate a structure to contain the Control record returned by
1065  *      the database read code and copy the record information into the
1066  *      structure.
1067  *
1068  ************************************************************************/
1069
1070 static Boolean
1071 ControlParseCB (DtDtsDbField  * fields,
1072                 DtDbPathId   path_id, 
1073                 char        * host_prefix,
1074                 Boolean       rejection)
1075
1076 {
1077    AllocateRecordData (&control_data,
1078                        sizeof (ElementValue) * CONTROL_KEYWORD_COUNT,
1079                        &control_data_count, &control_count);
1080
1081    ProcessRecord (fields, control_data[control_count - 1].element_values);
1082
1083    InitializePrimaryControlFields
1084                         (control_data[control_count - 1].element_values);
1085
1086    OrderRecord (control_data, control_count, CONTROL_CONTAINER_NAME);
1087
1088    return (True);
1089 }
1090
1091
1092
1093
1094 /************************************************************************
1095  *
1096  *  AnimationParseCB
1097  *      Allocate a structure to contain the Animation records returned by
1098  *      the database read code and copy the record information into the
1099  *      structure.
1100  *
1101  ************************************************************************/
1102
1103 static Boolean
1104 AnimationParseCB (DtDtsDbField  * fields,
1105                   DtDbPathId   path_id, 
1106                   char       * host_prefix,
1107                   Boolean      rejection)
1108
1109 {
1110    unsigned char *string, *source, *head_ptr;
1111    char * field1;
1112    char * field2;
1113    int count = panel.animation_count;
1114    int field_count = 0;
1115    void * val_rtn;
1116    int i;
1117    XrmQuark     animation_quark = XrmStringToQuark(ANIMATION);
1118
1119    panel.animation_data = (AnimationData *) 
1120                           XtRealloc ((char *) panel.animation_data, 
1121                                      sizeof (AnimationData) * (count + 1));
1122
1123    panel.animation_data[count].name = strdup(fields[0].fieldValue);
1124
1125
1126    for (i = 1; fields[i].fieldName != NULL; i++)
1127    {
1128        if (fields[i].fieldName == animation_quark)
1129           field_count++;
1130    }
1131
1132    panel.animation_data[count].item_count = field_count;
1133
1134    panel.animation_data[count].items = (AnimationItem *)
1135                          XtMalloc(sizeof(AnimationItem) * field_count);
1136
1137    for (i = 0; i < field_count; i++)
1138    {
1139      if (fields[i+1].fieldName == animation_quark)
1140      {
1141         head_ptr = source =
1142                  (unsigned char *) strdup((char *)fields[i+1].fieldValue);
1143
1144         if ((string = _DtWmParseNextTokenC(&source, False)) != NULL)
1145         {
1146            panel.animation_data[count].items[i].image_name =
1147                                                  strdup((char *) string);
1148            if ((string = _DtWmParseNextTokenC(&source, False)) != NULL)
1149            {
1150               StringToInt((char *)string, &val_rtn);
1151               panel.animation_data[count].items[i].delay = (int) val_rtn;
1152            }
1153            else
1154            {
1155               panel.animation_data[count].items[i].delay = 0;
1156            }
1157         }
1158
1159         free((char *)head_ptr);
1160      }
1161    }
1162      
1163    panel.animation_count++;
1164
1165    return (True);
1166 }
1167
1168
1169
1170 /************************************************************************
1171  *
1172  *  ControlSingleParseCB
1173  *      Allocate a structure to contain the Control record returned by
1174  *      the database read code and copy the record information into the
1175  *      structure.
1176  *
1177  ************************************************************************/
1178
1179 static Boolean
1180 ControlSingleParseCB (DtDtsDbField  * fields,
1181                 DtDbPathId   path_id, 
1182                 char        * host_prefix,
1183                 Boolean       rejection)
1184
1185 {
1186    if (control_element_value_found) return;
1187
1188    control_element_values = (ElementValue *) XtMalloc (sizeof(ElementValue) *
1189                                                        CONTROL_KEYWORD_COUNT);
1190    control_element_value_found = True;
1191
1192    ProcessRecord (fields, control_element_values);
1193
1194    InitializeControlFields(control_element_values, NULL);
1195
1196    return (True);
1197 }
1198
1199
1200  
1201  
1202 /************************************************************************
1203  *
1204  *  ProcessRecord
1205  *      Extract the fields of a returned record and put them into an
1206  *      allocated structure for latter processing.
1207  *
1208  ************************************************************************/
1209
1210 static void
1211 ProcessRecord (DtDtsDbField   * fields,
1212                ElementValue * element_values)
1213
1214 {
1215    int i, j;
1216    int entry;
1217
1218    int keyword_count;
1219    char ** field_keywords;
1220
1221
1222    /*  Find the position in the record structure for the value of   */
1223    /*  the entry keyword contained in the first position of the     */
1224    /*  fields array                                                 */
1225    
1226    for (entry = 0; entry < TOTAL_ENTRY_COUNT; entry++)
1227    {
1228       if (fields[0].fieldName == XrmStringToQuark(record_keywords[entry].record_keyword))
1229       {
1230          keyword_count = record_keywords[entry].keyword_count;
1231          field_keywords = record_keywords[entry].field_keywords;
1232          break;
1233       }
1234    }
1235
1236
1237    /*  Initialize the element_values array  */
1238    
1239    for (i = 0; i < keyword_count; i++)
1240    {
1241       (element_values + i)->use_default = True;
1242       (element_values + i)->string_value = NULL;
1243       (element_values + i)->parsed_value = NULL;
1244    }
1245
1246
1247    /*  Loop through each read in keyword value pair, comparing it  */
1248    /*  to the keywords for this record type and when found, enter  */
1249    /*  it into the element values array for the component.         */
1250
1251    for (i = 0; fields[i].fieldName != NULL; i++)
1252    {
1253       XrmQuark field1 = fields[i].fieldName;
1254       char * field2 = fields[i].fieldValue;
1255
1256
1257       /*  Search the field_keywords list and when the keyword is found    */
1258       /*  make a copy of field2 and place in its position.                */
1259       
1260       for (j = 0; j < keyword_count; j++)
1261       {
1262          if (field1 == XrmStringToQuark(field_keywords[j]))
1263          {
1264             (element_values + j)->use_default = False;
1265             (element_values + j)->string_value = strdup (field2);
1266             break;
1267          }
1268       }
1269
1270       if (j == keyword_count)
1271          _DtSimpleError (panel.app_name, DtWarning, NULL,
1272                          "Invalid keyword -- %s", XrmQuarkToString(field1));
1273    }
1274 }
1275
1276
1277
1278
1279 /************************************************************************
1280  *
1281  *  AllocateRecordData
1282  *      Allocate a structure to contain the values for a data base record
1283  *      and stuff it in an array for latter processing.  Do all of this
1284  *      by indirection so that multiple record types can be handled.
1285  *
1286  ************************************************************************/
1287
1288 static void
1289 AllocateRecordData (RecordData ** record_data,
1290                     int           record_size,
1291                     int         * record_data_count,
1292                     int         * record_count)
1293
1294 {
1295    if (*record_count >= *record_data_count)
1296    {
1297       *record_data_count += 10;
1298       *record_data = (RecordData *) 
1299                        XtRealloc ((char *) *record_data, 
1300                                   sizeof (RecordData *) * (*record_data_count));
1301    }
1302
1303    (*record_data)[*record_count].element_values = 
1304                                        (ElementValue *) XtMalloc (record_size);
1305       
1306             
1307    (*record_count)++;
1308 }
1309
1310
1311
1312 /************************************************************************
1313  *
1314  *  OrderRecord
1315  *      Compare the value in the last element values struture referenced
1316  *      by value_define to previous element values.  Move the element
1317  *      value structure to a new position defined by the comparison
1318  *      value being equal or greater the previous position and less
1319  *      than the next position
1320  *
1321  *      The function works on string data.
1322  *
1323  ************************************************************************/
1324
1325 static void
1326 OrderRecord (RecordData  * record_data,
1327              int           record_count,
1328              int           value_define)
1329
1330 {
1331    int i;
1332    int new_loc;
1333
1334    char         * position_value;
1335    char         * compare_value;
1336    ElementValue * element_values;
1337
1338
1339    /*  If this is the first record, it is already in position  */
1340    
1341    if (record_count == 1)
1342       return;
1343
1344
1345    /*  Extract the comparison value and loop backward through the  */
1346    /*  record_data to find the correct                             */
1347
1348    element_values = record_data[record_count - 1].element_values;
1349    position_value = element_values[value_define].parsed_value;
1350
1351    for (new_loc = record_count - 2; new_loc >= 0; new_loc--)
1352    {
1353       compare_value =
1354          record_data[new_loc].element_values[value_define].parsed_value;
1355
1356       if (strcmp (position_value, compare_value) >= 0)
1357          break;
1358
1359       record_data[new_loc + 1].element_values = 
1360          record_data[new_loc].element_values;
1361
1362    } 
1363
1364
1365    /*  If any values have been moved, place the position value into  */
1366    /*  the vacated spot.                                             */
1367    
1368    if (new_loc != record_count - 2)
1369       record_data[new_loc + 1].element_values = element_values;
1370 }
1371
1372
1373
1374
1375 /************************************************************************
1376  *
1377  *  SwapEntries
1378  *      Swap element value records based on positions.
1379  *
1380  ************************************************************************/
1381
1382 static void
1383 SwapEntries (RecordData * rec_data,
1384              int          i,
1385              int          j)
1386
1387
1388 {
1389    ElementValue * temp_value;
1390
1391    temp_value = rec_data[i].element_values;
1392    rec_data[i].element_values = rec_data[j].element_values;
1393    rec_data[j].element_values = temp_value;
1394 }
1395
1396
1397
1398
1399 /************************************************************************
1400  *
1401  *  QuickSort
1402  *      Reorder the records according to element index.  This routine
1403  *      performs a quick sort.  Positions that are equal will retain current
1404  *      positioning.
1405  *
1406  ************************************************************************/
1407
1408 #ifdef NOT_DEF
1409 static void
1410 QuickSort(RecordData * rec_data,
1411           int          left,
1412           int          right,
1413           int          elem_index,
1414           int          container)
1415 {
1416    int i, last;
1417      
1418    if (left >= right)
1419       return;
1420
1421    SwapEntries(rec_data, left, (left + right)/2);
1422
1423    last = left;
1424
1425    if (container == BOX && elem_index == BOX_POSITION_HINTS ||
1426        (container == CONTROL && elem_index == CONTROL_POSITION_HINTS))
1427    {
1428      for (i = left + 1; i <= right; i++)
1429         if (rec_data[i].element_values[elem_index].parsed_value <
1430             rec_data[left].element_values[elem_index].parsed_value)
1431            SwapEntries(rec_data, ++last, i);
1432    }
1433    else
1434    {
1435      for (i = left + 1; i <= right; i++)
1436         if (strcmp(rec_data[i].element_values[elem_index].parsed_value,
1437                    rec_data[left].element_values[elem_index].parsed_value) < 0)
1438            SwapEntries(rec_data, ++last, i);
1439    }
1440
1441    SwapEntries(rec_data, left, last);
1442
1443    QuickSort(rec_data, left, last - 1, elem_index, container);
1444    QuickSort(rec_data, last + 1, right, elem_index, container);
1445 }
1446 #endif /* NOT_DEF */
1447
1448
1449
1450
1451 /************************************************************************
1452  *
1453  *  BubbleSort
1454  *      Reorder the records according to element index.  This routine
1455  *      performs a bubble sort.  Positions that are equal will retain current
1456  *      positioning.
1457  *
1458  ************************************************************************/
1459
1460 static void
1461 BubbleSort (RecordData * rec_data,
1462             int          start,
1463             int          rec_count,
1464             int          elem_index)
1465
1466
1467 {
1468    int bound, t, j;
1469    Boolean is_string = False;
1470    char *str1, *str2;
1471
1472    bound = rec_count;
1473
1474    if (elem_index == CONTROL_CONTAINER_NAME ||
1475        elem_index == CONTROL_NAME)
1476       is_string = True;
1477
1478    while (bound != 0)
1479    {
1480       t = 0;
1481       for (j = start; j < bound; j++)
1482       {
1483         if (is_string)
1484         {
1485            str1 = (char *)rec_data[j].element_values[elem_index].parsed_value;
1486            str2 = (char *)rec_data[j+1].element_values[elem_index].parsed_value;
1487            if (strcmp(str1, str2) > 0)
1488            {
1489                  SwapEntries(rec_data, j, j+1);
1490                  t = j;
1491            }
1492         }
1493         else
1494         {
1495            if ((int) rec_data[j].element_values[elem_index].parsed_value >
1496                (int) rec_data[j+1].element_values[elem_index].parsed_value)
1497            {
1498               SwapEntries(rec_data, j, j+1);
1499               t = j;
1500            }
1501         }
1502       }
1503       bound = t;
1504    }
1505 }
1506
1507
1508
1509
1510 /************************************************************************
1511  *
1512  *  ReversePositions
1513  *      Reverse order of the records.  This routine reverses the order of
1514  *      the records so that user records that have the same positioning
1515  *      will get a higher presidence.
1516  *
1517  *
1518  ************************************************************************/
1519
1520 static void
1521 ReversePositions (RecordData * rec_data, 
1522                   int          start, 
1523                   int          end)
1524
1525
1526 {
1527    int i, j;
1528
1529    for (i = start, j = end; i < j; i++, j--)
1530    {
1531        SwapEntries(rec_data, i, j);
1532    }
1533 }
1534
1535
1536
1537
1538 /************************************************************************
1539  *
1540  *  ReorderByContainerName
1541  *      Reorder the records according to container name.  This will be done
1542  *      using a quick sort.  Container type order must be retained.  Matchinng
1543  *      names will retain current ordering.
1544  *      
1545  *************************************************************************/
1546
1547 static void
1548 ReorderByContainerName (RecordData * rec_data,
1549                         int          rec_count,
1550                         int          name,
1551                         int          elem_type)
1552
1553 {
1554    int i = 0, start = 0;
1555    int cont_type;
1556    
1557    while (i < rec_count)
1558    {
1559        cont_type = (int)
1560                    (rec_data[start].element_values[elem_type].parsed_value);
1561        while ((int)(rec_data[i].element_values[elem_type].parsed_value) ==
1562               cont_type)
1563        {
1564            i++;
1565            if (rec_count == i) break;
1566        }
1567
1568        BubbleSort(rec_data, start, i - 1, name);
1569        start = i;
1570    }
1571 }
1572
1573
1574
1575
1576 /************************************************************************
1577  *
1578  *  ReorderByName
1579  *      Reorder the records according to names.  This will be done
1580  *      using a quick sort.  Container name order must be retained.
1581  *      Matching names will retain current order.
1582  *
1583  *************************************************************************/
1584
1585 static void
1586 ReorderByName (RecordData * rec_data,
1587                int          rec_count,
1588                int          name,
1589                int          elem_type)
1590
1591 {
1592    int i = 0, start = 0;
1593    char *cont_name;
1594    
1595    while (i < rec_count)
1596    {
1597        cont_name = (char *)
1598                   (rec_data[start].element_values[elem_type].parsed_value);
1599        while (strcmp((char *)rec_data[i].element_values[elem_type].parsed_value,
1600                      cont_name) == 0)
1601        {
1602              i++;
1603              if (rec_count == i) break;
1604        }
1605
1606        BubbleSort(rec_data, start, i - 1, name);
1607        start = i;
1608    }
1609 }
1610
1611
1612
1613
1614 /************************************************************************
1615  *
1616  *  ReorderByPosition
1617  *      Reorder the records according to position_hints.  This will be done
1618  *      using a quick sort.  Positions that are equal will retain current
1619  *      positioning.
1620  *************************************************************************/
1621
1622 static void
1623 ReorderByPosition(RecordData *rec_data,
1624                   int         rec_count,
1625                   int         pos_hints,
1626                   int         cont_type,
1627                   int         cont_name)
1628
1629 {
1630    int   i = 0, start = 0;
1631    int   container_type;
1632    char  *container_name;
1633
1634    ReversePositions(rec_data, 0, rec_count - 1);
1635
1636    while (i < rec_count)
1637    {
1638        container_name = (char *)
1639                   (rec_data[start].element_values[cont_name].parsed_value);
1640
1641        if (cont_type == ANY_CONTAINER_TYPE)
1642        {
1643           while (strcmp((char *)
1644                         rec_data[i].element_values[cont_name].parsed_value,
1645                         container_name) == 0)
1646           {
1647                i++;
1648                if (rec_count == i) break;
1649           }
1650        }
1651        else
1652        {
1653           container_type = (int)
1654                   (rec_data[start].element_values[cont_type].parsed_value);
1655           while (((int)rec_data[i].element_values[cont_type].parsed_value ==
1656                                                            container_type) &&
1657                  (strcmp((char *)
1658                          rec_data[i].element_values[cont_name].parsed_value,
1659                          container_name) == 0))
1660           {
1661                i++;
1662                if (rec_count == i) break;
1663           }
1664        }
1665
1666        BubbleSort(rec_data, start, i - 1, pos_hints);
1667        start = i;
1668    }
1669
1670 }
1671
1672
1673
1674
1675 /************************************************************************
1676  *
1677  *  ReorderByContainerType
1678  *      Reorder the records according to container type.  This will be done
1679  *      using a bubble sort.  Container types that are match must retain
1680  *      current positioning.
1681  *
1682  *************************************************************************/
1683
1684 static void
1685 ReorderByContainerType (RecordData * rec_data,
1686                         int          rec_count,
1687                         int          container_type)
1688
1689 {
1690    BubbleSort(rec_data, 0, rec_count - 1, container_type);
1691 }
1692
1693
1694
1695
1696 /************************************************************************
1697  *
1698  *  RemoveEntry
1699  *
1700  ************************************************************************/
1701  
1702 void
1703 RemoveEntry (RecordData * record_data,
1704              int          record_type)
1705
1706
1707 {
1708    int i;
1709  
1710    for (i = 0; i < record_descriptor[record_type].maxFields; i++)
1711    {
1712        if (record_keywords[record_type].parse_functions[i].free_function
1713                                                              != NULL &&
1714            record_data->element_values[i].parsed_value != NULL &&
1715            record_data->element_values[i].use_default == False)
1716        {
1717           (*(record_keywords[record_type].parse_functions[i].free_function))
1718             (&(record_data->element_values[i].parsed_value));
1719        }
1720
1721        if (record_data->element_values[i].use_default == False &&
1722            record_data->element_values[i].string_value != NULL)
1723           free(record_data->element_values[i].string_value);
1724    }
1725                     
1726    XtFree((char *)record_data->element_values);
1727 }
1728
1729
1730
1731
1732 /************************************************************************
1733  *
1734  *  EliminateEntries
1735  *      Given a container type and the indicies of the records to be deleted,
1736  *      delete any components which are within the specified container type
1737  *      and range.
1738  *
1739  ************************************************************************/
1740
1741 static void
1742 EliminateEntries (RecordData * record_data,
1743                   int        * record_count,
1744                   int          start,
1745                   int          end,
1746                   int        * i,
1747                   int        * count,
1748                   int          record_type)
1749
1750 {
1751    int j, k;
1752
1753    if (start > end) return;
1754
1755    for (j = start; j <= end; j++)
1756    {
1757        RemoveEntry(&(record_data[j]), record_type);
1758    }
1759
1760    if (end + 1 < *record_count)
1761    {
1762       memmove((void *) &record_data[start], (void *) &record_data[end+1],
1763               (size_t) ((*record_count - end) * sizeof(RecordData)));
1764    }
1765
1766
1767    *i += (end - start) + 1;
1768    *count = *record_count -= (end - start) + 1;
1769 }
1770
1771
1772
1773
1774 /************************************************************************
1775  *
1776  *  ResolveDuplicates
1777  *      Reprocess each group to eliminate overridden components.
1778  *      If a component is locked, use the first lock encountered.
1779  *      Otherwise, use the last component read.   
1780  *
1781  ************************************************************************/
1782
1783 static void
1784 ResolveDuplicates (RecordData * record_data,
1785                    int        * record_count,
1786                    int          name_type,
1787                    int          container_type,
1788                    int          container_name,
1789                    int          lock_type,
1790                    int          record_type)
1791
1792 {
1793    int i, start_index, lock_index, last_index;
1794    ElementValue * element_values;
1795    int cont_type;
1796    char *cont_name, *record_name;
1797    int count = *record_count;
1798    Boolean locked;
1799
1800    i = count - 1;
1801
1802    /* Go through the array of records */
1803
1804    while (i >= 0)
1805    {
1806       element_values = record_data[i].element_values;
1807       if (ANY_CONTAINER_TYPE != container_type)
1808       {
1809          cont_type = (int) (element_values[container_type].parsed_value);
1810          cont_name = (char *) (element_values[container_name].parsed_value);
1811       }
1812       record_name = (char *) (element_values[name_type].parsed_value);
1813
1814       locked = (Boolean)(element_values[lock_type].parsed_value);
1815       if (locked)
1816       {
1817          i--;
1818          if (i < 0) break;
1819          start_index = last_index = i;
1820          element_values = record_data[i].element_values;
1821          if (ANY_CONTAINER_TYPE == container_type)
1822          {
1823             while ((strcmp((char *) (element_values[name_type].parsed_value),
1824                            cont_name) == 0))
1825             {
1826                last_index = i;
1827                i--;
1828                if (i < 0) break;
1829                element_values = record_data[i].element_values;
1830             }
1831          }
1832          else
1833          { 
1834             while (((int)(element_values[container_type].parsed_value)
1835                           == cont_type) &&
1836                   (strcmp((char *)(element_values[container_name].parsed_value),
1837                            cont_name) == 0) &&
1838                   (strcmp((char *)(element_values[name_type].parsed_value),
1839                            record_name) == 0))
1840             {
1841                last_index = i;
1842                i--;
1843                if (i < 0) break;
1844                element_values = record_data[i].element_values;
1845             }
1846          }
1847          if (start_index != last_index)
1848             EliminateEntries(record_data, record_count, last_index,
1849                              start_index - 1, &i, &count, record_type);
1850
1851          if (i < 0) break;
1852       }
1853       else
1854       {
1855          start_index = lock_index = last_index = i;
1856          i--;
1857          if (i < 0) continue;
1858          element_values = record_data[i].element_values;
1859          if (ANY_CONTAINER_TYPE == container_type)
1860          {
1861             while ((strcmp((char *) (element_values[name_type].parsed_value),
1862                            record_name) == 0))
1863             {
1864                 locked = (Boolean)(element_values[lock_type].parsed_value);
1865                 if (locked && start_index == lock_index)
1866                    lock_index = i;
1867                 last_index = i;
1868                 i--;
1869                 if (i < 0) break;
1870                 element_values = record_data[i].element_values;
1871             }
1872          }
1873          else
1874          {
1875             while (((int)(element_values[container_type].parsed_value)
1876                            == cont_type) &&
1877                   (strcmp((char *)(element_values[container_name].parsed_value),
1878                            cont_name) == 0) &&
1879                   (strcmp((char *)(element_values[name_type].parsed_value),
1880                            record_name) == 0))
1881             {
1882                 locked = (Boolean)(element_values[lock_type].parsed_value);
1883                 if (locked && start_index == lock_index)
1884                    lock_index = i;
1885                 last_index = i;
1886                 i--;
1887                 if (i < 0) break;
1888                 element_values = record_data[i].element_values;
1889             }
1890          }
1891          if (start_index != last_index)
1892          {
1893             if (start_index == lock_index)
1894                EliminateEntries(record_data, record_count, last_index + 1,
1895                                 start_index, &i, &count, record_type);
1896             else
1897             {
1898                int diff = start_index - lock_index;
1899                EliminateEntries(record_data, record_count, lock_index + 1,
1900                                 start_index, &i, &count, record_type);
1901                lock_index += diff;
1902                last_index += diff;
1903                if (lock_index != last_index)
1904                   EliminateEntries(record_data, record_count, last_index,
1905                                    lock_index - 1, &i, &count, record_type);
1906             }
1907          }
1908          if (i < 0) break;
1909       }
1910    }
1911 }
1912
1913
1914
1915
1916 /************************************************************************
1917  *
1918  *  GetNameList
1919  *      Given a record_data array and a particular container type, 
1920  *      allocate an array of pointers to strings and set to the component
1921  *      names of each component which matches the above criteria.
1922  *
1923  ************************************************************************/
1924
1925 static char **
1926 GetNameList (RecordData * record_data,
1927              int          record_count,
1928              int          name_type,
1929              int          container_type,
1930              int          container)
1931
1932 {
1933    int i;
1934
1935    char ** name_list = NULL;
1936    int     name_list_count = 0;
1937    int     found_count = 0;
1938
1939    for (i = 0; i < record_count; i++)
1940    {
1941       if (ANY_CONTAINER_TYPE == container_type ||
1942           (int)(record_data[i].element_values[container_type].parsed_value) == 
1943           container)
1944       {
1945          if (found_count >= name_list_count)
1946          {
1947             name_list_count += 10;
1948             name_list = 
1949                (char **) XtRealloc ((char *) name_list, 
1950                                    sizeof (char **) * (name_list_count + 1));
1951          }       
1952          name_list [found_count] = 
1953             record_data[i].element_values[name_type].parsed_value;
1954          found_count++;
1955       }
1956    }
1957
1958    if (name_list != NULL)
1959       name_list [found_count] = NULL;
1960
1961    return (name_list);
1962 }
1963
1964
1965
1966
1967
1968 /************************************************************************
1969  *
1970  *  EliminateUnused
1971  *      Given a record_data array, container name list and container type,
1972  *      delete any components which are within the specified container type
1973  *      but do not contain the container name.
1974  *
1975  ************************************************************************/
1976
1977 static void
1978 EliminateUnused (RecordData    * record_data,
1979                  int           * record_count,
1980                  char         ** cont_name_list,
1981                  int             cont_name,
1982                  int             cont_type,
1983                  int             container,
1984                  int             record_type)
1985
1986 {
1987    int i, j, dummy = 0;
1988    char * container_name;
1989    int count = *record_count;
1990    Boolean name_found = False;
1991    ElementValue * element_values;
1992
1993    i = 0;
1994
1995    while (i < count)
1996    {
1997        element_values = record_data[i].element_values;
1998        if (cont_type == ANY_CONTAINER_TYPE ||
1999            (int)(element_values[cont_type].parsed_value) == container)
2000        {
2001           if (cont_name_list != NULL)
2002           {
2003              for (j = 0; cont_name_list[j] != NULL; j++)
2004              {
2005                container_name = cont_name_list[j];
2006                if (strcmp((char *)element_values[cont_name].parsed_value,
2007                           container_name) == 0)
2008                {
2009                   name_found = True;
2010                   break;
2011                }
2012              }
2013           }
2014           if (!name_found)
2015           {
2016 #ifdef DEBUG
2017             printf("Entry Eliminated - %s\n",
2018                     (char *)element_values[cont_name].parsed_value);
2019 #endif
2020             EliminateEntries(record_data, record_count, i, i, &dummy, &count,
2021                              record_type);
2022           }
2023           else
2024           {
2025             name_found = False;
2026             i++;
2027           }
2028        }
2029        else
2030           i++;
2031    }
2032 }
2033
2034
2035
2036 /************************************************************************
2037  *
2038  *  EliminateDeleted
2039  *      Given a record_data array, delete any components which have the
2040  *      DELETE keyword set to True.  Also delete any duplicates that match
2041  *      the container name, container type, record name, and record type 
2042  *      but do not have the LOCKED keyword set to True.
2043  *
2044  ************************************************************************/
2045
2046 static void
2047 EliminateDeleted (RecordData    * record_data,
2048                  int           * record_count,
2049                  int             cont_name,
2050                  int             record_name,
2051                  int             record_type,
2052                  int             delete_type,
2053                  int             lock_type)
2054
2055 {
2056    int i, j, start, dummy = 0;
2057    int count;
2058    ElementValue * element_values, * other_element_values;
2059    char * container_name, * rec_name;
2060    int container_type, rec_type;
2061
2062    count = *record_count;
2063    i = 0;
2064
2065    while (i < count)
2066    {
2067        start = i;
2068        element_values = record_data[i].element_values;
2069        if ((Boolean)element_values[delete_type].parsed_value)
2070        {
2071           Boolean delete_rest = False;
2072
2073           if (record_type == CONTROL)
2074           {
2075              rec_type = (int)element_values[CONTROL_TYPE].parsed_value;
2076              container_type =
2077                        (int)element_values[CONTROL_CONTAINER_TYPE].parsed_value;
2078           }
2079           container_name = 
2080              XtNewString ((char *)element_values[cont_name].parsed_value);
2081           rec_name = 
2082              XtNewString ((char *)element_values[record_name].parsed_value);
2083
2084           for (j = count - 1; j >= 0; j--)
2085           {
2086              other_element_values = record_data[j].element_values;
2087              if ((record_type != CONTROL ||
2088                  ((int)other_element_values[CONTROL_CONTAINER_TYPE].parsed_value
2089                    == container_type &&
2090                   (int) other_element_values[CONTROL_TYPE].parsed_value
2091                    == rec_type)) &&
2092                  strcmp((char *)other_element_values[cont_name].parsed_value,
2093                         container_name) == 0 &&
2094                  strcmp((char *)other_element_values[record_name].parsed_value,
2095                         rec_name) == 0)
2096              {
2097                 if ((Boolean)other_element_values[lock_type].parsed_value)
2098                 {
2099                    if ((Boolean)other_element_values[delete_type].parsed_value)
2100                    {
2101                        EliminateEntries(record_data, record_count, j, j, &dummy,
2102                                         &count, record_type);
2103                        delete_rest = True;
2104                    }
2105                    else if (delete_rest)
2106                    {
2107                        EliminateEntries(record_data, record_count, j, j, &dummy,
2108                                         &count, record_type);
2109                    }
2110                 }
2111                 else
2112                    EliminateEntries(record_data, record_count, j, j, &dummy,
2113                                     &count, record_type);
2114              }
2115           }
2116
2117           XtFree(container_name);
2118           XtFree(rec_name);
2119        }
2120        else
2121           i++;
2122    }
2123 }
2124
2125
2126
2127
2128 /************************************************************************
2129  *
2130  *  InitializeField
2131  *      Given an ElementValues array, a particular keyword that references
2132  *      a single element and the parse function array for the record
2133  *      type:  if the element has a value string, parse it otherwise
2134  *      set the parsed value to the default.
2135  * 
2136  ************************************************************************/
2137  
2138 static void
2139 InitializeField (ElementValue  * element_values,
2140                  int             keyword,
2141                  ParseFunction * parse_functions)
2142
2143 {
2144    if (element_values[keyword].string_value != NULL)
2145    {
2146       element_values[keyword].use_default = False;
2147
2148       if (!parse_functions[keyword].parse_function (
2149                                       element_values[keyword].string_value,
2150                                       &(element_values[keyword].parsed_value)))
2151       {
2152          XtFree(element_values[keyword].string_value);
2153          element_values[keyword].string_value = NULL;
2154
2155          element_values[keyword].use_default = True;
2156          element_values[keyword].parsed_value = 
2157                                          parse_functions[keyword].default_value;
2158       }
2159    }
2160    else
2161    {
2162       element_values[keyword].use_default = True;
2163       element_values[keyword].parsed_value = 
2164          parse_functions[keyword].default_value;
2165    }           
2166 }
2167
2168
2169
2170 /************************************************************************
2171  *
2172  *  CountElements
2173  *      Given a record_data array, a container name and container type
2174  *      count how many records match and return the value.
2175  *
2176  ************************************************************************/
2177
2178 static int
2179 CountElements (RecordData * record_data,
2180                int          record_count,
2181                char       * container_name,
2182                int          name_type,
2183                int          container_type,
2184                int          container)
2185
2186
2187 {
2188    int i;
2189    static int found_count = 0;
2190
2191    for (i = 0; i < record_count; i++)
2192    {
2193       if (ANY_CONTAINER_TYPE == container_type ||
2194           (int)(record_data[i].element_values[container_type].parsed_value) == 
2195           container)
2196       {
2197          if (strcmp (container_name, 
2198                      record_data[i].element_values[name_type].parsed_value) ==0)
2199             found_count++;
2200       }
2201    }
2202
2203    return (found_count);
2204 }
2205
2206
2207
2208
2209 /************************************************************************
2210  *
2211  *  DeleteControlActionList
2212  *
2213  ************************************************************************/
2214  
2215
2216 void
2217 DeleteControlActionList (ControlData * control_data)
2218
2219
2220 {
2221    int i;
2222
2223    if (control_data->move_action != NULL)
2224       free(control_data->move_action);
2225    if (control_data->copy_action != NULL)
2226       free(control_data->copy_action);
2227    if (control_data->link_action != NULL)
2228       free(control_data->link_action);
2229
2230    if (control_data->actions != NULL)
2231    {
2232        for (i = 0; control_data->actions[i] != NULL; i++)
2233        {
2234           free (control_data->actions[i]->action_name);
2235           if (control_data->actions[i]->action_label != NULL)
2236              free (control_data->actions[i]->action_label);
2237           XtFree ((char *) control_data->actions[i]);
2238        }
2239
2240        XtFree((char *)control_data->actions);
2241    }
2242 }
2243
2244
2245
2246
2247 /************************************************************************
2248  *
2249  *  AddControlActionList
2250  *
2251  ************************************************************************/
2252  
2253
2254 void
2255 AddControlActionList (ControlData * control_data)
2256
2257
2258 {
2259    char * data_type = NULL;
2260    char * act_list = NULL;
2261    char * file_name = NULL;
2262    char * file_str;
2263    char ** action_list = NULL;
2264    int num_actions = 0;
2265    int i = 0;
2266    int result;
2267    Boolean is_file_control = False;
2268    PanelActionData * drop_action;
2269    char * label;
2270    int j = 0;
2271
2272
2273    if ((int)control_data->element_values[CONTROL_TYPE].parsed_value ==
2274                                                                  CONTROL_FILE)
2275    {
2276       file_name = (char *)
2277                   control_data->element_values[CONTROL_FILE_NAME].parsed_value;
2278
2279       data_type = DtDtsFileToDataType (file_name);
2280       is_file_control = True;   
2281    }
2282       
2283    if (data_type != NULL)
2284    {
2285       DtDtsAttribute  ** attr_list;
2286       char * attr[5];
2287
2288       attr_list = DtDtsDataTypeToAttributeList (data_type, file_name);
2289       
2290
2291       /*  The attribute list is ordered alphabetically by name so      */
2292       /*  do a linear search of the atr_list array and get the values  */
2293       /*  as use run into them.  Use the following array to get the    */
2294       /*  values for these attributes.                                 */
2295
2296       attr[0] = DtDTS_DA_ACTION_LIST;
2297       attr[1] = DtDTS_DA_COPY_TO_ACTION;
2298       attr[2] = DtDTS_DA_LINK_TO_ACTION;
2299       attr[3] = DtDTS_DA_MOVE_TO_ACTION;
2300
2301       if (attr_list != NULL)
2302       {
2303          for (i = 0; attr_list[i] != NULL; i++)
2304          {
2305             for (j = 0; j < 4; j++)
2306                if (strcmp (attr_list[i]->name, attr[j]) == 0)
2307                   break;
2308
2309
2310             /*  If we have found a match, find the appropriate attr  */
2311             /*  and assign the value.                                */
2312
2313             switch (j)
2314             {
2315                /* DtDTS_DA_ACTION_LIST */
2316                case 0:
2317                   act_list = (char *) strdup(attr_list[i]->value);
2318                break;
2319
2320                /* DtDTS_DA_COPY_TO_ACTION */
2321                case 1:
2322                   control_data->copy_action =
2323                                  (char *) strdup(attr_list[i]->value);
2324                break;
2325
2326                /* DtDTS_DA_LINK_TO_ACTION */
2327                case 2:
2328                   control_data->link_action = 
2329                                  (char *) strdup(attr_list[i]->value);
2330                break;
2331
2332                /* DtDTS_DA_MOVE_TO_ACTION */
2333                case 3:
2334                   control_data->move_action =
2335                                  (char *) strdup(attr_list[i]->value);
2336                break;
2337
2338                /* No Match */
2339                case 4:
2340                break;
2341             }
2342          }
2343       }
2344
2345       if (act_list)
2346       {
2347          action_list = _DtVectorizeInPlace (act_list, ',');
2348          for (i = 0; action_list[i] != NULL; i++)
2349              num_actions++;
2350       }
2351
2352       if (DtDtsDataTypeIsAction(data_type) && is_file_control)
2353          control_data->is_action = True;
2354
2355       if (attr_list != NULL)
2356          DtDtsFreeAttributeList(attr_list);
2357    }
2358
2359    if (action_list == NULL)
2360    {
2361       if (control_data->element_values[CONTROL_PUSH_ACTION].string_value != NULL)
2362       {
2363          action_list = (char **) XtMalloc(sizeof(char *) * 2);
2364
2365          action_list[0] = 
2366             control_data->element_values[CONTROL_PUSH_ACTION].string_value;
2367          action_list[1] = NULL;
2368          num_actions = 1;
2369       }
2370       else
2371          num_actions = 0;
2372    }
2373    
2374    control_data->actions = (PanelActionData **)
2375                                   XtMalloc(sizeof(PanelActionData *) *
2376                                            (num_actions + 1));
2377
2378    for (i = 0, j = 0; j < num_actions; i++, j++)
2379    {
2380       /* Remove the OpenInPlace action from the list of actions */
2381        if (strcmp(action_list[j],"OpenInPlace") == 0)
2382        {
2383           i--;
2384           continue;
2385        }
2386
2387        control_data->actions[i] = (PanelActionData *)
2388                                        XtMalloc(sizeof(PanelActionData));
2389
2390        control_data->actions[i]->action_name = strdup(action_list[j]);
2391
2392        control_data->actions[i]->aap = NULL;
2393        control_data->actions[i]->count = 0;
2394
2395        label = DtActionLabel (action_list[j]);
2396
2397        if (label != NULL)
2398           control_data->actions[i]->action_label = label;
2399        else
2400           control_data->actions[i]->action_label = strdup (action_list[j]);
2401
2402
2403    }
2404
2405    control_data->actions[i] = NULL;
2406
2407    if (act_list)
2408        free (act_list);
2409
2410    if (action_list)
2411        XtFree ((char *) action_list);
2412
2413    if ((data_type != NULL) && is_file_control)
2414       DtDtsFreeDataType (data_type);
2415 }
2416
2417
2418
2419
2420 /************************************************************************
2421  *
2422  *  ProcessBox
2423  *      For a box structure, find the control set that is to be contained
2424  *      by it, allocate a ControlData array and reassign the element
2425  *      values pointers.  Further process each control.
2426  *
2427  *  Inputs: box_data - a pointer the BoxData structure to be initialized.
2428  *
2429  ************************************************************************/
2430
2431 static void
2432 ProcessBox (BoxData * box_data)
2433
2434
2435 {
2436    ElementValue * element_values;
2437
2438    int box_control_count = 0;
2439    int i;
2440
2441
2442    /*  Loop the control array and check each control to see if it belongs  */
2443    /*  in this box.  If so, call a function to add it and then see if the  */
2444    /*  control has a subpanel to process.                                  */
2445
2446    for (i = 0; i < control_count; i++)
2447    {
2448       element_values = control_data[i].element_values;
2449
2450       if ((int) element_values[CONTROL_CONTAINER_TYPE].parsed_value == BOX &&
2451           strcmp ((char *) box_data->element_values[BOX_NAME].parsed_value,
2452                   (char *) element_values[CONTROL_CONTAINER_NAME].parsed_value) == 0)
2453       {
2454          ProcessControl ((XtPointer) box_data, BOX, &(box_data->control_data),
2455                           &box_control_count, element_values);
2456
2457          box_data->subpanel_count +=
2458             ProcessBoxControl (box_data->control_data[box_control_count - 1]);
2459       }
2460    }
2461
2462    box_data->control_data_count = box_control_count;
2463 }
2464
2465
2466
2467
2468 /************************************************************************
2469  *
2470  *  ProcessControl
2471  *      For each control that is created, reallocate the array of 
2472  *      pointer that hold the control and allocate a control structure.
2473  *      Initialize the control fields.  This is called for BOX, SUBPANEL
2474  *      and SWITCH controls.
2475  *
2476  *  Inputs: parent - a pointer to the head of the structure that is to
2477  *          contain this control.
2478  *          parent_type - the type of parent of the control.
2479  *          control_data_ptr - a pointer to the array of control pointers.
2480  *          control_count - the current count of controls within the array.
2481  *          element_values - the new controls database values.
2482  *
2483  ************************************************************************/
2484  
2485  
2486 static void
2487 ProcessControl (XtPointer       parent,
2488                 char            parent_type,
2489                 ControlData *** control_data_ptr,
2490                 int           * control_count,
2491                 ElementValue  * element_values)
2492
2493
2494 {
2495    ControlData * control;
2496
2497    *control_data_ptr = 
2498       (ControlData **) XtRealloc ((char *) *control_data_ptr,
2499                                  sizeof (ControlData *) * (*control_count + 1));
2500    (*control_data_ptr)[*control_count] = 
2501       (ControlData *) XtMalloc (sizeof (ControlData));
2502
2503    control = (*control_data_ptr)[*control_count];
2504
2505    control->element_values = element_values;
2506    control->parent_data = parent;
2507    control->parent_type = parent_type;
2508    control->subpanel_data = NULL;
2509    control->icon = NULL;
2510    control->arrow = NULL;
2511    control->arrow_separator = NULL;
2512    control->indicator = NULL;
2513    control->actions = NULL;
2514    control->is_action = False;
2515    control->move_action = NULL;
2516    control->copy_action = NULL;
2517    control->link_action = NULL;
2518    control->operation = NULL;
2519
2520    AddControlActionList (control);
2521
2522    *control_count = *control_count + 1;
2523 }
2524
2525
2526
2527
2528 /************************************************************************
2529  *
2530  *  ProcessBoxControl
2531  *      For a control structure within a box, see if there is a subpanel
2532  *      attached to it and if so, process the subpanel and its controls.
2533  *      Return the subpanel count to be stored as part of the box data.
2534  *
2535  *  Inputs: control_data - a pointer to the control to be processed
2536  *
2537  ************************************************************************/
2538
2539 static int
2540 ProcessBoxControl (ControlData * control_data)
2541
2542
2543 {
2544    int i;
2545    ElementValue * element_values;
2546    int box_subpanel_count = 0;
2547    SubpanelData * subpanel;
2548
2549
2550    /*  Loop through the subpanel data and find one that is attached  */
2551    /*  to the provided control.                                      */
2552
2553    for (i = 0; i < subpanel_count; i++)
2554    {
2555       element_values = subpanel_data[i].element_values;
2556
2557       if (strcmp ((char *) control_data->element_values[CONTROL_NAME].parsed_value,
2558                   (char *) element_values[SUBPANEL_CONTAINER_NAME].parsed_value) == 0)
2559       {
2560          box_subpanel_count = 1;
2561          
2562          control_data->subpanel_data = 
2563             (SubpanelData *) XtMalloc (sizeof (SubpanelData));
2564
2565          subpanel = control_data->subpanel_data;
2566          subpanel->element_values = element_values;
2567          subpanel->control_data = NULL;
2568          subpanel->control_data_count = 0;
2569          subpanel->parent_control_data = control_data;
2570          subpanel->default_control = NULL;
2571          subpanel->shell = NULL;
2572          subpanel->form = NULL;
2573          subpanel->dropzone = NULL;
2574          subpanel->separator = NULL;
2575          subpanel->main_panel_icon_copy = NULL;
2576          subpanel->torn = False;
2577
2578          ProcessSubpanel (subpanel);
2579
2580       }
2581    }
2582
2583    return (box_subpanel_count);
2584 }
2585
2586
2587
2588
2589 /************************************************************************
2590  *
2591  *  ProcessSubpanel
2592  *      For a Subpanel, find all of the controls within it an allocate
2593  *      a ControlData array and move the element values for the controls.
2594  *
2595  *  Inputs: subpanel_data - A pointer the the subpanel structure to be
2596  *          processed.
2597  *
2598  ************************************************************************/
2599
2600 static void
2601 ProcessSubpanel (SubpanelData * subpanel_data)
2602
2603
2604 {
2605    ElementValue * element_values;
2606
2607    int subpanel_control_count = 0;
2608    int i;
2609
2610
2611
2612    /*  Loop the control array and check each control to see if it belongs  */
2613    /*  in this subpanel.  If so, call a function to add it.                */
2614
2615    for (i = 0; i < control_count; i++)
2616    {
2617       element_values = control_data[i].element_values;
2618
2619       if ((int) element_values[CONTROL_CONTAINER_TYPE].parsed_value == SUBPANEL &&
2620           strcmp ((char *) subpanel_data->element_values[SUBPANEL_NAME].parsed_value,
2621                   (char *) element_values[CONTROL_CONTAINER_NAME].parsed_value) == 0)
2622       {
2623          ProcessControl ((XtPointer) subpanel_data, SUBPANEL,
2624                           &(subpanel_data->control_data),
2625                           &subpanel_control_count, element_values);
2626       }
2627    }
2628
2629    subpanel_data->control_data_count = subpanel_control_count;
2630 }
2631
2632
2633
2634
2635 /************************************************************************
2636  *
2637  *  ProcessSwitch
2638  *      For a Switch, find all of the controls within it an allocate
2639  *      a ControlData array and move the element values for the controls.
2640  *
2641  *  Inputs: switch_data - a pointer to the switch data structure to be
2642  *          processed.
2643  *
2644  ************************************************************************/
2645
2646 static void
2647 ProcessSwitch (SwitchData * switch_data)
2648
2649
2650 {
2651    ElementValue * element_values;
2652
2653    int switch_control_count = 0;
2654    int i;
2655
2656
2657    /*  Count the number of controls that are to go into this switch  */
2658    /*  and allocate a ControlData array to hold the controls.        */
2659
2660    for (i = 0; i < control_count; i++)
2661    {
2662       element_values = control_data[i].element_values;
2663
2664       if ((int) element_values[CONTROL_CONTAINER_TYPE].parsed_value == SWITCH &&
2665           strcmp ((char *) switch_data->element_values[SWITCH_NAME].parsed_value,
2666                   (char *) element_values[CONTROL_CONTAINER_NAME].parsed_value) == 0)
2667       {
2668          ProcessControl ((XtPointer) switch_data, SWITCH,
2669                           &(switch_data->control_data),
2670                           &switch_control_count, element_values);
2671       }
2672    }
2673
2674    switch_data->control_data_count = switch_control_count;
2675 }
2676
2677
2678
2679
2680 /************************************************************************
2681  *
2682  *  CreateComponentFileName
2683  *      Create a file name in which to store a component file.  This is
2684  *      accomplished by using the components name with an integer value
2685  *      appended.
2686  *
2687  *  Inputs: record_data - a pointer to the struture that contains the
2688  *            components name, as well as other values.
2689  *
2690  ************************************************************************/
2691  
2692
2693 static char *
2694 CreateComponentFileName (RecordData * record_data)
2695
2696
2697 {
2698    char * file_name;
2699    char * component_name;
2700    struct stat stat_info;
2701    int i;
2702
2703
2704    component_name = XtMalloc(9);
2705    strncpy (component_name, record_data->element_values[0].string_value, 8);
2706    component_name[8] = '\0';
2707
2708    file_name = XtMalloc (strlen (HOME_DIR) + strlen (TYPES_DIR) + 14);
2709
2710    for (i = 1; i < 1000; i++)
2711    {
2712       sprintf(file_name, "%s%s%s%d.fp", HOME_DIR, TYPES_DIR, component_name, i);
2713
2714       if (lstat (file_name, &stat_info) != 0)
2715          break;
2716    }
2717
2718    XtFree(component_name);
2719
2720    return (file_name);
2721 }
2722
2723
2724
2725
2726 /************************************************************************
2727  *
2728  *  WriteComponentToFile
2729  *      Write a component (contained within record_data) to a .fp file.
2730  *
2731  *  Inputs: record_data - a pointer to the data for the component,
2732  *            including its element values.
2733  *          record_type - the type of component (CONTROL, SUBPANEL, ...)
2734  *          keywords - the ordered array of keywords for the component
2735  *            type, used to reference into the element values array.
2736  *          container_name - the parent of the component.
2737  *          container_type - the type of parent of the component.
2738  *          delete - whether the component is be added or deleted.
2739  *
2740  ************************************************************************/
2741  
2742
2743 static void
2744 WriteComponentToFile (RecordData * record_data,
2745                       int          record_type,
2746                       char      ** keywords,
2747                       char       * container_name,
2748                       int          container_type,
2749                       Boolean      delete)
2750
2751
2752 {
2753    FILE * fd;
2754    char * file_name = CreateComponentFileName (record_data);
2755    int k;
2756
2757    if ((fd = fopen(file_name, "w")) != NULL)
2758    {
2759       fprintf (fd, "%s  %s\n{\n", keywords[0],
2760                record_data->element_values[0].string_value);
2761
2762       if (delete)
2763       {
2764          if (record_type == CONTROL)
2765          {
2766             fprintf(fd, "   TYPE      %s\n",
2767                    record_data->element_values[CONTROL_TYPE].string_value);
2768             fprintf(fd, "   CONTAINER_TYPE      %s\n",
2769               record_data->element_values[CONTROL_CONTAINER_TYPE].string_value);
2770          }
2771
2772          fprintf(fd, "   CONTAINER_NAME      %s\n", container_name);
2773          fprintf(fd, "   DELETE      True\n");
2774          
2775       }
2776       else
2777       {
2778          for (k = 1; k < record_descriptor[record_type].maxFields; k++)
2779          {
2780              if (record_data->element_values[k].string_value != NULL &&
2781                  record_data->element_values[k].use_default == False)
2782              {
2783                 if (record_type == CONTROL &&
2784                     (int) record_data->element_values[CONTROL_TYPE].parsed_value == CONTROL_FILE &&
2785                     (k == CONTROL_PUSH_ACTION ||
2786                      k == CONTROL_LABEL || k == CONTROL_DROP_ACTION))
2787                    continue;
2788
2789                 fprintf (fd, "   %s     %s\n", keywords[k],
2790                          record_data->element_values[k].string_value);
2791              }
2792          }
2793       }
2794
2795       fprintf(fd, "}\n");
2796    
2797       fflush(fd);
2798       fclose(fd);
2799
2800       if (record_type == CONTROL)
2801          SessionAddFileData(file_name,
2802                          record_data->element_values[CONTROL_NAME].string_value,
2803                          (int) CONTROL,
2804                          container_name, container_type, delete);
2805       else
2806          SessionAddFileData(file_name,
2807                             record_data->element_values[0].string_value,
2808                             record_type, container_name, container_type,delete);
2809    }
2810
2811    WmFrontPanelSessionSaveData ();
2812
2813    XtFree (file_name);
2814 }
2815
2816
2817
2818
2819 /************************************************************************
2820  *
2821  *  RemoveComponentFile
2822  *      Find the dynamic .fp file name of a file in the session data and
2823  *      unlink the file to remove the component.  If no file name is
2824  *      found or the unlink fails, Call a function to write a .fp for
2825  *      the file which will have the DELETE keyword set to True.
2826  *
2827  ************************************************************************/
2828  
2829
2830 static void
2831 RemoveComponentFile (RecordData * record_data,
2832                      int          record_type,
2833                      char      ** keywords,
2834                      char       * container_name,
2835                      int          container_type)
2836
2837
2838 {
2839    char * file_name;
2840
2841    file_name = 
2842       SessionFileNameLookup (record_data->element_values[0].string_value, 
2843                              record_type, container_name, container_type);
2844
2845    if (file_name == NULL || unlink (file_name) < 0)
2846       WriteComponentToFile (record_data, record_type, keywords,
2847                             container_name, container_type, True);
2848    else
2849    {
2850       SessionDeleteFileData (file_name);
2851       WmFrontPanelSessionSaveData ();
2852    }
2853 }
2854
2855
2856
2857
2858 /************************************************************************
2859  *
2860  *  WriteControlComponentFile
2861  *      Set up the parameters to call a function which will write out
2862  *      to a .fp file a control description.
2863  *
2864  *      Inputs: control_data - a pointer to the control to be written.
2865  *
2866  ************************************************************************/
2867  
2868
2869 void
2870 WriteControlComponentFile (ControlData * control_data)
2871
2872
2873 {
2874    ElementValue * element_values;
2875
2876    element_values = control_data->element_values;
2877    
2878    WriteComponentToFile ((RecordData *) control_data, CONTROL, control_keywords,
2879                          (char *) element_values[CONTROL_CONTAINER_NAME].parsed_value,
2880                          (int) element_values[CONTROL_CONTAINER_TYPE].parsed_value,
2881                          False);
2882 }
2883
2884
2885
2886
2887 /************************************************************************
2888  *
2889  *  WriteSubpanelComponentFile
2890  *      Set up the parameters to call a function which will write out
2891  *      to a .fp file a subpanel description.
2892  *
2893  *      Inputs: subpanel_data - a pointer to the subpanel to be written.
2894  *
2895  ************************************************************************/
2896  
2897 void
2898 WriteSubpanelComponentFile (SubpanelData * subpanel_data)
2899
2900
2901 {
2902    ElementValue * element_values = subpanel_data->element_values;
2903
2904    WriteComponentToFile ((RecordData *) subpanel_data, SUBPANEL, subpanel_keywords,
2905                          (char *) element_values[SUBPANEL_CONTAINER_NAME].parsed_value,
2906                          CONTROL, False);
2907 }
2908
2909
2910
2911
2912 /************************************************************************
2913  *
2914  *  RemoveControlComponentFile
2915  *      Set up the parameters to call a function which delete a control's
2916  *      .fp file.
2917  *
2918  *      Inputs: control_data - a pointer to the control to be deleted.
2919  *
2920  ************************************************************************/
2921  
2922
2923 void
2924 RemoveControlComponentFile (ControlData * control_data)
2925
2926
2927 {
2928    ElementValue * element_values = control_data->element_values;
2929
2930    RemoveComponentFile ((RecordData *) control_data, CONTROL, control_keywords,
2931                         (char *) element_values[CONTROL_CONTAINER_NAME].parsed_value,
2932                         (int) element_values[CONTROL_CONTAINER_TYPE].parsed_value);
2933 }
2934
2935
2936
2937
2938 /************************************************************************
2939  *
2940  *  RemoveSubpanelComponentFile
2941  *      Set up the parameters to call a function which delete a subpanel's
2942  *      .fp file.
2943  *
2944  *      Inputs: subpanel_data - a pointer to the subpanel to be deleted.
2945  *
2946  ************************************************************************/
2947  
2948 void
2949 RemoveSubpanelComponentFile (SubpanelData * subpanel_data)
2950
2951
2952 {
2953    ElementValue * element_values = subpanel_data->element_values;
2954
2955    RemoveComponentFile ((RecordData *) subpanel_data, SUBPANEL, subpanel_keywords,
2956                         (char *) element_values[SUBPANEL_CONTAINER_NAME].parsed_value,
2957                         CONTROL);
2958 }
2959
2960
2961
2962
2963 /************************************************************************
2964  *
2965  *  _WriteControlElementValues
2966  *      Set up a loop which write out all of the values that define
2967  *      a control.  These are written as normal keyword, value pairs.
2968  *
2969  *  Inputs: element_values - a pointer to the array of element value
2970  *          strutures each of which contain a value for a keyword.
2971  *
2972  ************************************************************************/
2973  
2974
2975 void
2976 _WriteControlElementValues (ElementValue * element_values)
2977
2978
2979 {
2980    int k; 
2981
2982    printf("%s   %s\n{\n", control_keywords[0], element_values[0].string_value);
2983
2984    for (k = 1; k < record_descriptor[CONTROL].maxFields; k++)
2985    {
2986        if (element_values[k].string_value != NULL)
2987           printf("   %s %s\n", 
2988                  control_keywords[k], element_values[k].string_value);
2989    }
2990
2991    printf("}\n");
2992 }
2993
2994
2995
2996
2997
2998 /************************************************************************
2999  *
3000  *  InitParse
3001  *
3002  ************************************************************************/
3003  
3004 void
3005 InitParse (char          * file_name,
3006            ElementValue ** elem_vals)
3007
3008
3009 {
3010    char * tmpPath;
3011    char * tmpDir;
3012    char * hostName;
3013    char * tmpName;
3014    char * baseName;
3015    char * tmpFile;
3016    DtDirPaths * dirPath;
3017
3018
3019    /* create directory for dir path */
3020
3021    tmpPath = XtMalloc (strlen(HOME_DIR) + strlen(TYPES_DIR) + 34);
3022    sprintf (tmpPath, "%s%s%s%d", HOME_DIR, TYPES_DIR, "fp", (int) getpid());
3023    mkdir (tmpPath, S_IRUSR | S_IWUSR | S_IXUSR);
3024
3025
3026    /* create symbolic link to file_name */
3027
3028    tmpName = XtNewString(file_name);
3029    baseName = strrchr(tmpName, '/');
3030    tmpFile = XtMalloc(strlen(tmpPath) + strlen(baseName) + 1);
3031    sprintf(tmpFile, "%s%s", tmpPath, baseName);
3032    symlink(file_name, tmpFile);
3033
3034    hostName = XtMalloc((Cardinal)(MAXHOSTNAMELEN + 1));
3035    DtGetShortHostname (hostName, MAXHOSTNAMELEN + 1);
3036
3037    tmpDir = XtMalloc(strlen(hostName) + strlen(tmpPath) + 2);
3038    sprintf(tmpDir, "%s:%s", hostName, tmpPath);
3039
3040    dirPath = (DtDirPaths *) XtMalloc(sizeof(DtDirPaths));
3041    dirPath->dirs = (char **) XtMalloc(sizeof(char *) * 2);
3042    dirPath->paths = (char **) XtMalloc(sizeof(char *) * 2);
3043
3044    dirPath->dirs[0] = tmpDir;
3045    dirPath->dirs[1] = NULL;
3046    dirPath->paths[0] = tmpPath;
3047    dirPath->paths[1] = NULL;
3048
3049    _DtDbRead (dirPath, FILE_TYPE_SUFFIX, control_record_descriptor, 2);
3050
3051    control_element_value_found = False;
3052
3053    /* remove link and directory */
3054
3055    unlink(tmpFile);
3056    rmdir(tmpPath);
3057
3058    XtFree((char *) dirPath->dirs);
3059    XtFree((char *) dirPath->paths);
3060    XtFree((char *) dirPath);
3061    XtFree(hostName);
3062    XtFree(tmpName);
3063    XtFree(tmpDir);
3064    XtFree(tmpPath);
3065    XtFree(tmpFile);
3066
3067    *elem_vals = control_element_values;
3068 }
3069
3070
3071
3072
3073 /************************************************************************
3074  *
3075  *  FreeFileControlField
3076  *
3077  ************************************************************************/
3078
3079
3080 static void
3081 FreeFileControlField (ElementValue * element_values, 
3082                       int            indx)
3083
3084
3085 {
3086    if (control_parse_functions[indx].free_function != NULL &&
3087        element_values[indx].parsed_value != NULL &&
3088        element_values[indx].use_default == False)
3089    {
3090       (*(control_parse_functions[indx].free_function))
3091          (&(element_values[indx].parsed_value));
3092       element_values[indx].parsed_value = NULL;
3093    }
3094
3095    if (element_values[indx].use_default == False &&
3096        element_values[indx].string_value != NULL)
3097    {
3098       free(element_values[indx].string_value);
3099       element_values[indx].string_value = NULL;
3100    }
3101 }
3102                     
3103
3104
3105
3106 /************************************************************************
3107  *
3108  *  InitializePrimaryControlFields
3109  *
3110  ************************************************************************/
3111  
3112
3113 static void
3114 InitializePrimaryControlFields (ElementValue * element_values)
3115
3116
3117 {
3118    InitializeField (element_values,
3119                     CONTROL_NAME, control_parse_functions);
3120    InitializeField (element_values,
3121                     CONTROL_CONTAINER_NAME, control_parse_functions);
3122    InitializeField (element_values,
3123                     CONTROL_CONTAINER_TYPE, control_parse_functions);
3124    InitializeField (element_values,
3125                     CONTROL_LOCKED, control_parse_functions);
3126    InitializeField (element_values,
3127                     CONTROL_DELETE, control_parse_functions);
3128
3129 }
3130
3131
3132
3133
3134 /************************************************************************
3135  *
3136  *  InitializeSecondaryControlFields
3137  *
3138  ************************************************************************/
3139
3140
3141 static void
3142 InitializeSecondaryControlFields (ElementValue * element_values)
3143
3144
3145 {
3146    InitializeField (element_values,
3147                     CONTROL_TYPE, control_parse_functions);
3148    InitializeField (element_values,
3149                     CONTROL_POSITION_HINTS, control_parse_functions);
3150    InitializeField (element_values,
3151                     CONTROL_ALTERNATE_ICON, control_parse_functions);
3152    InitializeField (element_values,
3153                     CONTROL_PUSH_ANIMATION, control_parse_functions);
3154    InitializeField (element_values,
3155                     CONTROL_DROP_ANIMATION, control_parse_functions);
3156    InitializeField (element_values,
3157                     CONTROL_PUSH_RECALL, control_parse_functions);
3158    InitializeField (element_values,
3159                     CONTROL_MONITOR_TYPE, control_parse_functions);
3160    InitializeField (element_values,
3161                     CONTROL_CLIENT_NAME, control_parse_functions);
3162    InitializeField (element_values,
3163                     CONTROL_CLIENT_GEOMETRY, control_parse_functions);
3164    InitializeField (element_values,
3165                     CONTROL_FILE_NAME, control_parse_functions);
3166    InitializeField (element_values,
3167                     CONTROL_DATE_FORMAT, control_parse_functions);
3168    InitializeField (element_values,
3169                     CONTROL_HELP_STRING, control_parse_functions);
3170    InitializeField (element_values,
3171                     CONTROL_HELP_VOLUME, control_parse_functions);
3172    InitializeField (element_values,
3173                     CONTROL_HELP_TOPIC, control_parse_functions);
3174
3175 }
3176
3177
3178
3179
3180 /************************************************************************
3181  *
3182  *  InitializeFileControlFields
3183  *
3184  ************************************************************************/
3185  
3186
3187 static void
3188 InitializeFileControlFields (ElementValue * element_values,
3189                              char         * data_type)
3190
3191
3192 {
3193    if ((int)element_values[CONTROL_TYPE].parsed_value == CONTROL_FILE)
3194    {
3195       Boolean free_data_type = False;
3196       char * act_list;
3197       char ** action_list = NULL;
3198       char * icon_name;
3199       char * file_name;
3200       char * description;
3201       char * file_str;
3202       char * label = NULL;
3203       int i, j, result;
3204
3205       struct stat stat_info;
3206       Boolean valid_file = True;
3207    
3208
3209       file_name = (char *) element_values[CONTROL_FILE_NAME].parsed_value;
3210
3211       if (lstat (file_name, &stat_info) != 0)
3212          valid_file = False;
3213
3214       if (data_type == NULL && file_name != NULL)
3215       {
3216          data_type = DtDtsFileToDataType (file_name);
3217          free_data_type = True;
3218       }
3219
3220       if (data_type != NULL)
3221       {
3222          if (valid_file)
3223          {
3224             icon_name = DtDtsDataTypeToAttributeValue (data_type,
3225                                                        DtDTS_DA_ICON, NULL);
3226
3227             if (element_values[CONTROL_NORMAL_ICON].string_value != NULL)
3228             {
3229                XtFree (element_values[CONTROL_NORMAL_ICON].string_value);
3230                element_values[CONTROL_NORMAL_ICON].string_value = NULL;
3231             }
3232
3233             element_values[CONTROL_NORMAL_ICON].string_value =
3234                                                        XtNewString (icon_name);
3235
3236             DtDtsFreeAttributeValue(icon_name);
3237          }
3238
3239          description = 
3240            DtDtsDataTypeToAttributeValue(data_type, DtDTS_DA_DESCRIPTION, NULL);
3241
3242          if (element_values[CONTROL_HELP_STRING].string_value != NULL)
3243          {
3244             XtFree (element_values[CONTROL_HELP_STRING].string_value);
3245             element_values[CONTROL_HELP_STRING].string_value = NULL;
3246          }
3247
3248          element_values[CONTROL_HELP_STRING].string_value = XtNewString (description);
3249          DtDtsFreeAttributeValue (description);
3250
3251
3252          act_list = DtDtsDataTypeToAttributeValue (data_type,
3253                                                    DtDTS_DA_ACTION_LIST,
3254                                                    NULL);
3255          if (act_list)
3256             action_list = _DtVectorizeInPlace (act_list, ',');
3257
3258          if (action_list && action_list[0] != NULL)
3259          {
3260             element_values[CONTROL_PUSH_ACTION].string_value =
3261                                               strdup (action_list[0]);
3262             element_values[CONTROL_DROP_ACTION].string_value =
3263                                               strdup (action_list[0]);
3264
3265             if (DtDtsDataTypeIsAction (data_type))
3266                label = DtActionLabel (action_list[0]);
3267          }
3268
3269          /* try to set it to the name of the type */
3270          if (label == NULL) {
3271              label = DtDtsDataTypeToAttributeValue (data_type,
3272                                                     DtDTS_DA_LABEL, NULL);
3273
3274              /* copy & correctly free the memory */
3275              if (label) {
3276                  char *t = label;
3277
3278                  label = XtNewString(t);
3279
3280                  DtDtsFreeAttributeValue(t);
3281              }
3282          }
3283          
3284
3285          if (label == NULL && file_name != NULL)
3286          {
3287             if ((file_str = (char *)strrchr(file_name, '/')) == NULL)
3288                 file_str = file_name;
3289             else
3290                 file_str++;
3291             label = XtNewString(file_str);
3292          }
3293
3294          if (label != NULL)
3295             element_values[CONTROL_LABEL].string_value = label;
3296
3297
3298          if (data_type != NULL)
3299          {
3300             if (act_list)
3301             {
3302                DtDtsFreeAttributeValue (act_list);
3303                XtFree ((char *) action_list);
3304             }
3305
3306             if (free_data_type)
3307                DtDtsFreeDataType (data_type);
3308          }
3309       }
3310    } 
3311
3312    InitializeField (element_values,
3313                     CONTROL_NORMAL_ICON, control_parse_functions);
3314    InitializeField (element_values,
3315                     CONTROL_HELP_STRING, control_parse_functions);
3316    InitializeField (element_values,
3317                     CONTROL_LABEL, control_parse_functions);
3318    InitializeField (element_values,
3319                     CONTROL_PUSH_ACTION, control_parse_functions);
3320    InitializeField (element_values,
3321                     CONTROL_DROP_ACTION, control_parse_functions);
3322 }
3323
3324
3325
3326
3327 /************************************************************************
3328  *
3329  *  InitializeControlFields
3330  *
3331  ************************************************************************/
3332
3333
3334 void
3335 InitializeControlFields (ElementValue * element_values,
3336                          char         * data_type)
3337
3338
3339 {
3340    InitializePrimaryControlFields (element_values);
3341    InitializeSecondaryControlFields (element_values);
3342    InitializeFileControlFields (element_values, data_type);
3343 }
3344
3345
3346
3347
3348 /************************************************************************
3349  *
3350  *  UpdateFileType
3351  *
3352  ************************************************************************/
3353  
3354
3355 static void
3356 UpdateFileType (ControlData * control_data)
3357
3358
3359 {
3360    char * icon_name;
3361    char * control_label;
3362    XmString icon_label;
3363    Arg al[2];
3364
3365    FreeFileControlField (control_data->element_values, CONTROL_NORMAL_ICON);
3366    FreeFileControlField (control_data->element_values, CONTROL_PUSH_ACTION);
3367    FreeFileControlField (control_data->element_values, CONTROL_DROP_ACTION);
3368    FreeFileControlField (control_data->element_values, CONTROL_LABEL);
3369    InitializeFileControlFields (control_data->element_values, NULL);
3370
3371    DeleteControlActionList (control_data);
3372    AddControlActionList (control_data);
3373
3374    icon_name =
3375          (char *)control_data->element_values[CONTROL_NORMAL_ICON].parsed_value;
3376
3377    if ((int)control_data->element_values[CONTROL_CONTAINER_TYPE].parsed_value ==
3378                                                                        SUBPANEL)
3379    {
3380       icon_name = GetIconName (icon_name, panel.sub_icon_size);
3381    }
3382    else
3383    {
3384       icon_name = GetIconName (icon_name, panel.main_icon_size);
3385
3386       if (icon_name == NULL)
3387          icon_name = GetIconName (icon_name, panel.sub_icon_size);
3388    }
3389
3390    control_label = (char *)
3391                    control_data->element_values[CONTROL_LABEL].parsed_value;
3392
3393    icon_label = XmStringCreateLocalized (control_label);
3394
3395    XtSetArg(al[0], XmNimageName, icon_name);
3396    XtSetArg(al[1], XmNstring, icon_label);
3397    XtSetValues(control_data->icon, al, 2);
3398 }
3399
3400
3401
3402
3403 /************************************************************************
3404  *
3405  *  UpdateFileTypeControlFields
3406  *
3407  ************************************************************************/
3408  
3409
3410 void
3411 UpdateFileTypeControlFields (void)
3412
3413
3414 {
3415    BoxData * box_data;
3416    ControlData * control_data;
3417    SubpanelData * subpanel_data;
3418    SwitchData * switch_data;
3419    int i, j, k;
3420
3421    if (panel_count == 0) return;
3422
3423    for (i = 0; i < panel.box_data_count; i++)
3424    {
3425       box_data = panel.box_data[i];
3426
3427       for (j = 0; j < box_data->control_data_count; j++)
3428       {
3429          control_data = box_data->control_data[j];
3430
3431          if ((int)control_data->element_values[CONTROL_TYPE].parsed_value ==
3432                                                                  CONTROL_FILE)
3433             UpdateFileType(control_data);
3434
3435          if (control_data->subpanel_data != NULL)
3436          {
3437             subpanel_data = control_data->subpanel_data;
3438
3439             for (k = 0; k < subpanel_data->control_data_count; k++)
3440             {
3441                control_data = subpanel_data->control_data[k];
3442
3443                if ((int)control_data->element_values[CONTROL_TYPE].parsed_value
3444                                                                 == CONTROL_FILE)
3445                   UpdateFileType(control_data);
3446             }
3447          }
3448       }
3449
3450       if (box_data->switch_data != NULL)
3451       {
3452          switch_data = box_data->switch_data;
3453          for (j = 0; j < switch_data->control_data_count; j++)
3454          {
3455             control_data = switch_data->control_data[j];
3456
3457             if ((int)control_data->element_values[CONTROL_TYPE].parsed_value ==
3458                                                                    CONTROL_FILE)
3459                UpdateFileType(control_data);
3460          }
3461       }
3462    }
3463 }
3464
3465
3466
3467
3468 /************************************************************************
3469  *
3470  *  InitializeSubpanelFields
3471  *
3472  ************************************************************************/
3473  
3474
3475 void
3476 InitializeSubpanelFields (ElementValue * element_values)
3477
3478
3479 {
3480    InitializeField (element_values,
3481                     SUBPANEL_NAME, subpanel_parse_functions);
3482    InitializeField (element_values,
3483                     SUBPANEL_CONTAINER_NAME, subpanel_parse_functions);
3484    InitializeField (element_values,
3485                     SUBPANEL_LOCKED, subpanel_parse_functions);
3486    InitializeField (element_values,
3487                     SUBPANEL_CONTROL_INSTALL, subpanel_parse_functions);
3488    InitializeField (element_values,
3489                     SUBPANEL_TITLE, subpanel_parse_functions);
3490    InitializeField (element_values,
3491                     SUBPANEL_DELETE, subpanel_parse_functions);
3492    InitializeField (element_values,
3493                     SUBPANEL_HELP_STRING, subpanel_parse_functions);
3494    InitializeField (element_values,
3495                     SUBPANEL_HELP_TOPIC, subpanel_parse_functions);
3496    InitializeField (element_values,
3497                     SUBPANEL_HELP_VOLUME, subpanel_parse_functions);
3498 }
3499
3500