home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / shelledt / shelledt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  48.6 KB  |  1,661 lines

  1. /*
  2.  * Copyright (c) 1990, 1991, 1992 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23. /* $Header: /Source/Media/collab/ShellEdit/RCS/ShellEdit.c,v 2.13 92/06/15 14:57:15 drapeau Exp $ */
  24. /* $Log:    ShellEdit.c,v $
  25.  * Revision 2.13  92/06/15  14:57:15  drapeau
  26.  * Minor change: declared "UpdateHeader()" with function prototypes.
  27.  * 
  28.  * Revision 2.12  92/05/29  12:42:54  drapeau
  29.  * Modified code to track new name of the MAEstro "Selection" structure;
  30.  * it is now named "MAESelection".
  31.  * 
  32.  * Revision 2.11  92/04/30  16:24:00  drapeau
  33.  * Several changes:
  34.  * * Re-formatted and commented small portions of code for cosmetic reasons.
  35.  * * Updated copyright notice.
  36.  * * Added function UpdateHeader() that updates the title bar of 
  37.  *   application to reflect the current status of the current
  38.  *   document (whether modified or not).
  39.  * * Made "Save" silent (i.e., does not always prompt for confirmation,
  40.  *   only when the document is being saved for the first time).
  41.  * 
  42.  * Revision 2.1  92/01/09  18:20:41  drapeau
  43.  * Slight modifications to make code ANSI-compliant.
  44.  * 
  45.  * Revision 2.0  92/01/06  12:57:02  drapeau
  46.  * Changes too numerous to list here, due to lack of proper RCS logging
  47.  * of previous changes.
  48.  * 
  49.  * Revision 1.14  91/07/18  14:45:15  bryant
  50.  * Made it so that quitting from the frame is identical to quitting from the
  51.  * Document window
  52.  * 
  53.  * Revision 1.13  91/07/17  10:08:11  bryant
  54.  * Finished the added protocol items (partial selection using the offset field).
  55.  * Implemented the command line support for -h hostName filename. Upgraded the
  56.  * algorithm so that processes that must be run in the foreground (because of a
  57.  * stop from TTY input or TTY output) can also be timed.
  58.  * Cleaned up the interfacing with OpenPanel.
  59.  * 
  60.  * Revision 1.12  91/07/15  19:46:15  bryant
  61.  * Upgraded the means by which ShellEdit gets the process ID's of its children -- instead
  62.  * of reading in the job data from the tty window, it now uses a popen on ps -jx and
  63.  * scans for any new processes owned by the shell of the tty window. I also improved
  64.  * the quit function so that it would destroy all child processes before quitting.
  65.  * 
  66.  * Revision 1.11  91/07/02  18:21:30  bryant
  67.  * Implemented the OpenPanel and SavePanel functionality. Changed the popen command to ps -jx
  68.  * so that the first two fields would be the PPID and the PID of the process.
  69.  * 
  70.  * Revision 1.10  91/06/28  16:31:58  bryant
  71.  * Forgot to put in the log comment
  72.  *  */
  73.  
  74. /* Still to do:
  75.    change notify response defaults
  76.    comment code
  77. */
  78.  
  79. static char rcsid[] = "$Header: /Source/Media/collab/ShellEdit/RCS/ShellEdit.c,v 2.13 92/06/15 14:57:15 drapeau Exp $";
  80. #include <xview/tty.h>  
  81. #include <xview/xview.h>
  82. #include <xview/font.h>
  83. #include <xview/icon.h>
  84. #include <xview/notice.h>
  85. #include <xview/notify.h>
  86. #include <xview/panel.h>
  87. #include <xview/seln.h>
  88. #include <xview/svrimage.h>
  89. #include <xview/textsw.h>
  90. #include <xview/termsw.h> 
  91. #include <xview/xv_xrect.h>
  92. #include <gdd.h>
  93. #include <X11/Xos.h>
  94. #include <errno.h>
  95. #include <stdio.h>
  96. #include <sys/param.h>
  97. #include <sys/wait.h>
  98. #include <sys/stat.h>
  99. #include <sys/time.h>
  100. #include <sys/types.h>
  101. #include <sys/resource.h>
  102. #include <signal.h>
  103. #include <ctype.h>
  104. #include "ShellEdit_ui.h"
  105. #include <Sender.h>
  106. #include <Receiver.h>
  107. #include <getopt.h>
  108. #include <Browse.h>
  109.  
  110. extern char* realpath(char*, char*);
  111. extern char* strdup(char*);
  112.  
  113. #define MaxLength 255
  114. #define WriteDontExit 0
  115. #define WriteThenExit 1
  116.  
  117. /*
  118.  * Instance XV_KEY_DATA key.  An instance is a set of related
  119.  * user interface objects.  A pointer to an object's instance
  120.  * is stored under this key in every object.  This must be a
  121.  * global variable.
  122.  */
  123. Attr_attribute INSTANCE;
  124.  
  125. ShellEdit_baseWindow_objects *ShellEdit_baseWindow;
  126. ShellEdit_ShellEditInfo_objects    *ShellEdit_ShellEditInfo;
  127. int OpenHandler(), SaveHandler();                /* browser code */
  128. char path[MaxLength];                           /* browser code */
  129. struct itimerval timer[MaxLength], pauseTimer;
  130. char command[MaxLength]; 
  131. char *duration[MaxLength];
  132. char dummy[MaxLength];
  133. char *currentFilename = "untitled";
  134. int editNum, bufferNum = 0, bufferSize = 0, timerIndex = 0, OpenEditFile(), AnElement();
  135. int pauseCount = 0, pauseFreeze = 0, numJobs = 0, shellEditPid, foregroundMode = 0;
  136. int jobPids[MaxLength], resetMode = 0;
  137. int WriteFunction = WriteDontExit;
  138. Notify_client pausePid;
  139. FILE *filep;
  140. unsigned int lastPid = 0;
  141. Notify_value GetPid(), WaitForPs(), IncrementCounter(), CheckForStoppedProcess();
  142. Notify_value QuitNotify();
  143. Xv_font *listFont;
  144. void itoa(), Reverse(), DeselectList(), DeselectAll(), WriteEditListToFile(), LoadEditList();
  145. void DeleteAllLists(), FileAccessError(), Show(), Hide(), KillPids(), Show(), Hide();
  146. void DeleteFromBuffer(), PrintBuffer(), KillProcesses(), CheckOptions();
  147. void OpenDoc();
  148. void SetSelection();
  149. void PerformSelection();
  150. char **GetDoc();
  151. MAESelection*    GetSelection();
  152. void HaltSelection();
  153. void PauseSelection();
  154. void ResumeSelection();
  155. void HideApplication();
  156. void ShowApplication();
  157. IconData *GetAppIcon();
  158. void PerformCommand(Panel_item item, Event* event);
  159. void UpdateHeader (char* documentName, int modified);
  160.  
  161. static char *canonFilename;
  162. Sender* sender;
  163. Receiver* receiver;
  164. Port senderPort;
  165. int ReceiverPortNumber;
  166.  
  167. struct EditPacket {
  168.   char filename[MaxLength];
  169.   int numItems;
  170.   int changes;
  171.   char *command[MaxLength]; 
  172.   char *label[MaxLength]; 
  173.   char *duration[MaxLength];
  174. } *editList[MaxLength];
  175.  
  176.  
  177. void main(argc, argv)
  178.      int        argc;
  179.      char        **argv;
  180. {
  181.   static DispatchTable  DT = 
  182.     {
  183.       OpenDoc,
  184.       GetDoc,
  185.       GetSelection,
  186.       SetSelection,
  187.       PerformSelection,
  188.       NULL,
  189.       NULL,
  190.       NULL,
  191.       NULL,
  192.       NULL,
  193.       NULL,
  194.       HaltSelection,
  195.       PauseSelection,
  196.       ResumeSelection,
  197.       HideApplication,
  198.       ShowApplication,
  199.       GetAppIcon
  200.     }; 
  201.  
  202.   /*
  203.    * Initialize XView.
  204.    */
  205.   xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
  206.   INSTANCE = xv_unique_key();
  207.  
  208.   /*
  209.    * Initialize user interface components.
  210.    */
  211.   ShellEdit_baseWindow = ShellEdit_baseWindow_objects_initialize(NULL, NULL);
  212.   ShellEdit_ShellEditInfo = ShellEdit_ShellEditInfo_objects_initialize(NULL, ShellEdit_baseWindow->baseWindow);
  213.   CreateBrowse(OpenHandler, SaveHandler,
  214.         ShellEdit_baseWindow->baseWindow);       /* browser code */  
  215.   notify_interpose_destroy_func(ShellEdit_baseWindow->baseWindow, QuitNotify);
  216.  
  217.   textsw_insert(ShellEdit_baseWindow->terminal, "unset filec\n", strlen("unset filec\n"));
  218.   textsw_insert(ShellEdit_baseWindow->terminal, "clear\n", strlen("clear\n"));
  219.  
  220.   listFont = (Xv_font *) xv_find(ShellEdit_baseWindow->baseWindow, FONT,
  221.                  FONT_FAMILY, FONT_FAMILY_LUCIDA_FIXEDWIDTH,
  222.                  FONT_STYLE, FONT_STYLE_NORMAL,
  223.                  FONT_SIZE, 12,
  224.                  NULL);
  225.   
  226.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, TRUE, NULL);
  227.   xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, TRUE, NULL);
  228.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, TRUE, NULL);
  229.   xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, "Indefinite", NULL);
  230.   shellEditPid = (unsigned int)getpid();
  231.   
  232.   /* Networking stuff */
  233.   
  234.   senderPort.hostName = "localhost";
  235.   ReceiverPortNumber = AnyPort;
  236.   CheckOptions(argc, argv);
  237.   
  238.   senderPort.portNumber = PortMgrPortNumber;
  239.   sender = NewSender(&senderPort);
  240.   if (!sender)
  241.     {
  242.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  243.             NOTICE_MESSAGE_STRINGS,
  244.             "The PortManager is not running.",
  245.             "Please check that it is running and try again.",
  246.             NULL,
  247.             NOTICE_BUTTON_YES, "OK",
  248.             NULL);
  249.       exit(0);
  250.     }
  251.   receiver = NewReceiver(sender, "ShellEdit", ReceiverPortNumber);
  252.   BuildDispatchTable (&DT);
  253.   canonFilename = (char *) malloc(MaxLength);
  254.   
  255.   (void) notify_enable_rpc_svc (TRUE);
  256.   xv_main_loop(ShellEdit_baseWindow->baseWindow);            /* Turn contol over to xview */
  257.   exit(0);
  258. }
  259.  
  260.  
  261.  
  262. void
  263. OpenDoc(filename)
  264. char **filename;
  265. {
  266.   char temp[MaxLength];
  267.  
  268.   if (strcmp(*filename, currentFilename) != 0 &&            /* Check that filename is not 'untitled' or that... */
  269.       strstr(*filename, "untitled") == NULL                /* ...it hasn't been loaded already */
  270.       && strlen(*filename) > 0)
  271.     {
  272.       currentFilename = (char *)strdup(*filename);
  273.       sprintf(temp, "Shell Edit Document :  \"%s\"", *filename);
  274.       xv_set(ShellEdit_baseWindow->baseWindow, XV_LABEL, temp, NULL);
  275.       OpenEditFile();
  276.     }
  277. }
  278.  
  279.  
  280. void
  281. SetSelection(MAESelection* selection)
  282. {
  283.   char selectedNum[MaxLength];
  284.   char adjustedDuration[MaxLength];
  285.   int offset = (int)((selection->offset)/1000 + .5);
  286.   editNum = (selection->start)+1;
  287.   if (editNum > editList[bufferNum]->numItems)
  288.     {
  289.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  290.             NOTICE_MESSAGE_STRINGS,
  291.             "Selected edit doesn't exist",
  292.             NULL,
  293.             NOTICE_BUTTON_YES, "OK",
  294.             NULL);
  295.       return;
  296.     }
  297.   strcpy(adjustedDuration, editList[bufferNum]->duration[editNum-1]); 
  298.   if (strncmp(adjustedDuration, "Indefinite", 10))
  299.     itoa(atoi(editList[bufferNum]->duration[editNum-1])-offset, adjustedDuration);
  300.   if (editNum != 0)
  301.     {
  302.       DeselectAll();
  303.       itoa(editNum, selectedNum);  
  304.       xv_set(ShellEdit_baseWindow->command, PANEL_VALUE, editList[bufferNum]->command[editNum-1], NULL);  
  305.       if (strncmp(editList[bufferNum]->label[editNum-1], "No Label", 8) != 0)
  306.     xv_set(ShellEdit_baseWindow->label, PANEL_VALUE, editList[bufferNum]->label[editNum-1], NULL);  
  307.       xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, adjustedDuration, NULL);
  308.       xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, selectedNum, NULL);  
  309.       xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, FALSE, NULL);
  310.       xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  311.       xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, FALSE, NULL);  
  312.       xv_set(ShellEdit_baseWindow->scrollList, PANEL_LIST_SELECT, editNum-1, TRUE, NULL); 
  313.     }
  314. }
  315.  
  316. void
  317.   PerformSelection()
  318. {
  319.   if (editNum != 0 && editNum <= editList[bufferNum]->numItems)
  320.     PerformCommand(NULL, NULL);
  321. }
  322.  
  323. char **
  324.   GetDoc(unusedArg)
  325. void *unusedArg;
  326. {
  327.   if (strlen(currentFilename) == 0 || realpath(currentFilename, canonFilename) == NULL) 
  328.     strcpy(canonFilename, "untitled");
  329.   return (&canonFilename);
  330. }
  331.  
  332. MAESelection* GetSelection(void* unusedArg)
  333. {
  334.   static MAESelection select;
  335.   if (editNum >= 1)
  336.     {
  337.       select.offset = 0;
  338.       if (strncmp(editList[bufferNum]->label[editNum-1], "No Label", 8) != 0)
  339.     sprintf(select.label, editList[bufferNum]->label[editNum-1]);
  340.       else
  341.     sprintf(select.label, editList[bufferNum]->command[editNum-1]);
  342.       select.start = editNum - 1;
  343.       select.end = editNum - 1;
  344.       if (strncmp(editList[bufferNum]->duration[editNum-1], "Indefinite", 10))
  345.     select.duration = 1000*atoi(editList[bufferNum]->duration[editNum-1]);   
  346.       else 
  347.     select.duration = 0;
  348.     }
  349.   else 
  350.     {
  351.       select.duration = -1;
  352.       select.start = -1;
  353.       select.end = -1;
  354.       select.offset = 0;
  355.       sprintf(select.label, "No Label");
  356.     }
  357.   return (&select);
  358. }
  359.  
  360. void 
  361.   HaltSelection()
  362. {
  363.   KillProcesses(NULL, NULL);
  364. }
  365.  
  366. void 
  367.   PauseSelection()
  368. {
  369.   pauseFreeze = 0;
  370. /*  printf("tv_sec = %d\n", timer[timerIndex].it_value.tv_sec); */
  371.   pauseTimer.it_value.tv_sec = 1;
  372.   pauseTimer.it_value.tv_usec = 0;
  373.   pauseTimer.it_interval.tv_sec = 1;
  374.   pauseTimer.it_interval.tv_usec = 0;
  375.   notify_set_itimer_func((Notify_client)ShellEdit_baseWindow->baseWindow, IncrementCounter, 
  376.              ITIMER_REAL, &pauseTimer, NULL);
  377.   return;
  378. }
  379.  
  380.  
  381. Notify_value
  382.   IncrementCounter(timerIndex, which)
  383. Notify_client timerIndex;
  384. int which;
  385. {
  386.   if (pauseFreeze == 0)
  387.     pauseCount++;
  388. }
  389.  
  390. void 
  391.   ResumeSelection()
  392. {
  393.   if (++timerIndex > 255)
  394.     timerIndex = 0;
  395.   if (pauseFreeze)    /* occurs if note timer ends before resume is selected */
  396.     {
  397.       timer[timerIndex].it_value.tv_sec = pauseCount;
  398.       pauseCount = 0;
  399.       notify_set_itimer_func((Notify_client)pausePid, WaitForPs, 
  400.              ITIMER_REAL, &timer[timerIndex], NULL);
  401.     }
  402.   else
  403.     pauseFreeze = 1;
  404.   notify_set_itimer_func((Notify_client)ShellEdit_baseWindow->baseWindow, 
  405.              NOTIFY_FUNC_NULL, ITIMER_REAL, NULL, NULL);
  406. }
  407.  
  408. void 
  409.   HideApplication()
  410. {
  411.   xv_set(ShellEdit_baseWindow->baseWindow, FRAME_CLOSED, TRUE, NULL);
  412.   XFlush((Display *)xv_get(ShellEdit_baseWindow->baseWindow, XV_DISPLAY));
  413. }
  414.  
  415. void 
  416.   ShowApplication()
  417. {
  418.   xv_set(ShellEdit_baseWindow->baseWindow, FRAME_CLOSED, FALSE, NULL); 
  419.   XRaiseWindow((Display *)xv_get(ShellEdit_baseWindow->baseWindow, XV_DISPLAY),
  420.            (Window)xv_get(ShellEdit_baseWindow->baseWindow, XV_XID));
  421.   XFlush((Display *)xv_get(ShellEdit_baseWindow->baseWindow, XV_DISPLAY));
  422. }
  423.  
  424. IconData *
  425.   GetAppIcon()
  426. {
  427.   static IconData returnVal;
  428.   static unsigned short baseWindow_bits[] = {
  429. #include "ShellEdit.icon"
  430.         };
  431.   returnVal.iconData = (char *)malloc(sizeof(baseWindow_bits));
  432.   bcopy(baseWindow_bits, returnVal.iconData, sizeof(baseWindow_bits));
  433.   if (returnVal.iconData)
  434.     returnVal.dataLength = sizeof(baseWindow_bits);
  435.   return(&returnVal);
  436. }
  437.  
  438.  
  439.  
  440. Notify_value
  441.   CheckForStoppedProcess(activePid, which)
  442. Notify_client activePid;
  443. int which;
  444. {
  445.   int i=0, pid, ppid, length;
  446.   char line[MaxLength];
  447.   filep = popen("ps jx", "r");
  448.   if (filep != NULL)
  449.     {
  450.       while (fgets(line, MaxLength, filep)!=NULL)
  451.     {
  452.       if (i > 0)               /* skip over the first line that has the labels PPID PID etc */
  453.         {
  454.           sscanf(line, "%u%u", &ppid, &pid);  
  455.           if ((pid==(int)(activePid-1)) && (line[34]=='T' || line[35]=='T' || line[36]=='T' || line[37]=='T'))
  456.         {
  457.           printf("Stopped process %d\n", activePid-1);
  458.           WaitForPs(activePid-1, which);
  459.           resetMode = 1;
  460.           foregroundMode = 1;
  461.           PerformCommand(NULL, NULL);
  462.           textsw_insert(ShellEdit_baseWindow->terminal, "reset\n", strlen("reset\n"));
  463.           /* You might also set a reset flag to send the reset command to the terminal */
  464.         }        
  465.         }
  466.       i++;
  467.     }
  468.       pclose(filep);
  469.     }
  470.   else
  471.     printf("Couldn't do a popen()\n");
  472.   return NOTIFY_DONE;
  473. }
  474.  
  475.  
  476. /*
  477.  * Notify callback function for `PerformCommand'.
  478.  */
  479. void PerformCommand(Panel_item item, Event* event)
  480. {
  481.   int pid, ppid, i;
  482.   char line[MaxLength];
  483.   if (++timerIndex > 255)
  484.     timerIndex = 0;
  485.   duration[timerIndex] = (char *)malloc(MaxLength);
  486.   strcpy(duration[timerIndex], (char *)xv_get(ShellEdit_baseWindow->duration, PANEL_VALUE));
  487.   if (strncmp(duration[timerIndex], "Indefinite", 10) != 0)  
  488.     {
  489.       if (atoi(duration[timerIndex]) < 1)
  490.     {
  491.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  492.             NOTICE_MESSAGE_STRINGS,
  493.             "Duration out of bounds: set to 1 sec.",
  494.             NULL,
  495.             NOTICE_BUTTON_YES, "OK",
  496.             NULL);
  497.       strcpy(duration[timerIndex], "1");
  498.       xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, "1", NULL);
  499.     }
  500.       else if (atoi(duration[timerIndex]) > 10000)
  501.     {
  502.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  503.             NOTICE_MESSAGE_STRINGS,
  504.             "Duration out of bounds: set to 10000 sec.",
  505.             NULL,
  506.             NOTICE_BUTTON_YES, "OK",
  507.             NULL);
  508.       strcpy(duration[timerIndex], "10000");
  509.       xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, "10000", NULL);
  510.     }
  511.     }
  512.   filep = popen("ps jx", "r");
  513.   if (filep != NULL)
  514.     {
  515.       numJobs = 0;
  516.       i = 0;
  517.       while (fgets(line, MaxLength, filep)!=NULL)
  518.     {
  519.       if (i > 0)               /* skip over the first line that has the labels PPID PID etc */
  520.         {
  521.           sscanf(line, "%u%u", &ppid, &pid);   
  522.           if (ppid==(int)xv_get(ShellEdit_baseWindow->terminal, TTY_PID))
  523.         jobPids[numJobs++] = pid;
  524.         }
  525.       i++;
  526.     }
  527.       pclose(filep);
  528.     }
  529.   else
  530.     printf("Couldn't do a popen()\n");
  531.   if (foregroundMode == 0)
  532.     sprintf(command, "%.255s &\n", 
  533.         (char *)xv_get(ShellEdit_baseWindow->command, PANEL_VALUE)); 
  534.   else
  535.     {
  536.       sprintf(command, "%.255s\n", 
  537.           (char *)xv_get(ShellEdit_baseWindow->command, PANEL_VALUE)); 
  538.       foregroundMode = 0;
  539.     }
  540.   textsw_insert(ShellEdit_baseWindow->terminal, command, strlen(command));
  541.   timer[timerIndex].it_value.tv_sec = 1;
  542.   notify_set_itimer_func((Notify_client)timerIndex, GetPid,
  543.                          ITIMER_REAL, &timer[timerIndex], NULL);
  544.   return;
  545. }
  546.  
  547.  
  548. Notify_value
  549.   GetPid(client, which)
  550. Notify_client client;
  551. int which;
  552. {
  553.   int killPid=-1, ppid, pid, i;
  554.   unsigned int length;
  555.   char line[MaxLength];
  556.   filep = popen("ps jx", "r");
  557.   if (filep != NULL)
  558.     {
  559.       i = 0;
  560.       while (fgets(line, MaxLength, filep)!=NULL)
  561.     {
  562.       if (i > 0)              /* skip over the first line that has the labels PPID PID etc */
  563.         {
  564.           sscanf(line, "%u%u", &ppid, &pid);   
  565.           if (ppid==(int)xv_get(ShellEdit_baseWindow->terminal, TTY_PID) &&
  566.           !AnElement(pid, jobPids))
  567.         {
  568.           if (numJobs < 255)
  569.             jobPids[numJobs++] = pid;
  570.           else
  571.             {
  572.               notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  573.                     NOTICE_MESSAGE_STRINGS,
  574.                     "Too many job processes",
  575.                     NULL,
  576.                     NOTICE_BUTTON_YES, "OK",
  577.                     NULL);
  578.               return NOTIFY_DONE;
  579.             }
  580.           killPid = pid;
  581.         }
  582.         }
  583.       i++;
  584.     }
  585.       pclose(filep);
  586.     }
  587.   else
  588.     printf("Couldn't do a popen()\n");
  589.   if (killPid > -1)
  590.     {
  591.       if (++timerIndex > 255)
  592.     timerIndex = 0;
  593.       timer[timerIndex].it_value.tv_sec = 2;
  594.       notify_set_itimer_func((Notify_client)(killPid+1), CheckForStoppedProcess,
  595.              ITIMER_REAL, &timer[timerIndex], NULL);         
  596.       if (strncmp(duration[(int)client], "Indefinite", 10) != 0)
  597.     {
  598.       if ((length = atoi(duration[(int)client]))>1)
  599.         length -= 1;
  600.       if (++timerIndex > 255)
  601.         timerIndex = 0;
  602.       timer[timerIndex].it_value.tv_sec = length;
  603.       pausePid = killPid;
  604.       notify_set_itimer_func((Notify_client)killPid, WaitForPs, 
  605.                  ITIMER_REAL, &timer[timerIndex], NULL);
  606.     }
  607.     }
  608.   return NOTIFY_DONE;
  609. }
  610.  
  611.  
  612. int
  613.   AnElement(pid, jobPids)
  614. int pid;
  615. int jobPids[];
  616. {
  617.   int i;
  618.   for (i=0; i<numJobs; i++)
  619.     {
  620. /*    printf("jobPids[%d]=%d\n", i, jobPids[i]); */
  621.       if (pid == jobPids[i])
  622.     return 1;
  623.     }
  624.   return 0;
  625. }
  626.  
  627.  
  628. Notify_value
  629.   WaitForPs(killPid, which)
  630. Notify_client killPid;
  631. int which;
  632. {
  633.   unsigned int i, pid, ppid, pgid, sid, pidIndex=0, pids[MaxLength][3];
  634.   char line[MaxLength];
  635.   if (pauseCount == 0)
  636.     {
  637.       if (resetMode > 0)
  638.     if (resetMode++ ==2)
  639.       {
  640.         kill((int)killPid, SIGKILL);
  641.         textsw_insert(ShellEdit_baseWindow->terminal, "reset\n", strlen("reset\n"));
  642.         resetMode = 0;
  643.         return NOTIFY_DONE;
  644.       }
  645.       filep = popen("ps jx", "r");
  646.       if (filep != NULL)
  647.     {
  648.       i = 0;
  649.       while (fgets(line, MaxLength, filep)!=NULL)
  650.         {
  651.           if (i > 0)     /* skip over the first line that has the labels PPID PID etc */
  652.         {
  653.           sscanf(line, "%u%u%u%u", &ppid, &pid, &pgid, &sid);
  654.           pids[pidIndex][0] = ppid;
  655.           pids[pidIndex][1] = pid;
  656.           pids[pidIndex][2] = sid;
  657.           pidIndex++;
  658.         }
  659.           i++;
  660.         }
  661.       pclose(filep);
  662.     }
  663.       else
  664.     printf("Couldn't do a popen()\n");
  665.  
  666.       for(i=0; i<pidIndex; i++)
  667.     if ((pids[i][1]==(int)killPid) || (pids[i][0]==1 && pids[i][2]==shellEditPid))        /* kill the killPid process as well as any process that */
  668.       KillPids(pids[i][1], pidIndex, pids, 0);                                            /* is of this session ID and is orphaned                */
  669.     }
  670.   else if (pauseFreeze == 0)
  671.     pauseFreeze = 1;
  672.   else
  673.     {
  674.       if (++timerIndex > 255)
  675.     timerIndex = 0;
  676.       timer[timerIndex].it_value.tv_sec = pauseCount;
  677.       pauseCount = 0;
  678.       notify_set_itimer_func((Notify_client)pausePid, WaitForPs, 
  679.                  ITIMER_REAL, &timer[timerIndex], NULL);
  680.     }
  681.   return NOTIFY_DONE;
  682. }
  683.  
  684. void 
  685.   KillPids(killPid, pidIndex, pids, marker)
  686. unsigned int killPid;
  687. unsigned int pidIndex;
  688. unsigned int pids[][3];
  689. int marker;
  690. {
  691.   unsigned int i;
  692.   char str[MaxLength];
  693. /*   printf("killPid (recursive)=%d\n", killPid);   */
  694.   kill(killPid, SIGKILL);
  695.   for (i=marker; i<pidIndex; i++)
  696.     if (pids[i][0]==killPid)
  697.       KillPids(pids[i][1], pidIndex, pids, i+1);
  698. }
  699.  
  700.  
  701. /*
  702.  * Notify callback function for `killProcesses'.
  703.  */
  704. void
  705.   KillProcesses(item, event)
  706. Panel_item    item;
  707. Event        *event;
  708. {
  709.   char line[MaxLength];
  710.   int i, pid, ppid, pgid, sid;
  711.   filep = popen("ps jx", "r");
  712.   if (filep != NULL)
  713.     {
  714.       i = 0;
  715.       while (fgets(line, MaxLength, filep)!=NULL)
  716.     {
  717.       if (i > 0)               /* skip over the first line that has the labels PPID PID etc */
  718.         {
  719.           sscanf(line, "%u%u%u%u", &ppid, &pid, &pgid, &sid);   
  720.           if (sid==shellEditPid && pid!=shellEditPid && pid!=
  721.           (int)xv_get(ShellEdit_baseWindow->terminal, TTY_PID))
  722.         kill(pid, SIGKILL);
  723.         }
  724.       i++;
  725.     }
  726.       pclose(filep);
  727.     }
  728.   else
  729.     printf("Couldn't do a popen()\n");
  730. }
  731.  
  732.  
  733. /*
  734.  * Notify callback function for `indefinite'.
  735.  */
  736. void
  737.   Indefinite(item, event)
  738. Panel_item    item;
  739. Event        *event;
  740. {
  741.   xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, "Indefinite", NULL);
  742. }
  743.  
  744.  
  745. /*
  746.  * Notify callback function for `scrollList'.
  747.  */
  748. int 
  749.   ScrollList(item, string, client_data, op, event)
  750. Panel_item       item;
  751. char        *string;
  752. Xv_opaque      client_data;
  753. Panel_list_op    op;
  754. Event        *event;
  755. {
  756.   char selectedNum[MaxLength];
  757.   int counter;
  758.   switch(op) 
  759.     {
  760.     case PANEL_LIST_OP_DESELECT:
  761.       DeselectAll();     
  762.       xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, "New Edit", NULL);  
  763.       xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, TRUE, NULL);
  764.       xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, TRUE, NULL);
  765.       xv_set(ShellEdit_baseWindow->label, PANEL_VALUE, "", NULL); 
  766.       break;
  767.       
  768.     case PANEL_LIST_OP_SELECT:
  769.       sscanf(string, "%d", &editNum);
  770.       itoa(editNum, selectedNum);  
  771.       xv_set(ShellEdit_baseWindow->command, PANEL_VALUE, editList[bufferNum]->command[editNum-1], NULL);  
  772.       if (strncmp(editList[bufferNum]->label[editNum-1], "No Label", 8) != 0)
  773.     xv_set(ShellEdit_baseWindow->label, PANEL_VALUE, editList[bufferNum]->label[editNum-1], NULL);  
  774.       xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, editList[bufferNum]->duration[editNum-1], NULL);
  775.       xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, selectedNum, NULL);  
  776.       xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, FALSE, NULL);
  777.       xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  778.       xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, FALSE, NULL);
  779.       break;
  780.       
  781.     case PANEL_LIST_OP_VALIDATE:
  782.     case PANEL_LIST_OP_DELETE:
  783.       break;
  784.       
  785.     default:
  786.       printf("unknown operation\n");
  787.       break;
  788.     }
  789.   return XV_OK;
  790. }
  791.  
  792.  
  793. /*
  794.  * Notify callback function for `filename'.
  795.  */
  796. Panel_setting 
  797.   Filename(item, event)
  798. Panel_item    item;
  799. Event        *event;
  800. {
  801.   OpenEditFile();
  802.   return panel_text_notify(item, event);
  803. }
  804.  
  805. /*
  806.  * Menu handler for `documentMenu (Info)'.
  807.  */
  808. Menu_item
  809.   Info(item, op)
  810. Menu_item    item;
  811. Menu_generate    op;
  812. {
  813.   switch (op) 
  814.     {
  815.     case MENU_NOTIFY:
  816.       Show(&ShellEdit_ShellEditInfo->ShellEditInfo);
  817.       break;
  818.     case MENU_DISPLAY:
  819.     case MENU_DISPLAY_DONE:
  820.     case MENU_NOTIFY_DONE:
  821.       break;
  822.     }
  823.   return item;
  824. }
  825.  
  826. /*
  827.  * Menu handler for `documentMenu (Open)'.
  828.  */
  829. Menu_item
  830.   OpenFile(item, op)
  831. Menu_item    item;
  832. Menu_generate    op;
  833. {
  834.   switch (op) {
  835.   case MENU_NOTIFY:
  836.     Browse(realpath(currentFilename, dummy), 
  837.        BrowseOpen, 0, "#Shell Edit Document#", "ShellEdit"); 
  838.     break;
  839.   case MENU_DISPLAY:
  840.   case MENU_DISPLAY_DONE:
  841.   case MENU_NOTIFY_DONE:
  842.     break;
  843.   }
  844.   return item;
  845. }
  846.  
  847.  
  848. int 
  849.   OpenEditFile()
  850. {
  851.   int i, size, response;
  852.   struct stat stbuf;
  853.   char asciiSize[MaxLength];
  854.   char message[MaxLength]; 
  855.   if (bufferSize > 0)
  856.   {
  857.     if (editList[bufferNum]->changes == 0)
  858.       DeleteFromBuffer();
  859.     for (i=0; i<bufferSize; i++)
  860.     {
  861.       if (realpath(currentFilename, dummy)==NULL)
  862.       {
  863.     Browse(realpath(currentFilename, dummy), 
  864.            BrowseOpen, 0, "#Shell Edit Document#", "ShellEdit"); 
  865.     return -1;
  866.       }
  867.       if (strcmp(realpath(currentFilename, dummy),
  868.          editList[i]->filename)==0)
  869.       {
  870.     bufferNum = i;
  871.     LoadEditList();
  872.     return 1;
  873.       }
  874.     }
  875.   }
  876.   bufferSize++;
  877.   bufferNum = bufferSize-1;
  878.   editList[bufferNum] = (struct EditPacket *)malloc(sizeof(struct EditPacket));
  879.   editList[bufferNum]->changes = 0;
  880.   editList[bufferNum]->numItems = 0;
  881.   if ((int)xv_get(ShellEdit_baseWindow->scrollList, PANEL_LIST_NROWS)!=0)
  882.     DeleteAllLists();
  883.   if (realpath(currentFilename, dummy) != NULL)
  884.     strcpy(editList[bufferNum]->filename, 
  885.        realpath(currentFilename, dummy));
  886.   else
  887.     {
  888.       Browse(realpath(currentFilename, dummy), 
  889.          BrowseOpen, 0, "#Shell Edit Document#", "ShellEdit"); 
  890.       return -1;
  891.     }            
  892.   
  893.   if (strlen(editList[bufferNum]->filename) == 0)
  894.     {
  895.       Browse(realpath(currentFilename, dummy), 
  896.          BrowseOpen, 0, "#Shell Edit Document#", "ShellEdit"); 
  897.       return -1;
  898.     }            
  899.  
  900.   if (CheckFile(&size) == 1)
  901.     {
  902.       itoa(size, asciiSize);
  903.       xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, asciiSize, NULL);
  904.       editList[bufferNum]->numItems = size;
  905.       if (editList[bufferNum]->numItems > 0)
  906.     xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  907.       UpdateHeader(editList[bufferNum]->filename,            /* Display new document title and changed status... */
  908.            editList[bufferNum]->changes);            /* ...on title bar */
  909.     }
  910.   else
  911.     {
  912.       xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, "0", NULL);
  913.       /*   DeleteFromBuffer();   */
  914.       return -1;
  915.     }     
  916.   return 1;
  917. }
  918.  
  919. /*
  920.  * Menu handler for `documentMenu (Save)'.
  921.  */
  922. Menu_item
  923.   Save(item, op)
  924. Menu_item    item;
  925. Menu_generate    op;
  926. {
  927.   switch (op) 
  928.     {
  929.     case MENU_NOTIFY:
  930.       if (strlen(currentFilename) == 0 ||
  931.       strstr(currentFilename, "untitled") != NULL) 
  932.     Browse(realpath(currentFilename, dummy), 
  933.            BrowseSave, 0, "#Shell Edit Document#", "ShellEdit"); 
  934.       else
  935.     Browse(realpath(currentFilename, dummy), 
  936.            BrowseCheckSave, 0, "#Shell Edit Document#", "ShellEdit"); 
  937.       break;
  938.     case MENU_DISPLAY:
  939.     case MENU_DISPLAY_DONE:
  940.     case MENU_NOTIFY_DONE:
  941.       break;
  942.     }
  943.   return item;
  944. }                                    /* end function Save */
  945.  
  946.  
  947.  
  948. /*
  949.  * Notify callback function for `SaveAs'.
  950.  */
  951. Panel_setting
  952.   SaveFile(item, event)
  953. Panel_item    item;
  954. Event        *event;
  955. {
  956.   FILE *fp;
  957.   char fileType[MaxLength];
  958.   char dummy[MaxLength];
  959.   int response;
  960.   struct stat stbuf;
  961.   char message[MaxLength];
  962.   if (editList[bufferNum] == NULL)
  963.   {
  964.     editList[bufferNum] = (struct EditPacket *)malloc(sizeof(struct EditPacket));
  965.     editList[bufferNum]->numItems = 0;
  966.     bufferSize++;
  967.   }
  968.   strcpy(editList[bufferNum]->filename, currentFilename);
  969.   if (strlen(editList[bufferNum]->filename)<1)
  970.   {
  971.     response = notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  972.                  NOTICE_MESSAGE_STRINGS,
  973.                  "Filename not specified.",
  974.                  NULL,
  975.                  NOTICE_BUTTON_YES, "OK",
  976.                  NULL);
  977.     return item;
  978.   }
  979.   if (stat(editList[bufferNum]->filename, &stbuf)!=-1) 
  980.   {
  981.     fp = fopen (editList[bufferNum]->filename, "r");                    
  982.     fscanf (fp, "#%s Edit Document#\n", fileType);            
  983.     if (strcmp(fileType, "Shell"))                
  984.     {                                
  985.       sprintf (message, "'%s' exists and is not a Shell Edit list.\n", editList[bufferNum]->filename);
  986.       response = notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  987.                    NOTICE_MESSAGE_STRINGS,
  988.                    message,
  989.                    "Go ahead and overwrite its contents?",
  990.                    NULL,
  991.                    NOTICE_BUTTON_NO, "Yes",
  992.                    NOTICE_BUTTON_YES, "Cancel",
  993.                    NULL);
  994.       if (response == NOTICE_YES)
  995.       {
  996.     fclose (fp);                               
  997.     return item;
  998.       }
  999.     }                                    /* end if part of if (strcmp... */
  1000.     fclose (fp);                               
  1001.   }                                    /* end if (stat... */
  1002.   WriteEditListToFile(bufferNum);
  1003.   return item;
  1004. }                                    /* end function SaveFile */
  1005.  
  1006.  
  1007. /*
  1008.  * Menu handler for `documentMenu (Save As)'.
  1009.  */
  1010. Menu_item
  1011. SaveAs(item, op)
  1012.   Menu_item    item;
  1013.   Menu_generate    op;
  1014. {
  1015.   switch (op) 
  1016.     {
  1017.     case MENU_NOTIFY:
  1018.       Browse(realpath(currentFilename, dummy), 
  1019.          BrowseSave, 0, "#Shell Edit Document#", "ShellEdit"); 
  1020.       break;
  1021.     case MENU_DISPLAY:
  1022.     case MENU_DISPLAY_DONE:
  1023.     case MENU_NOTIFY_DONE:
  1024.       break;
  1025.     }
  1026.   return item;
  1027. }
  1028.  
  1029. /*
  1030.  * Menu handler for `documentMenu (Quit)'.
  1031.  */
  1032. Menu_item
  1033.   QuitShellEdit(item, op)
  1034. Menu_item    item;
  1035. Menu_generate    op;
  1036. {
  1037.   switch (op) 
  1038.     {
  1039.     case MENU_NOTIFY:
  1040.       xv_destroy_safe(ShellEdit_baseWindow->baseWindow);
  1041.       break;
  1042.     case MENU_DISPLAY:
  1043.     case MENU_DISPLAY_DONE:
  1044.     case MENU_NOTIFY_DONE:
  1045.       break;
  1046.     }
  1047.   return item;
  1048. }
  1049.  
  1050.  
  1051. /*
  1052.    This is the interpose function for the frame destroy procedure.  It
  1053.    is called when the quit button is pressed, or when the frame's "Quit"
  1054.    menu selection is chosen.
  1055.    The frame destroying process happens in two phases (meaning this
  1056.    function will be called twice).  The first time it is called, status =
  1057.    DESTROY_CHECKING (this is done automatically by XView).  At this
  1058.    point, the interpose function can choose to veto the destruction, or
  1059.    let it proceed to phase two, where the actual destruction occurs.
  1060. */
  1061. Notify_value 
  1062.   QuitNotify(client, status)
  1063. Notify_client client;
  1064. Destroy_status status;
  1065. {
  1066.   int response, i;
  1067.   char message[MaxLength];
  1068.   /* First phase:  Check to see if we really want to destroy the frame */
  1069.   if (status == DESTROY_CHECKING)
  1070.     {
  1071.       for (i=0; i<bufferSize; i++)
  1072.     if (editList[i]->changes)
  1073.       {
  1074.         sprintf(message, "Save changes to '%s' ?", editList[i]->filename);
  1075.         response = notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  1076.                      NOTICE_MESSAGE_STRINGS,
  1077.                      message,
  1078.                      NULL,
  1079.                      NOTICE_BUTTON_YES, "Yes",
  1080.                      NOTICE_BUTTON_NO,  "No",
  1081.                      NOTICE_BUTTON, "Cancel", 100,
  1082.                      NULL);
  1083.         if (response == 100)
  1084.           return notify_veto_destroy(client);
  1085.         if (response == NOTICE_YES)
  1086.           {
  1087.         WriteEditListToFile(i);
  1088.         notify_veto_destroy(client);
  1089.           }
  1090.       }
  1091.       WriteFunction = WriteThenExit;
  1092.     }
  1093.   else /* Second phase:  Proceed to destroy */
  1094.     {
  1095.       KillProcesses(NULL, NULL);
  1096.       SenderDisconnectFromPortMgr(sender, &(receiver->receivePort));
  1097.       return notify_next_destroy_func(client, status);
  1098.     }
  1099.   return NOTIFY_DONE;
  1100. }
  1101.  
  1102. int 
  1103.   CheckFile(size)
  1104. int             *size;
  1105. {
  1106.   int counter, temp;
  1107.   int response;
  1108.   char message[MaxLength];
  1109.   char line[MaxLength];
  1110.   char fileType[MaxLength];
  1111.   char workingDirectory[MaxLength];
  1112.   char *formatString[MaxLength];
  1113.   char *tempCommand, *tempLabel, *tempDuration, *desiredWorkingDirectory;
  1114.   FILE *fp;
  1115.   fp = (FILE *)fopen(editList[bufferNum]->filename, "r");
  1116.   fscanf (fp, "#%s Edit Document#\n", fileType);            
  1117.   if (strcmp(fileType, "Shell"))                
  1118.     {                                
  1119.       sprintf (message, "'%s' is not a Shell Edit list\n", editList[bufferNum]->filename);
  1120.       response = notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  1121.                    NOTICE_MESSAGE_STRINGS,
  1122.                    message,
  1123.                    NULL,
  1124.                    NOTICE_BUTTON_YES, "OK",
  1125.                    NULL);
  1126.       fclose(fp);
  1127.       return -1;
  1128.     }
  1129.   fgets(line,512,fp);    
  1130.   desiredWorkingDirectory = &line[20];                        
  1131.   desiredWorkingDirectory[strlen(desiredWorkingDirectory)-1] = '\0';            
  1132.   if (getwd(workingDirectory))
  1133.     {
  1134.       if (strcmp(workingDirectory, desiredWorkingDirectory) && 
  1135.       strncmp(desiredWorkingDirectory, "Unspecified", 11))
  1136.     {
  1137.       sprintf(command, "cd %s\n", desiredWorkingDirectory);
  1138.       textsw_insert(ShellEdit_baseWindow->terminal, command, strlen(command));
  1139.     }
  1140.     }
  1141.   else if (strncmp(desiredWorkingDirectory, "Unspecified", 11))
  1142.     { 
  1143.       sprintf(command, "cd %s\n", desiredWorkingDirectory);
  1144.       textsw_insert(ShellEdit_baseWindow->terminal, command, strlen(command));
  1145.     }
  1146.   fscanf (fp, "#Number of Edits:\t%d\n", &temp);        
  1147.   *size = temp;
  1148.   for (counter=0; counter<temp; counter++)
  1149.     {
  1150.       fgets(line,512,fp);      /* skip the #Edit Number: */                              
  1151.       fgets(line,512,fp);                                    
  1152.       tempCommand = &line[10];                        
  1153.       tempCommand[strlen(tempCommand)-1] = '\0';            
  1154.       editList[bufferNum]->command[counter] = (char *)strdup(tempCommand);
  1155.       fgets(line,512,fp);                                    
  1156.       tempLabel = &line[9];                        
  1157.       tempLabel[strlen(tempLabel)-1] = '\0';            
  1158.       editList[bufferNum]->label[counter] = (char *)strdup(tempLabel);
  1159.       fgets(line,512,fp);                                    
  1160.       tempDuration = &line[11];                    
  1161.       tempDuration[strlen(tempDuration)-1] = '\0';            
  1162.       editList[bufferNum]->duration[counter] = (char *)strdup(tempDuration);
  1163.       formatString[counter] = (char *)malloc(MaxLength);
  1164.       if (strncmp(editList[bufferNum]->label[counter], "No Label", 8) != 0)
  1165.     sprintf(formatString[counter], "%3d   %-25.25s  %-10s", 
  1166.         counter+1, editList[bufferNum]->label[counter], editList[bufferNum]->duration[counter]);
  1167.       else
  1168.     sprintf(formatString[counter], "%3d   %-25.25s  %-10s", 
  1169.         counter+1, editList[bufferNum]->command[counter], editList[bufferNum]->duration[counter]);
  1170.       fgets(line,512,fp);                                    
  1171.     }
  1172.   fclose(fp);
  1173.  
  1174.   xv_set(ShellEdit_baseWindow->scrollList, 
  1175.      XV_SHOW, FALSE, NULL); 
  1176.   for (counter=0; counter<temp; counter++)
  1177.     xv_set(ShellEdit_baseWindow->scrollList, 
  1178.        PANEL_LIST_INSERT, counter, 
  1179.        XV_SHOW, FALSE, 
  1180.        PANEL_LIST_STRING, counter, formatString[counter],
  1181.        PANEL_LIST_FONT, counter, listFont,
  1182.        NULL);
  1183.   xv_set(ShellEdit_baseWindow->scrollList, 
  1184.      XV_SHOW, TRUE, NULL);   
  1185.   return 1;
  1186. }
  1187.  
  1188.  
  1189. void 
  1190.   WriteEditListToFile(i)
  1191. int i;
  1192. {
  1193.   FILE *fp;
  1194.   char workingDirectory[MaxLength];
  1195.   int counter;
  1196.   char errorMessage[MaxLength];
  1197.   DeselectAll();
  1198.   if (strstr(editList[i]->filename, "untitled") != NULL || strlen(editList[i]->filename) == 0) 
  1199.     {
  1200.       bufferNum = i;
  1201.       Browse(realpath(editList[i]->filename, dummy), 
  1202.          BrowseSave, 0, "#Shell Edit Document#", "ShellEdit"); 
  1203.       return;
  1204.     }
  1205.   if ((fp = fopen(editList[i]->filename, "w")) == (FILE *)NULL)
  1206.     {
  1207.       sprintf(errorMessage, "Can't open '%s' for writing.", editList[i]->filename);
  1208.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  1209.             NOTICE_MESSAGE_STRINGS,
  1210.             errorMessage,
  1211.             NULL,
  1212.             NOTICE_BUTTON_YES, "OK",
  1213.             NULL);
  1214.       fclose (fp);                               
  1215.       return;
  1216.     }
  1217.   fprintf (fp, "#Shell Edit Document#\n");
  1218.   if (getwd(workingDirectory))    
  1219.     fprintf (fp, "#Working Directory:\t%s\n", workingDirectory);
  1220.   else
  1221.     fprintf (fp, "#Working Directory\t%s\n", "Unspecified");
  1222.   fprintf (fp, "#Number of Edits:\t%d\n\n", editList[i]->numItems);           
  1223.   for (counter = 0; counter < editList[i]->numItems; counter ++)               
  1224.     {                                 
  1225.       fprintf(fp, "#Edit Number:\t%d\n#Command:\t%s\n#Label:\t\t%s\n#Duration:\t%s\n\n",       
  1226.           counter+1, editList[i]->command[counter], editList[i]->label[counter], 
  1227.           editList[i]->duration[counter]);
  1228.     }
  1229.   fclose (fp);                               
  1230.   editList[i]->changes = 0;
  1231.   UpdateHeader(editList[i]->filename,                    /* Display new document title and changed status... */
  1232.            editList[i]->changes);                    /* ...on title bar */
  1233.   if (WriteFunction == WriteThenExit)
  1234.     xv_destroy_safe(ShellEdit_baseWindow->baseWindow);
  1235.   return;
  1236. }
  1237.  
  1238.  
  1239. /*
  1240.  * Notify callback function for `add'.
  1241.  */
  1242. void 
  1243.   Add(item, event)
  1244. Panel_item    item;
  1245. Event        *event;
  1246. {
  1247.   char formatString[MaxLength];
  1248.   char *tempCommand, *tempLabel, *tempDuration;
  1249.   char selectedNum[MaxLength];
  1250.   int lastEdit;
  1251.   tempCommand = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->command, PANEL_VALUE));
  1252.   tempLabel = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->label, PANEL_VALUE));
  1253.   if (strlen(tempLabel) < 1)
  1254.     tempLabel = (char *)strdup("No Label");
  1255.   tempDuration = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->duration, PANEL_VALUE)); 
  1256.   if (editList[bufferNum] == NULL)
  1257.     {
  1258.       editList[bufferNum] = (struct EditPacket *)malloc(sizeof(struct EditPacket));
  1259.       editList[bufferNum]->numItems = 0;
  1260.       bufferSize++;
  1261.       sprintf(editList[bufferNum]->filename, "untitled.%d", bufferSize);
  1262.     }
  1263.   lastEdit = ++editList[bufferNum]->numItems;
  1264.   DeselectAll();
  1265.   if (strncmp(tempLabel, "No Label", 8) != 0)
  1266.     sprintf(formatString, "%3d   %-25.25s  %-10s", lastEdit, tempLabel, tempDuration);
  1267.   else
  1268.     sprintf(formatString, "%3d   %-25.25s  %-10s", lastEdit, tempCommand, tempDuration);
  1269.   xv_set(ShellEdit_baseWindow->scrollList, 
  1270.      PANEL_LIST_INSERT, lastEdit-1, 
  1271.      PANEL_LIST_STRING, lastEdit-1, formatString, 
  1272.      PANEL_LIST_FONT, lastEdit-1, listFont, 
  1273.      NULL);  
  1274.   editNum = lastEdit;
  1275.   editList[bufferNum]->command[editNum-1] = (char *)strdup(tempCommand);
  1276.   editList[bufferNum]->label[editNum-1] = (char *)strdup(tempLabel);
  1277.   editList[bufferNum]->duration[editNum-1] = (char *)strdup(tempDuration);
  1278.   itoa(editNum, selectedNum);
  1279.   xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, selectedNum, NULL);
  1280.   xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, selectedNum, NULL);
  1281.   xv_set(ShellEdit_baseWindow->scrollList, 
  1282.      PANEL_LIST_SELECT, lastEdit-1, TRUE,
  1283.      NULL);  
  1284.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, FALSE, NULL);
  1285.   xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  1286.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, FALSE, NULL);
  1287.   editList[bufferNum]->changes = 1;
  1288.   UpdateHeader(editList[bufferNum]->filename,                /* Display new document title and changed status... */
  1289.            editList[bufferNum]->changes);                /* ...on title bar */
  1290. }                                    /* end function Add */
  1291.  
  1292.  
  1293. /*
  1294.  * Notify callback function for `modify'.
  1295.  */
  1296. void 
  1297.   Modify(item, event)
  1298. Panel_item    item;
  1299. Event        *event;
  1300. {
  1301.   char formatString[MaxLength];
  1302.   char *tempCommand, *tempDuration, *tempLabel;
  1303.   char selectedNum[MaxLength];
  1304.   tempCommand = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->command, PANEL_VALUE));
  1305.   tempLabel = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->label, PANEL_VALUE));
  1306.   if (strlen(tempLabel) < 1)
  1307.     tempLabel = (char *)strdup("No Label");
  1308.   tempDuration = (char *)strdup((char *)xv_get(ShellEdit_baseWindow->duration, PANEL_VALUE)); 
  1309.   if (strncmp(tempLabel, "No Label", 8) != 0)
  1310.     sprintf(formatString, "%3d   %-25.25s  %-10s", editNum, tempLabel, tempDuration);
  1311.   else
  1312.     sprintf(formatString, "%3d   %-25.25s  %-10s", editNum, tempCommand, tempDuration);
  1313.   xv_set(ShellEdit_baseWindow->scrollList,  
  1314.      PANEL_LIST_STRING, editNum-1, formatString, 
  1315.      PANEL_LIST_SELECT, editNum-1, TRUE,
  1316.      PANEL_LIST_FONT, editNum-1, listFont, 
  1317.      NULL);
  1318.   editList[bufferNum]->command[editNum-1] = (char *)strdup(tempCommand); 
  1319.   editList[bufferNum]->label[editNum-1] = (char *)strdup(tempLabel);
  1320.   editList[bufferNum]->duration[editNum-1] = (char *)strdup(tempDuration);
  1321.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, FALSE, NULL);
  1322.   xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  1323.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, FALSE, NULL);
  1324.   editList[bufferNum]->changes = 1;
  1325.   UpdateHeader(editList[bufferNum]->filename,                /* Display new document title and changed status... */
  1326.            editList[bufferNum]->changes);                /* ...on title bar */
  1327. }                                    /* end function Modify */
  1328.  
  1329.  
  1330. /*
  1331.  * Notify callback function for `delete'.
  1332.  */
  1333. void 
  1334.   Delete(item, event)
  1335. Panel_item    item;
  1336. Event        *event;
  1337. {
  1338.   int lastEdit, counter;
  1339.   char formatString[MaxLength];
  1340.   char newTot[MaxLength];
  1341.   lastEdit = editList[bufferNum]->numItems--;
  1342.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, FALSE, NULL); 
  1343.   DeselectList();   
  1344.   if (editNum > 1)
  1345.     xv_set(ShellEdit_baseWindow->scrollList, PANEL_LIST_SELECT, editNum-2, TRUE, NULL);
  1346.   xv_set(ShellEdit_baseWindow->scrollList, PANEL_LIST_DELETE, lastEdit - 1, NULL);
  1347.   for (counter = editNum-1; counter < lastEdit-1; counter++)
  1348.     { 
  1349.       editList[bufferNum]->command[counter] = editList[bufferNum]->command[counter+1];
  1350.       editList[bufferNum]->label[counter] = editList[bufferNum]->label[counter+1];
  1351.       editList[bufferNum]->duration[counter] = editList[bufferNum]->duration[counter+1];
  1352.       if (strncmp(editList[bufferNum]->label[counter], "No Label", 8) != 0)
  1353.     sprintf(formatString, "%3d   %-25.25s  %-10s", 
  1354.         counter+1, editList[bufferNum]->label[counter], editList[bufferNum]->duration[counter]);
  1355.       else
  1356.     sprintf(formatString, "%3d   %-25.25s  %-10s", 
  1357.         counter+1, editList[bufferNum]->command[counter], editList[bufferNum]->duration[counter]);
  1358.       xv_set(ShellEdit_baseWindow->scrollList,  
  1359.          PANEL_LIST_STRING, counter, formatString, 
  1360.          PANEL_LIST_FONT, counter, listFont, 
  1361.          NULL);    
  1362.     }
  1363.   DeselectAll();
  1364.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, TRUE, NULL);   
  1365.   itoa(lastEdit-1, newTot);
  1366.   xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, newTot, NULL);
  1367.   xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, "New Edit", NULL); 
  1368.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, TRUE, NULL);    
  1369.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, TRUE, NULL);    
  1370.   if (editList[bufferNum]->numItems == 0)    
  1371.     xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, TRUE, NULL);
  1372.   editList[bufferNum]->changes = 1;
  1373.   UpdateHeader(editList[bufferNum]->filename,                /* Display new document title and changed status... */
  1374.            editList[bufferNum]->changes);                /* ...on title bar */
  1375. }                                    /* end function Delete */
  1376.  
  1377.  
  1378. /*
  1379.  * Notify callback function for `deleteAll'.
  1380.  */ 
  1381. void 
  1382.   DeleteAll(item, event)
  1383. Panel_item    item;
  1384. Event        *event;
  1385. {
  1386.   DeleteAllLists();
  1387.   editList[bufferNum]->numItems = 0;
  1388.   editList[bufferNum]->changes = 1;
  1389.   UpdateHeader(editList[bufferNum]->filename,                /* Display new document title and changed status... */
  1390.            editList[bufferNum]->changes);                /* ...on title bar */
  1391. }                                    /* end function DeleteAll */
  1392.  
  1393.  
  1394. void 
  1395.   LoadEditList()
  1396. {
  1397.   int counter;
  1398.   char formatString[MaxLength];
  1399.   char newTot[MaxLength];
  1400.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, FALSE, NULL); 
  1401.   DeleteAllLists();
  1402.   for (counter = 0; counter < editList[bufferNum]->numItems; counter++)
  1403.     { 
  1404.       if (strncmp(editList[bufferNum]->label[counter], "No Label", 8) != 0)
  1405.     sprintf(formatString, "%3d   %-25.25s  %-10s", 
  1406.         counter+1, editList[bufferNum]->label[counter], editList[bufferNum]->duration[counter]);
  1407.       else
  1408.     sprintf(formatString, "%3d   %-25.25s  %-10s", 
  1409.         counter+1, editList[bufferNum]->command[counter], editList[bufferNum]->duration[counter]);
  1410.       xv_set(ShellEdit_baseWindow->scrollList,  
  1411.          PANEL_LIST_STRING, counter, formatString, 
  1412.          PANEL_LIST_FONT, counter, listFont, 
  1413.          NULL);    
  1414.     }
  1415.   DeselectAll();
  1416.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, TRUE, NULL);   
  1417.   itoa(editList[bufferNum]->numItems, newTot);
  1418.   xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, newTot, NULL);
  1419.   xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, "New Edit", NULL); 
  1420.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, TRUE, NULL);    
  1421.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, TRUE, NULL);    
  1422.   if (editList[bufferNum]->numItems == 0)    
  1423.     xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, TRUE, NULL);
  1424.   else
  1425.     xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, FALSE, NULL);
  1426. }
  1427.  
  1428. void 
  1429.   DeleteFromBuffer()
  1430. {
  1431.   int i;
  1432.   free(editList[bufferNum]);
  1433.   for (i=bufferNum; i<bufferSize-1; i++)
  1434.     {
  1435.       editList[i] = editList[i+1];
  1436.     }
  1437.   bufferSize--;
  1438.   DeleteAllLists();
  1439. }
  1440.  
  1441. void 
  1442.   PrintBuffer()
  1443. {
  1444.   int i;
  1445.   for (i=0; i<bufferSize; i++)
  1446.     {
  1447.       printf("%d  %s\n", i, editList[i]->filename);
  1448.     }
  1449. }
  1450.  
  1451. void 
  1452.   DeleteAllLists()
  1453. {
  1454.   int i, nrows;
  1455.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, FALSE, NULL);
  1456.   nrows = (int)xv_get(ShellEdit_baseWindow->scrollList, PANEL_LIST_NROWS);
  1457.   for (i = 0; i < nrows; i++)
  1458.     xv_set(ShellEdit_baseWindow->scrollList, PANEL_LIST_DELETE, 0, NULL);
  1459.   xv_set(ShellEdit_baseWindow->scrollList, XV_SHOW, TRUE, NULL);   
  1460.   xv_set(ShellEdit_baseWindow->numOfEdits, PANEL_LABEL_STRING, "0", NULL);
  1461.   xv_set(ShellEdit_baseWindow->currentSelectionField, PANEL_LABEL_STRING, "New Edit", NULL); 
  1462.   xv_set(ShellEdit_baseWindow->command, PANEL_VALUE, "", NULL); 
  1463.   xv_set(ShellEdit_baseWindow->label, PANEL_VALUE, "", NULL); 
  1464.   xv_set(ShellEdit_baseWindow->duration, PANEL_VALUE, "", NULL); 
  1465.   xv_set(ShellEdit_baseWindow->delete, PANEL_INACTIVE, TRUE, NULL);
  1466.   xv_set(ShellEdit_baseWindow->modify, PANEL_INACTIVE, TRUE, NULL);
  1467.   xv_set(ShellEdit_baseWindow->deleteAll, PANEL_INACTIVE, TRUE, NULL);
  1468. }
  1469.  
  1470.  
  1471. void 
  1472.   DeselectList()
  1473. {
  1474.   xv_set (ShellEdit_baseWindow->scrollList, PANEL_LIST_SELECT, editNum-1, FALSE, NULL);
  1475. }
  1476.  
  1477.  
  1478. void 
  1479.   DeselectAll()
  1480. {
  1481.   int counter = 0;
  1482.   while (counter < editList[bufferNum]->numItems)
  1483.     {
  1484.       if ((int)xv_get(ShellEdit_baseWindow->scrollList, PANEL_LIST_SELECTED, counter))
  1485.       xv_set(ShellEdit_baseWindow->scrollList, PANEL_LIST_SELECT, counter, FALSE, NULL);
  1486.       counter++;
  1487.     }
  1488. }
  1489.  
  1490.  
  1491. void 
  1492.   itoa(num, string)
  1493. int num;
  1494. char string[];
  1495. {
  1496.   int i=0, sign;
  1497.   if ((sign=num) < 0) num = -num;
  1498.   do 
  1499.     string[i++] = num%10 + '0';
  1500.   while ((num /= 10) > 0);
  1501.   if (sign < 0) string[i++] = '-';
  1502.   string[i] = '\0';
  1503.   Reverse(string);
  1504. }
  1505.  
  1506. void 
  1507.   Reverse(string)
  1508. char string[];
  1509. {
  1510.   int c, i, j;
  1511.   for (i=0, j=strlen(string)-1; i<j; i++, j--)
  1512.     {
  1513.       c = string[i];
  1514.       string[i] = string[j];
  1515.       string[j] = c;
  1516.     }
  1517. }
  1518.  
  1519. int                                            /* browser code */
  1520.   OpenHandler(char *proposedPath, int id)
  1521. {
  1522.   char temp[MaxLength];
  1523.   currentFilename = (char *)strdup(proposedPath);
  1524.   if (OpenEditFile() == 1)
  1525.     {
  1526.       sprintf(temp, "Shell Edit Document :  \"%s\"", currentFilename);
  1527.       xv_set(ShellEdit_baseWindow->baseWindow, XV_LABEL, temp, NULL);
  1528.       return 0;
  1529.     }
  1530.   else
  1531.     return 1;
  1532. }
  1533.  
  1534. int                                            /* browser code */
  1535.   SaveHandler(char *proposedPath, int id)
  1536. {
  1537.   char temp[MaxLength];
  1538.   currentFilename = (char *)strdup(proposedPath);
  1539.   sprintf(temp, "Shell Edit Document :  \"%s\"", currentFilename);
  1540.   xv_set(ShellEdit_baseWindow->baseWindow, XV_LABEL, temp, NULL);
  1541.   if (strstr(proposedPath, "untitled") == NULL && strlen(proposedPath) > 0) 
  1542.     {
  1543.       SaveFile(NULL, NULL);
  1544.       return 0;
  1545.     }
  1546.   else
  1547.     {
  1548.       sprintf(temp, "Can't save to %s.\n", proposedPath);
  1549.       notice_prompt(ShellEdit_baseWindow->baseWindow, NULL,
  1550.             NOTICE_MESSAGE_STRINGS,
  1551.             temp,
  1552.             "Try saving to a different name.",
  1553.             NULL,
  1554.             NOTICE_BUTTON_YES, "OK",
  1555.             NULL);
  1556.       return -1;
  1557.     }
  1558. }
  1559.  
  1560.  
  1561. /* 
  1562.  * This function parses the command line and retrieves all the known options and their arguments.
  1563.  * Currently, the two options are hostname and portnumber.
  1564.  * After parsing the options, the variable optind will point to the start of those non-option arguments.  In this case, it will be the filename to be
  1565.  * loaded.  At present, only one filename will be handled.  So if there are multiple filenames typed, the last one will be loaded.
  1566.  */
  1567. void CheckOptions(argc, argv)
  1568.      int     argc;
  1569.      char     **argv;
  1570. {
  1571.   int optionChar;  
  1572.   int option_index = 0;
  1573.   static struct option long_options[] =
  1574.   {
  1575.     {"hostname", 1, 0, 'h'},        
  1576.  
  1577.     {"portnumber", 1, 0, 'p'},
  1578.     {0, 0, 0, 0}
  1579.   };
  1580.  
  1581.   while (1)                                /* Start parsing all known options */
  1582.   {
  1583.     optionChar = getopt_long_only (argc, argv, "h:p:",
  1584.                   long_options, &option_index);
  1585.     if (optionChar == EOF)                        /* Done with all known options */
  1586.     {
  1587.       break;
  1588.     }
  1589.     switch (optionChar)
  1590.     {
  1591.      case 'h':
  1592.       if (optarg) 
  1593.       {
  1594.     senderPort.hostName = strdup(optarg);
  1595.       }
  1596.       break;
  1597.      case 'p':
  1598.       if (optarg) 
  1599.       {
  1600.     ReceiverPortNumber = atoi(optarg);
  1601.       }
  1602.       break;
  1603.      default:
  1604.       break;
  1605.     }
  1606.   }
  1607.   if (optind < argc)                            /* Check if a filename has been specified */
  1608.     Browse(argv[optind], BrowseCheckOpen, 0, "#Shell Edit Document#", "ShellEdit"); 
  1609. }
  1610.  
  1611. void 
  1612.   Show(popup)
  1613. Frame *popup;
  1614. {
  1615.   if ((int)xv_get(*popup,FRAME_CMD_PUSHPIN_IN) == FALSE)           
  1616.     xv_set (*popup, FRAME_CMD_PUSHPIN_IN, TRUE, NULL);           
  1617.   if ((int)xv_get(*popup, XV_SHOW) == FALSE)               
  1618.     xv_set (*popup, XV_SHOW, TRUE, NULL);               
  1619. }                                   
  1620.  
  1621. void 
  1622.   Hide(popup)
  1623. Frame *popup;
  1624. {
  1625.   if ((int)xv_get(*popup,FRAME_CMD_PUSHPIN_IN) == TRUE)           
  1626.     xv_set (*popup, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);           
  1627.   if ((int)xv_get(*popup, XV_SHOW) == TRUE)               
  1628.     xv_set (*popup,XV_SHOW, FALSE, NULL);               
  1629. }      
  1630.  
  1631.  
  1632. /*
  1633.  * Notify callback function for `info'.
  1634.  */
  1635. void
  1636.   HideInfo(item, event)
  1637. Panel_item    item;
  1638. Event        *event;
  1639. {
  1640.   Hide(&ShellEdit_ShellEditInfo->ShellEditInfo);
  1641. }
  1642.  
  1643.  
  1644.  
  1645. void UpdateHeader (char* documentName, int modified)
  1646. {
  1647.   char    label[MAXPATHLEN+32];
  1648.   
  1649.   if (modified == 1)
  1650.   {
  1651.     sprintf(label, "Shell Edit Document : \"%s\" (modified)",
  1652.         documentName);
  1653.   }
  1654.   else
  1655.   {
  1656.     sprintf(label, "Shell Edit Document : \"%s\" ", documentName);
  1657.   }
  1658.   xv_set(ShellEdit_baseWindow->baseWindow,                /* Print the new label string on the title bar */
  1659.      XV_LABEL, label, NULL);
  1660. }                                    /* end function UpdateHeader */
  1661.