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