home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume8 / xdbx / part05 / command.c next >
Encoding:
C/C++ Source or Header  |  1990-08-28  |  18.3 KB  |  703 lines

  1. /*****************************************************************************
  2.  *
  3.  *  xdbx - X Window System interface to the dbx debugger
  4.  *
  5.  *  Copyright 1989 The University of Texas at Austin
  6.  *  Copyright 1990 Microelectronics and Computer Technology Corporation
  7.  *
  8.  *  Permission to use, copy, modify, and distribute this software and its
  9.  *  documentation for any purpose and without fee is hereby granted,
  10.  *  provided that the above copyright notice appear in all copies and that
  11.  *  both that copyright notice and this permission notice appear in
  12.  *  supporting documentation, and that the name of The University of Texas
  13.  *  and Microelectronics and Computer Technology Corporation (MCC) not be 
  14.  *  used in advertising or publicity pertaining to distribution of
  15.  *  the software without specific, written prior permission.  The
  16.  *  University of Texas and MCC makes no representations about the 
  17.  *  suitability of this software for any purpose.  It is provided "as is" 
  18.  *  without express or implied warranty.
  19.  *
  20.  *  THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO
  21.  *  THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22.  *  FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR
  23.  *  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  24.  *  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  25.  *  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  26.  *  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  27.  *
  28.  *  Author:      Po Cheung
  29.  *  Created:       March 10, 1989
  30.  *
  31.  *****************************************************************************/
  32.  
  33. /*  command.c
  34.  *
  35.  *    Create the command window, the command buttons and their callbacks.
  36.  *
  37.  *    CreateCommandPanel() :     Create a window with command buttons
  38.  *    CreateButtons() :        Create command buttons in panel
  39.  *    AddButton() :        Add a command button into the command window
  40.  *    ButtonSet() :        Action proc for command button translation
  41.  *
  42.  *    Command callbacks for the command buttons:
  43.  *
  44.  *    forwardSearch() :        forward string search
  45.  *    reverseSearch() :        reverse string search
  46.  *    Search() :        call either forwardSearch() or reverseSearch()
  47.  *    PopupSearch() :        command callback for search button
  48.  *    DoneSearch() :        command callback for DONE button in search panel
  49.  *    CreateSearchPopup() :    create search panel
  50.  *
  51.  *    Command queue manipulation routines:
  52.  *    send_command():        send a command to dbx and record in the queue
  53.  *    get_command():        read command off head of queue
  54.  *    insert_command():    insert command at the head of queue
  55.  *    delete_command():    delete command from head of queue
  56.  */
  57.  
  58. #include <signal.h>
  59. #include <ctype.h>
  60. #include <sys/wait.h>
  61. #include "global.h"
  62.  
  63. #define     REVERSE    0
  64. #define     FORWARD    1
  65.  
  66. Widget        commandWindow;            /* command panel with buttons */
  67. Boolean        PopupMode = False;
  68. static int    Button;
  69. static Widget    searchPopupShell, searchPopup;
  70. static Widget    AddButton();
  71. static Widget    button[30];
  72. static char    SearchString[BUFSIZ] = "";    /* search string buffer */
  73. static char    command[LINESIZ];
  74. static CommandRec *commandQueue = NULL;
  75. #ifdef BSD
  76. static char    savedCommand[LINESIZ] = ""; 
  77. #endif
  78.  
  79. /* ARGSUSED */
  80. static void ButtonSet(w, event, params, num_params)
  81.     Widget w;
  82.     XEvent *event;
  83.     String *params;
  84.     Cardinal *num_params;
  85. {
  86.     Button = atoi(params[0]);
  87. }
  88.  
  89. /* ARGSUSED */
  90. /*  Execute the dbx command specifed in client_data
  91.  */
  92. static void DoIt (w, command, call_data)
  93.     Widget w;
  94.     XtPointer command;
  95.     XtPointer call_data;
  96. {
  97.     /* run, cont, next, step, where, up, down, status */
  98.     send_command(command);
  99.     AppendDialogText(command);
  100. }
  101.  
  102. /* ARGSUSED */
  103. static void Return (w, client_data, call_data)
  104.     Widget w;
  105.     XtPointer client_data;
  106.     XtPointer call_data;
  107. {
  108.     char *funcname;
  109.     int  nbytes;
  110.  
  111.     funcname = XFetchBytes(display, &nbytes);    /* from CUT_BUFFER0 */
  112.     if (nbytes == 0)
  113.         strcpy(command, "return\n");
  114.     else
  115.         sprintf(command, "return %s\n", funcname);
  116.     send_command(command);
  117.     AppendDialogText(command);
  118. }
  119.  
  120. /* ARGSUSED */
  121. static void Stop_at(w, client_data, call_data)
  122.     Widget w;
  123.     XtPointer client_data;
  124.     XtPointer call_data;
  125. {
  126.     XawTextPosition pos;
  127.     int line;
  128.  
  129.     if (displayedFile == NULL) {
  130.     UpdateMessageWindow(STOP_AT_HELP, NULL);
  131.     bell(0);
  132.     return;
  133.     }
  134.     pos = XawTextGetInsertionPoint(sourceWindow);
  135.     line = TextPositionToLine(pos);
  136.     sprintf(command, "stop at %d\n", line);
  137.     send_command(command);
  138.     AppendDialogText(command);
  139. }
  140.  
  141. /* ARGSUSED */
  142. static void Stop_in(w, client_data, call_data)
  143.     Widget w;
  144.     XtPointer client_data;
  145.     XtPointer call_data;
  146. {
  147.     char *funcname;
  148.     int  nbytes;
  149.  
  150.     funcname = XFetchBytes(display, &nbytes);    /* from CUT_BUFFER0 */
  151.     if (nbytes == 0) {
  152.     UpdateMessageWindow(STOP_IN_HELP, NULL);
  153.     bell(0);
  154.     return;
  155.     }
  156.     sprintf(command, "stop in %s\n", funcname);
  157.     send_command(command);
  158.     AppendDialogText(command);
  159. }
  160.  
  161.  
  162. /*  Delete removes the stop_no associated with a given line number.
  163.  *  RemoveStop() is called to undisplay the stop sign only when there
  164.  *  are no more stop_no's associated with that line number.
  165.  */
  166. /* ARGSUSED */
  167. static void Delete(w, client_data, call_data)
  168.     Widget w;
  169.     XtPointer client_data;
  170.     XtPointer call_data;
  171. {
  172.     XawTextPosition pos;
  173.     char        *string;
  174.     int            stop_no, line, nbytes;
  175.  
  176.     string = XFetchBytes(display, &nbytes);
  177.     if (nbytes > 0 && (stop_no = atoi(string)) > 0) {
  178.         sprintf(command, "delete %d\n", stop_no);
  179.     send_command(command);
  180.     AppendDialogText(command);
  181.     return;
  182.     }
  183.     else if (displayedFile) {
  184.     pos = XawTextGetInsertionPoint(sourceWindow);
  185.     line = TextPositionToLine(pos);
  186.     if (stop_no = LineToStop_no(line)) {
  187.         sprintf(command, "delete %d\n", stop_no);
  188.         send_command(command);
  189.         AppendDialogText(command);
  190.         return;
  191.     }
  192.     }
  193.     UpdateMessageWindow(DELETE_HELP, NULL);
  194.     bell(0);
  195. }
  196.  
  197. /* ARGSUSED */
  198. static void Print(w, client_data, call_data)
  199.     Widget w;
  200.     XtPointer client_data;
  201.     XtPointer call_data;
  202. {
  203.     char *string;
  204.     int nbytes;
  205.  
  206.     if (Button == 3) PopupMode = True;
  207.  
  208.     string = XFetchBytes(display, &nbytes);
  209.     if (nbytes == 0) {
  210.     UpdateMessageWindow(PRINT_HELP, NULL);
  211.     bell(0);
  212.     return;
  213.     }
  214.     if (client_data == (XtPointer)0)
  215.     sprintf(command, "print %s\n", string);
  216.     else if (client_data == (XtPointer)1)
  217.     sprintf(command, "print *%s\n", string);
  218.     send_command(command);
  219.     AppendDialogText(command);
  220. }
  221.  
  222. /* ARGSUSED */
  223. static void Func(w, client_data, call_data)
  224.     Widget w;
  225.     XtPointer client_data;
  226.     XtPointer call_data;
  227. {
  228.     char *funcname;
  229.     int nbytes;
  230.  
  231.     funcname = XFetchBytes(display, &nbytes);
  232.     if (nbytes == 0)
  233.         strcpy(command, "func\n");
  234.     else
  235.         sprintf(command, "func %s\n", funcname);
  236.     send_command(command);
  237.     AppendDialogText(command);
  238. }
  239.  
  240. /* ARGSUSED */
  241. static void Quit(w, client_data, call_data)
  242.     Widget w;
  243.     XtPointer client_data;
  244.     XtPointer call_data;
  245. {
  246.     union wait status;
  247.  
  248.     write_dbx("quit\n");
  249.     XtDestroyApplicationContext(app_context);
  250.     kill(dbxpid, SIGKILL);
  251.     wait3(&status, WNOHANG, NULL);
  252.     exit(0);
  253. }
  254.  
  255.  
  256. /* ARGSUSED */
  257. static void Display_(w, client_data, call_data)
  258.     Widget w;
  259.     XtPointer client_data;
  260.     XtPointer call_data;
  261. {
  262.     char *string;
  263.     int nbytes;
  264.  
  265.     string = XFetchBytes(display, &nbytes);
  266.     sprintf(command, "display %s\n", string);
  267.     send_command(command);
  268.     AppendDialogText(command);
  269. }
  270.  
  271.  
  272. /* ARGSUSED */
  273. static void Undisplay(w, client_data, call_data)
  274.     Widget w;
  275.     XtPointer client_data;
  276.     XtPointer call_data;
  277. {
  278.     char *string;
  279.     int     stop_no, nbytes;
  280.  
  281.     string = XFetchBytes(display, &nbytes);
  282.     if (nbytes == 0) {
  283.     UpdateMessageWindow(UNDISPLAY_HELP, NULL);
  284.     bell(0);
  285.     return;
  286.     }
  287.     if ((stop_no = atoi(string)) > 0)
  288.     sprintf(command, "undisplay %d\n", stop_no);
  289.     else
  290.         sprintf(command, "undisplay %s\n", string);
  291.     send_command(command);
  292.     AppendDialogText(command);
  293. }
  294.  
  295.  
  296. /* ARGSUSED */
  297. static void Dump(w, client_data, call_data)
  298.     Widget w;
  299.     XtPointer client_data;
  300.     XtPointer call_data;
  301. {
  302.     char *funcname;
  303.     int nbytes;
  304.  
  305.     funcname = XFetchBytes(display, &nbytes);
  306.     if (nbytes == 0)
  307.         strcpy(command, "dump\n");
  308.     else
  309.         sprintf(command, "dump %s\n", funcname);
  310.     send_command(command);
  311.     AppendDialogText(command);
  312. }
  313.  
  314.  
  315. /*  Beginning from startpos, this routine searches text forward for 
  316.  *  searchstring, and returns 1 if searchstring is found, also returning 
  317.  *  the left and right positions of the matched string in left and right; 
  318.  *  else 0 is returned.
  319.  *  It also does wrap-around search.
  320.  */
  321. static forwardSearch(text, startpos, searchstring, left, right)
  322.     char *text;
  323.     int  startpos;
  324.     char *searchstring;
  325.     XawTextPosition  *left, *right;
  326. {
  327.     int  searchlength, searchsize, i, n=0;
  328.     char *s1, *s2;
  329.  
  330.     searchlength = strlen(searchstring);
  331.     searchsize = strlen(text) - searchlength;
  332.     for (i=startpos; i < searchsize; i++) {
  333.     n = searchlength;
  334.     s1 = &text[i];
  335.     s2 = searchstring;
  336.     while (--n >= 0 && *++s1 == *s2++);
  337.     if (n < 0) break;
  338.     }
  339.     if (n < 0) {
  340.         *left = i+1;
  341.         *right = i+1+searchlength;
  342.         return 1;
  343.     }
  344.     else {
  345.     for (i=0; i < startpos; i++) {
  346.         n = searchlength;
  347.         s1 = &text[i];
  348.         s2 = searchstring;
  349.         while (--n >= 0 && *++s1 == *s2++);
  350.         if (n < 0) break;
  351.     }
  352.     if (n < 0) {
  353.         *left = i+1;
  354.         *right = i+1+searchlength;
  355.         return 1;
  356.     }
  357.     return 0;
  358.     }
  359. }
  360.     
  361.  
  362. /*  Similar to forwardSearch(), except that it does a reverse search
  363.  */
  364. static reverseSearch(text, startpos, searchstring, left, right)
  365.     char         *text;
  366.     XawTextPosition  startpos;
  367.     char         *searchstring;
  368.     XawTextPosition  *left, *right;
  369. {
  370.     int  searchlength, i, n=0;
  371.     char *s1, *s2;
  372.  
  373.     searchlength = strlen(searchstring);
  374.     for (i=startpos; i > searchlength; i--) {
  375.     n = searchlength;
  376.     s1 = &text[i];
  377.     s2 = &searchstring[searchlength-1];
  378.     while (--n >= 0 && *--s1 == *s2--);
  379.     if (n < 0) break;
  380.     }
  381.     if (n < 0) {
  382.         *right = i;
  383.         *left = *right-searchlength;
  384.         return 1;
  385.     }
  386.     else {
  387.     for (i=strlen(text)-1; i > startpos; i--) {
  388.         n = searchlength;
  389.         s1 = &text[i];
  390.         s2 = &searchstring[searchlength-1];
  391.         while (--n >= 0 && *--s1 == *s2--);
  392.         if (n < 0) break;
  393.     }
  394.     if (n < 0) {
  395.             *right = i;
  396.             *left = *right-searchlength;
  397.         return 1;
  398.     }
  399.     return 0;
  400.     }
  401. }
  402.  
  403. /* ARGSUSED */
  404. static void PopupSearch(w, client_data, call_data)
  405.     Widget w;
  406.     XtPointer client_data;
  407.     XtPointer call_data;
  408. {
  409.     Arg     args[MAXARGS];
  410.     Cardinal     n;
  411.     Dimension    popup_width, dialog_width;
  412.     Position    x, y;
  413.  
  414.     if (!displayedFile) {
  415.     UpdateMessageWindow(SEARCH_HELP, NULL);
  416.     bell(0);
  417.     }
  418.     else {
  419.     XtRealizeWidget(searchPopupShell);
  420.     n = 0;
  421.     XtSetArg(args[n], XtNwidth, &popup_width);            n++;
  422.     XtGetValues(searchPopupShell, args, n);
  423.     n = 0;
  424.     XtSetArg(args[n], XtNwidth, &dialog_width);            n++;
  425.     XtGetValues(dialogWindow, args, n);
  426.     XtTranslateCoords(dialogWindow, 
  427.               (Position)(dialog_width - popup_width)/2, 10, &x, &y);
  428.     n = 0;
  429.     XtSetArg(args[n], XtNx, x);                    n++;
  430.     XtSetArg(args[n], XtNy, y);                    n++;
  431.     XtSetValues(searchPopupShell, args, n);
  432.     XtPopup(searchPopupShell, XtGrabNone);
  433.     }
  434. }
  435.  
  436.  
  437. /* ARGSUSED */
  438. /*  This routine handles both forward and reverse text search.
  439.  *  If no text has been entered, the contents of the cut buffer are used
  440.  *  for searching.
  441.  */ 
  442. static void Search(w, direction, call_data)
  443.     Widget w;
  444.     XtPointer direction;
  445.     XtPointer call_data;
  446. {
  447.     XawTextBlock        textblock;
  448.     XawTextPosition    pos, left, right;
  449.     char        *searchString;
  450.  
  451.     searchString = XawDialogGetValueString(searchPopup);
  452.     if (strlen(searchString) == 0) {
  453.     textblock.ptr = XFetchBytes(display, &textblock.length);
  454.     if (!textblock.ptr) {
  455.         UpdateMessageWindow("No search string selected", NULL);
  456.         bell(0);
  457.         return;
  458.     }
  459.     searchString = textblock.ptr;
  460.     }
  461.     pos = XawTextGetInsertionPoint(sourceWindow);
  462.     if ((direction == (XtPointer)FORWARD && 
  463.     forwardSearch(displayedFile->buf, pos, searchString, &left, &right)) ||
  464.         (direction == (XtPointer)REVERSE && 
  465.     reverseSearch(displayedFile->buf, pos, searchString, &left, &right))) {
  466.         AdjustText(TextPositionToLine(left));
  467.         XawTextSetSelection(sourceWindow, left, right);
  468.         XawTextSetInsertionPoint(sourceWindow, left);
  469.     }
  470.     else {
  471.         if (direction == (XtPointer)FORWARD)
  472.             UpdateMessageWindow("String not found", NULL);
  473.         else if (direction == (XtPointer)REVERSE)
  474.             UpdateMessageWindow("String not found", NULL);
  475.         else
  476.             UpdateMessageWindow("xdbx error: illegal search direction", NULL);
  477.         bell(0);
  478.     }
  479. }
  480.  
  481. /* ARGSUSED */
  482. static void DoneSearch(w, client_data, call_data)
  483.     Widget w;
  484.     XtPointer client_data;
  485.     XtPointer call_data;
  486. {
  487.     XtPopdown(client_data);
  488. }
  489.  
  490. /* ARGSUSED */
  491. static void Activate(w, event, params, num_params)
  492.     Widget w;
  493.     XEvent *event;
  494.     String *params;
  495.     Cardinal *num_params;
  496. {
  497.     Search(w, (XtPointer)FORWARD, NULL);
  498.     DoneSearch(w, (XtPointer)searchPopupShell, NULL);
  499. }
  500.  
  501. static void CreateSearchPopup()
  502. {
  503.     Widget    dialogValue;
  504.     Arg     args[MAXARGS];
  505.     Cardinal     n;
  506.  
  507.     static XtActionsRec search_actions[] = {
  508.         {"Activate", Activate},
  509.         {NULL, NULL}
  510.     };
  511.  
  512.     static String translations = "#override\n\
  513.         <Key>Return:         Activate() \n\
  514.     ";
  515.  
  516.     n = 0;
  517.     XtSetArg(args[n], XtNinput, True);                    n++;
  518.     XtSetArg(args[n], XtNallowShellResize, True);            n++;
  519.     searchPopupShell = XtCreatePopupShell("Search", transientShellWidgetClass, 
  520.     toplevel, args, n);
  521.  
  522.     n = 0;
  523.     XtSetArg(args[n], XtNlabel, "Enter search string :");        n++;
  524.     XtSetArg(args[n], XtNvalue, SearchString);                n++;
  525.     searchPopup = XtCreateManagedWidget("searchPopup", dialogWidgetClass, 
  526.     searchPopupShell, args, n);
  527.     
  528.     AddButton(searchPopup, "<<", Search, (XtPointer) REVERSE);
  529.     AddButton(searchPopup, ">>", Search, (XtPointer) FORWARD);
  530.     AddButton(searchPopup, "DONE", DoneSearch, (XtPointer)searchPopupShell);
  531.  
  532.     dialogValue = XtNameToWidget(searchPopup, "value");
  533.     XtOverrideTranslations(dialogValue, XtParseTranslationTable(translations));
  534.     XtAppAddActions(app_context, search_actions, XtNumber(search_actions));
  535. }
  536.  
  537.  
  538.  
  539. static Widget AddButton(parent, name, function, client_data)
  540. Widget parent;
  541. char *name;
  542. void (*function) ();
  543. XtPointer client_data;        /* callback registered data */
  544. {
  545.     Widget     button;
  546.     Arg     args[MAXARGS];
  547.     Cardinal     n;
  548.  
  549.     static XtActionsRec command_actions[] = {
  550.     {"ButtonSet", (XtActionProc) ButtonSet},
  551.         {NULL, NULL}
  552.     };
  553.  
  554.     static String translations = "\
  555.     <EnterWindow>:    highlight() \n\
  556.     <LeaveWindow>:    reset() \n\
  557.     <Btn1Down>:    set()\n\
  558.     <Btn1Up>:    ButtonSet(1) notify() unset() \n\
  559.     <Btn3Down>:    set()\n\
  560.     <Btn3Up>:    ButtonSet(3) notify() unset()\n\
  561.     ";
  562.  
  563.     n = 0;
  564.     XtSetArg(args[n], XtNresize, (XtArgVal) False);            n++;
  565.     if (strcmp(name, "print") == NULL || strcmp(name, "print *") == NULL) {
  566.     XtSetArg(args[n], XtNtranslations, 
  567.         XtParseTranslationTable(translations));             n++;
  568.     }
  569.     button = XtCreateManagedWidget(name, commandWidgetClass, parent, args, n);
  570.     XtAddCallback(button, XtNcallback, function, client_data);
  571.     XtAppAddActions(app_context, command_actions, XtNumber(command_actions));
  572.     return (button);
  573. }
  574.  
  575.  
  576. static void CreateButtons (parent)
  577. Widget parent;
  578. {
  579.     int i=0;
  580.  
  581.     button[i++] = AddButton (parent, "run", DoIt, "run\n");
  582.     button[i++] = AddButton (parent, "cont", DoIt, "cont\n");
  583.     button[i++] = AddButton (parent, "next", DoIt, "next\n");
  584.     button[i++] = AddButton (parent, "step", DoIt, "step\n");
  585. #ifdef BSD
  586.     button[i++] = AddButton (parent, "return", Return, "return\n");
  587. #endif
  588.     button[i++] = AddButton (parent, "stop at", Stop_at, NULL);
  589.     button[i++] = AddButton (parent, "stop in", Stop_in, NULL);
  590.     button[i++] = AddButton (parent, "delete", Delete, NULL);
  591.     button[i++] = AddButton (parent, "where", DoIt, "where\n");
  592.     button[i++] = AddButton (parent, "up", DoIt, "up\n");
  593.     button[i++] = AddButton (parent, "down", DoIt, "down\n");
  594.     button[i++] = AddButton (parent, "print", Print, (XtPointer)0);
  595.     button[i++] = AddButton (parent, "print *", Print, (XtPointer)1);
  596.     button[i++] = AddButton (parent, "func", Func, NULL);
  597.     button[i++] = AddButton (parent, "file", File, NULL);
  598.     button[i++] = AddButton (parent, "status", DoIt, "status\n");
  599. #ifndef BSD
  600.     button[i++] = AddButton (parent, "display", Display_, NULL);
  601.     button[i++] = AddButton (parent, "undisplay", Undisplay, NULL);
  602. #endif
  603.     button[i++] = AddButton (parent, "dump", Dump, NULL);
  604.     button[i++] = AddButton (parent, "search", PopupSearch, NULL);
  605.     button[i++] = AddButton (parent, "quit", Quit, NULL);
  606.     button[i++] = NULL;
  607.     CreateSearchPopup();
  608. }
  609.  
  610.  
  611. /*  Create a command widget, and the buttons.  */
  612.  
  613. void CreateCommandPanel(parent)
  614. Widget parent;
  615. {
  616.     Arg args[10];
  617.     Cardinal n;
  618.  
  619.     n = 0;
  620.     commandWindow = XtCreateManagedWidget("commandWindow", boxWidgetClass, 
  621.                       parent, args, n);
  622.     CreateButtons(commandWindow);
  623.     getwd(cwd);
  624. }
  625.  
  626. /**************************************************************************
  627.  *
  628.  *  Command queue functions
  629.  *
  630.  **************************************************************************/
  631.  
  632. /*  Append command to end of the command queue and send the command to dbx */
  633.  
  634. void send_command(command)
  635. char *command;
  636. {
  637.     CommandRec *p, *q, *r;
  638.  
  639. #ifdef BSD 
  640.     /* Save the command if it is not a blank command; else use the 
  641.        last saved command instead */
  642.     if (strcspn(command, " \n"))
  643.     strcpy(savedCommand, command);
  644.     else
  645.     strcpy(command, savedCommand);
  646. #endif
  647.  
  648.     p = (CommandRec *)XtNew(CommandRec);
  649.     p->command = XtNewString(command);
  650.     p->next = NULL;
  651.     if (!commandQueue)
  652.     commandQueue = p;
  653.     else {
  654.     q = commandQueue;
  655.     while (r = q->next)
  656.         q = r;
  657.     q->next = p;
  658.     }
  659.     write_dbx(command);
  660. }
  661.  
  662. /*  Read command at the head of the command queue */
  663.  
  664. char *get_command()
  665. {
  666.     if (commandQueue) {
  667.     return (commandQueue->command);
  668.     }
  669.     else
  670.     return NULL;
  671. }
  672.  
  673. /*  Delete command from the head of the command queue */
  674.  
  675. void delete_command()
  676. {
  677.     CommandRec *p;
  678.  
  679.     if (p = commandQueue) {
  680.     commandQueue = p->next;
  681.     XtFree(p->command);
  682.     XtFree(p);
  683.     }
  684. }
  685.  
  686. /*  Insert command into head of queue */
  687.  
  688. void insert_command(command)
  689. char *command;
  690. {
  691.     CommandRec *p;
  692.  
  693.     p = (CommandRec *)XtNew(CommandRec);
  694.     p->command = XtNewString(command);
  695.     p->next = NULL;
  696.     if (!commandQueue)
  697.     commandQueue = p;
  698.     else {
  699.     p->next = commandQueue;
  700.     commandQueue = p;
  701.     }
  702. }
  703.