home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / Jetedit / part03 / xmemisc.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-28  |  26.5 KB  |  891 lines

  1. /**---------------------------------------------------------------------
  2. ***     
  3. ***    file:        xmemisc.c
  4. ***
  5. ***    project:    jetedit - Motif Widgets text editor
  6. ***
  7. ***-------------------------------------------------------------------*/
  8.  
  9. #define  BUFFER  20    /* The number of commands that can be undone. */
  10. #define  BUFSIZE 40    /* The default storage size for the undo data. */
  11. #include "xme.h"
  12.  
  13. struct UndoRecord {
  14.     XmTextPosition  start_pos;
  15.     XmTextPosition  end_pos;
  16.     XmTextPosition  cursor_pos;
  17.     char  *delete_string;
  18. } UndoRecordPtr[BUFFER];
  19.  
  20. int    head, tail;
  21.  
  22. /*--------------------------------------------------------------
  23. **      OpenUndoBuffer
  24. **              Initialize an array of UndoRecord structures.
  25. */
  26. void OpenUndoBuffer()
  27. {
  28.     int  i;
  29.     
  30.     for (i=0; i<BUFFER; i++) {
  31.         UndoRecordPtr[i].delete_string = XtMalloc (BUFSIZE);
  32.         (UndoRecordPtr[i].delete_string)[0] = '\0';
  33.         UndoRecordPtr[i].start_pos = 0;
  34.         UndoRecordPtr[i].end_pos = 0;
  35.         UndoRecordPtr[i].cursor_pos = 0;
  36.     }
  37.     head = 0;
  38.     tail = 0;
  39. }
  40.  
  41.  
  42. /*--------------------------------------------------------------
  43. **      InitUndoBuffer
  44. **              Reinitialize the array of UndoRecord structures.
  45. */
  46. void InitUndoBuffer()
  47. {
  48.     int  i;
  49.     
  50.     for (i=0; i<BUFFER; i++) {
  51.         UndoRecordPtr[i].delete_string = 
  52.               XtRealloc (UndoRecordPtr[i].delete_string, BUFSIZE);
  53.         (UndoRecordPtr[i].delete_string)[0] = '\0';
  54.         UndoRecordPtr[i].start_pos = 0;
  55.         UndoRecordPtr[i].end_pos = 0;
  56.         UndoRecordPtr[i].cursor_pos = 0;
  57.     }
  58.     head = 0;
  59.     tail = 0;
  60. }
  61.  
  62.  
  63. /*--------------------------------------------------------------
  64. **      CloseUndoBuffer
  65. **              Deallocate the string arrays.
  66. */
  67. void CloseUndoBuffer()
  68. {
  69.     int  i;
  70.     
  71.     XtSetSensitive(undo_button, False);
  72.     for (i=0; i<BUFFER; i++)
  73.         XtFree (UndoRecordPtr[i].delete_string);
  74. }
  75.     
  76.     
  77. /*--------------------------------------------------------------
  78. **      UndoStoreCB
  79. **              Store an UndoRecord structure.
  80. */
  81. void UndoStoreCB (w, client_data, call_data)
  82. Widget    w;
  83. caddr_t    client_data;
  84. caddr_t    call_data;
  85. {
  86.     XmTextVerifyCallbackStruct *cb = (XmTextVerifyCallbackStruct *) call_data;
  87.     XmTextPosition    startpos, endpos;
  88.     char    *deltext;    /* text being deleted */
  89.     char    *thestring;    /* the complete text in the text widget */
  90.     int        textl;        /* the length of the text to be inserted */
  91.     long    i, j;
  92.     Arg        al[1];
  93.     int        newlines;
  94.     
  95.     if (no_undo) return;    /* a flag indicating to not store an undo record */
  96.     
  97.     if (file_saved) {
  98.         file_saved = False;
  99.         XtSetSensitive(save_button, True);
  100.         sprintf (message_string, " Editing:  %s", thefile);
  101.         XtSetArg(al[0], XmNlabelString, 
  102.             XmStringCreateLtoR(message_string, charset));
  103.         XtSetValues(message, al, 1);
  104.     }
  105.     XtSetSensitive(undo_button, True);
  106.     head++;
  107.     if (head >= BUFFER) 
  108.         head = 0;
  109.     if (head == tail) {
  110.         tail++;
  111.         if (tail >= BUFFER)
  112.             tail = 0;
  113.     }
  114.     
  115.     startpos = cb->startPos;
  116.     endpos   = cb->endPos;
  117.     textl  = cb->text->length;
  118.     thestring = cb->text->ptr;
  119.     deltext = UndoRecordPtr[head].delete_string;
  120.     deltext[0] = '\0';
  121.     UndoRecordPtr[head].cursor_pos = cb->currInsert;
  122.     UndoRecordPtr[head].start_pos = startpos;
  123.     UndoRecordPtr[head].end_pos = startpos + textl;
  124.  
  125.     newlines = 0;
  126.     if (textl) {     /* text is being inserted */
  127.         for (i=0; i<textl; i++)
  128.             if (thestring[i] == '\n')
  129.                 newlines++;
  130.     }
  131.     if (endpos != startpos) {      /* text is being deleted */
  132.         if (endpos - startpos + 1 > BUFSIZE) {
  133.             deltext = XtRealloc 
  134.                   (UndoRecordPtr[head].delete_string, endpos - startpos +1);
  135.             UndoRecordPtr[head].delete_string = deltext;
  136.         }
  137.         thestring = XmTextGetString(w);
  138.         j=0;
  139.         for (i=startpos; i<endpos; i++,j++) {
  140.             deltext[j] = thestring[i];
  141.             if (deltext[j] == '\n')
  142.                 newlines--;
  143.         }
  144.         deltext[j] = '\0';
  145.         XtFree(thestring);
  146.     }
  147.     
  148.     if (newlines) {
  149.         /* update the line number message */
  150.         lines += newlines;
  151.         sprintf (message_string, " Line:  %4d", lines);
  152.         XtSetArg(al[0], XmNlabelString, 
  153.             XmStringCreateLtoR(message_string, charset));
  154.         XtSetValues(line, al, 1);
  155.     }
  156. }
  157.  
  158.  
  159. /*--------------------------------------------------------------
  160. **      Undo
  161. **              Restore previous condition from an UndoRecord Structure.
  162. */
  163. void Undo(event)
  164. XKeyEvent *event;
  165. {
  166.     XmTextPosition startpos;
  167.     XmTextPosition endpos;
  168.     char    *thestring;
  169.     int        length, j, newlines;
  170.     char     *file_string;
  171.     char    line_string[15];
  172.     Arg        al[1];
  173.     
  174.     if (head == tail) return;
  175.     no_undo = True;
  176.     startpos = UndoRecordPtr[head].start_pos;
  177.     endpos = UndoRecordPtr[head].end_pos;
  178.     thestring = UndoRecordPtr[head].delete_string;
  179.     length = strlen(thestring);
  180.     
  181.     XmTextReplace (text, startpos, endpos, thestring);
  182.     if (length > 1)
  183.         XmTextSetSelection(text, startpos, startpos+length, event->time+1);
  184.     MoveTo(UndoRecordPtr[head].cursor_pos);
  185.     
  186.     file_string = (char *)XmTextGetString(text);
  187.     newlines = 1;
  188.     for (j=0; j<UndoRecordPtr[head].cursor_pos; j++)
  189.         if(file_string[j] == '\n')
  190.             newlines++;
  191.     
  192.     if (lines != newlines) {
  193.         lines = newlines;
  194.         /* update the line number message */
  195.         sprintf (line_string, " Line:%5d", lines);
  196.         XtSetArg(al[0], XmNlabelString, 
  197.             XmStringCreateLtoR(line_string, charset));
  198.         XtSetValues(line, al, 1);
  199.     }
  200.     XtFree (file_string);
  201.     
  202.     head--;
  203.     if (head < 0)
  204.         head = BUFFER - 1;
  205.     if (head == tail)
  206.         XtSetSensitive(undo_button, False);
  207.     no_undo = False;
  208. }
  209.  
  210.  
  211. /*--------------------------------------------------------------
  212. **      Indent
  213. **              Insert tab stop or spaces as appropriate.
  214. **        Return the number of characters inserted.
  215. */
  216. int Indent(file_string, cursorPos, fixCursor)
  217. char    *file_string;
  218. XmTextPosition cursorPos;
  219. Boolean fixCursor;
  220. {
  221.     XmTextPosition linePos;
  222.     int      i,j;
  223.     char     theChar;
  224.     int      numSpaces;
  225.     char     insertionText[MAX_TAB_SPACES+1];
  226.     Boolean    leading;    /* leading or trailing flag */
  227.     
  228.     /* if real tabs are selected, just insert and return */
  229.     if (leading_tabs && trailing_tabs) {
  230.         XmTextReplace(text, cursorPos, cursorPos, "\t");
  231.         return(1);
  232.     }
  233.     
  234.     /* FixCursor is a flag indicating this routine was called from
  235.         the auto indenting routines in NewLine. NewLine sends only
  236.         single lines of text in file_string rather than the entire
  237.         file. */
  238.     if (fixCursor)
  239.         linePos = strlen (file_string);
  240.     else linePos = cursorPos;
  241.     
  242.     /* We now figure out where to tab to. The first step is to move back
  243.         to the first non-space character, counting spaces as we go. */
  244.     numSpaces = 0;
  245.     while (linePos-- > 0) {
  246.         if (file_string[linePos] != ' ')
  247.             break;
  248.         numSpaces++;
  249.     }
  250.     
  251.     /* If the first none space character is a newline, or we reach the 
  252.         beginning of the string without finding anything but spaces,
  253.         we are inserting a leading tab stop. */
  254.     theChar = file_string[linePos];
  255.     if ((theChar == '\n') || (linePos < 0))
  256.         leading = True;
  257.     
  258.     /* else if the character was anything but '\t', we are 
  259.         inserting a trailing tab. Determine the total number of
  260.         characters on the line (stop counting if '\t' is encountered) */
  261.     else if (theChar != '\t') {
  262.         leading = False;
  263.         numSpaces++;
  264.         while (linePos-- > 0) {
  265.             if ((file_string[linePos] == '\n') || (file_string[linePos] == '\t'))
  266.                 break;
  267.             numSpaces++;
  268.         }
  269.     }
  270.     
  271.     /* else the character must have been '\t'. We check to see if there is anything
  272.         but spaces or tabs back on the line. If there are, it's a trailing tab.
  273.         If not, it's a leading tab. */
  274.     else {
  275.         while (linePos >= 0) {
  276.             if ((file_string[linePos] != ' ') && (file_string[linePos] != '\t'))
  277.                 break;
  278.             linePos--;
  279.         }
  280.         if ((file_string[linePos] == '\n') || (linePos < 0))
  281.             leading = True;
  282.         else leading = False;
  283.     }
  284.     
  285.     if ((leading && leading_tabs) || (!leading && trailing_tabs)) {
  286.         XmTextReplace(text, cursorPos, cursorPos, "\t");
  287.         return(1);
  288.     }
  289.     
  290.     /* Insert enough spaces to fill out to the next tab_spaces stop. */
  291.     i = tab_spaces - (numSpaces % tab_spaces);
  292.     for (j=0; j<i; j++)
  293.         insertionText[j] = ' ';
  294.     insertionText[i] = '\0';
  295.     XmTextReplace(text, cursorPos, cursorPos, insertionText);
  296.     return (i);
  297. }
  298.  
  299.  
  300.  
  301. /*--------------------------------------------------------------
  302. **      Outdent
  303. **              Delete to previous tab stop.
  304. */
  305. int Outdent(file_string, cursorPos, fixCursor)
  306. char    *file_string;
  307. XmTextPosition cursorPos;
  308. Boolean fixCursor;
  309. {
  310.     XmTextPosition linePos;
  311.     int  i;
  312.     int  numSpaces;
  313.     int  numNotabs;
  314.     
  315.     numSpaces=0;
  316.     /* FixCursor is a flag indicating this routine was called from
  317.         the auto indenting routines in NewLine. NewLine sends only
  318.         single lines of text in file_string rather than the entire
  319.         file. */
  320.     if (fixCursor)
  321.         linePos = strlen (file_string);
  322.     else linePos = cursorPos;
  323.     /* find previous none space */
  324.     while (linePos > 0) {
  325.         linePos--;
  326.         if (file_string[linePos] != ' ')
  327.             break;
  328.         numSpaces++;
  329.     }
  330.     /* Now we determine the total number of characters in the line.
  331.        We stop counting if we find a '\n' or '\t'. */
  332.     numNotabs = numSpaces;
  333.     if (file_string[linePos] != ' ') {
  334.         while (linePos > 0) {
  335.             if ((file_string[linePos] == '\n') || (file_string[linePos] == '\t'))
  336.                 break;
  337.             numNotabs++;
  338.             linePos--;        
  339.         }
  340.     }
  341.     
  342.     if (numNotabs) {
  343.         i = numNotabs % tab_spaces;
  344.         if (i == 0)
  345.             i = tab_spaces;
  346.         if (i > numSpaces)
  347.             i = numSpaces;
  348.     }
  349.     else {
  350.         if (file_string[linePos] == '\t')
  351.             i=1;
  352.         else i=0;
  353.     }
  354.  
  355.     if (i)
  356.         XmTextReplace(text, cursorPos-i, cursorPos, "");
  357.     return (i);
  358. }
  359.  
  360.  
  361. /*--------------------------------------------------------------
  362. **      IndentText
  363. **              Indent each line in a block of selected text
  364. **        or at the cursor if no text selected.
  365. */
  366. void IndentText(w,event)
  367. Widget      w;
  368. XKeyEvent *event;
  369. {
  370.     XmTextPosition cursorPos;
  371.     XmTextPosition linePos;
  372.     XmTextPosition endPos;
  373.     XmTextPosition startPos;
  374.     Arg  al[2];
  375.     char *selString;            /* the selected block of text */
  376.     char *file_string;
  377.     int     i;
  378.     
  379.     /* get the text string */
  380.     file_string = (char *)XmTextGetString(text);
  381.     /* get cursor position */
  382.     XtSetArg(al[0], XmNcursorPosition, &cursorPos);
  383.     XtGetValues(text, al, 1);
  384.     
  385.     /* The cursor may be located at either the start or end of the
  386.        selected block of text. */
  387.     selString = NULL;
  388.     if ((selString = XmTextGetSelection (text)) && strlen(selString)) {
  389.         if (!strncmp (selString, file_string+cursorPos, strlen(selString))) {
  390.             startPos = cursorPos;
  391.             endPos = cursorPos + strlen (selString);
  392.         }
  393.         else {
  394.             startPos = cursorPos - strlen (selString);
  395.             endPos = cursorPos;
  396.         }
  397.         cursorPos = endPos;
  398.         
  399.         if (file_string[--cursorPos] == '\n')
  400.             cursorPos--;    /* if last character is newline,
  401.                                     move back one character */
  402.         while (cursorPos >= startPos) {
  403.             /* find start of line */
  404.             while (file_string[cursorPos] != '\n' && cursorPos >= startPos)
  405.                 cursorPos--;
  406.             linePos = cursorPos + 1;
  407.             while (linePos < endPos) {
  408.                 if ((file_string[linePos] != ' ') && (file_string[linePos] != '\t'))
  409.                     break;
  410.                 linePos++;
  411.             }
  412.             i = Indent (file_string, linePos, False);
  413.             endPos += i;
  414.             cursorPos --;
  415.         }
  416.         /* the widget apparently clears the selection at event->time,
  417.            so we need to add one to get it to set a new selection */
  418.         XmTextSetSelection (text, startPos, endPos, event->time+1);
  419.         MoveTo(endPos);
  420.     }
  421.     else {
  422.         Indent(file_string, cursorPos, False);
  423.     }
  424.     
  425.     if (selString)
  426.         XtFree(selString);
  427.     XtFree (file_string);
  428. }
  429.  
  430.  
  431. /*--------------------------------------------------------------
  432. **      OutdentText
  433. **              Outdent each line in a block of selected text
  434. **        or at the cursor if no text selected.
  435. */
  436. void OutdentText(w,event)
  437. Widget      w;
  438. XKeyEvent *event;
  439. {
  440.     XmTextPosition cursorPos;        /* text cursor position    */
  441.     XmTextPosition endPos;
  442.     XmTextPosition startPos;
  443.     XmTextPosition oldPos;
  444.     Arg  al[2];
  445.     char *selString;            /* the selected block of text */
  446.     char *file_string;
  447.     char theChar;
  448.     
  449.     
  450.     /* get the text string */
  451.     file_string = (char *)XmTextGetString(text);
  452.     /* get cursor position */
  453.     XtSetArg(al[0], XmNcursorPosition, &cursorPos);
  454.     XtGetValues(text, al, 1);
  455.     
  456.     selString = NULL;
  457.     if ((selString = XmTextGetSelection (text)) && strlen(selString)) {
  458.         /*determine if cursor is at the beginning or end of selected block */
  459.         if (!strncmp (selString, file_string+cursorPos, strlen(selString))) {
  460.             startPos = cursorPos;
  461.             endPos = cursorPos + strlen (selString);
  462.         }
  463.         else {
  464.             startPos = cursorPos - strlen (selString);
  465.             endPos = cursorPos;
  466.         }
  467.         cursorPos = endPos;
  468.         
  469.         if (file_string[--cursorPos] == '\n')
  470.             cursorPos--;        /* if last character is \n, skip */
  471.         while (cursorPos >= startPos) {
  472.             /* find start of line */
  473.             while (file_string[cursorPos] != '\n' && cursorPos >= startPos)
  474.                 cursorPos--;
  475.             /* find first non space or tab */
  476.             oldPos = cursorPos;
  477.             while ((theChar = file_string[++cursorPos]) == '\t' || theChar == ' ')
  478.                 ;
  479.             endPos -= Outdent(file_string, cursorPos, False);
  480.             cursorPos = oldPos-1;
  481.         }
  482.         /* the widget apparently clears the selection at event->time,
  483.            so we need to add one to get it to set a new selection */
  484.         XmTextSetSelection (text, startPos, endPos, event->time+1);
  485.     }
  486.     else Outdent(file_string, cursorPos, False);
  487.     
  488.     if (selString)
  489.         XtFree(selString);
  490.     XtFree (file_string);
  491. }
  492.  
  493.  
  494. /*--------------------------------------------------------------
  495. **    GetPrevLine
  496. **        Get the previous line minus leading and trailing
  497. **        spaces and tabs.
  498. **
  499. **        This routine alters the contents of file_string.
  500. **        It returns a pointer to the
  501. **        position in file_string of the first non whitespace
  502. **        character of the first line before old_pos which is
  503. **        not a comment line. This can be the line containing
  504. **        old_pos. '\0's are put at the starting value of
  505. **        old_pos and at the end of the returned line but
  506. **        before trailing comments or whitespace.
  507. **
  508. **        On entry, old_pos points to the current insert point.
  509. **        On exit, it points to the '\n' immediately preceding
  510. **        the returned line. If there is no '\n', old_pos returns
  511. **        -1.
  512. **
  513. **        text_pos returns the offset from 
  514. **        the beginning of file_string of the beginning of
  515. **        the returned string.
  516. **
  517. **        spacetab will contain a '\n' followed by the leading
  518. **        whitespace and terminated with '\0'. This is for use
  519. **        in indenting the next line to the same position as the 
  520. **        previous one.
  521. */
  522. char *GetPrevLine(file_string, old_pos, text_pos, spacetab)
  523. char *file_string;
  524. long *old_pos;
  525. long *text_pos;
  526. char *spacetab;
  527. {
  528.     char *trailing;
  529.     long  i;
  530.     char theChar;
  531.     char *theLine;
  532.     
  533.     /* the while loop eliminates lines of only tabs, spaces & comments */
  534.     i=0;
  535.     while (*old_pos > 0) {
  536.         /* get the line */
  537.         file_string[*old_pos] = '\0';
  538.         while (file_string[--(*old_pos)] != '\n') 
  539.             if (*old_pos < 0) break;
  540.         *text_pos = *old_pos;
  541.         (*text_pos)++;
  542.         /* save leading spaces and tabs */
  543.         i=0;
  544.         spacetab[i++] = '\n';
  545.         while ((file_string[*text_pos] == ' ') || (file_string[*text_pos] == '\t')) {
  546.             spacetab[i++] = file_string[*text_pos];
  547.             (*text_pos)++;
  548.         }
  549.         /* strip the returned line of leading tabs & spaces */
  550.         theLine = (char *)(file_string + *text_pos);
  551.         /* if the line contains any characters, check for a comment line */
  552.         if (theLine[0] != '\0') {
  553.             /* break if this line is not a comment */
  554.             if (theLine[0] != '*' && strncmp (theLine, "/*", 2))
  555.                 break;
  556.         }
  557.     }
  558.     spacetab[i] = '\0';
  559.     spacetab[i+1] = '\0';    /* used by NewLine */
  560.  
  561.     /* delete trailing comments */
  562.     if (trailing = strchr (theLine, '/'))
  563.         if (trailing[1] == '*')
  564.             trailing[0] = '\0';
  565.     
  566.     /* delete trailing spaces & tabs */
  567.     i = strlen (theLine);
  568.     while (((theChar = theLine[--i]) == ' ') || (theChar == '\t'))
  569.         ;
  570.     theLine[i+1] = '\0';
  571.     return (theLine);
  572. }
  573.  
  574. /*--------------------------------------------------------------
  575. **      InSwitch
  576. **              Determine whether text_pos is in a switch.
  577. */
  578. Boolean    InSwitch(file_string, text_pos)
  579. char    *file_string;
  580. long    text_pos;
  581. {
  582.     int     close_brackets;
  583.     char    *theLine;
  584.     
  585.     close_brackets = 0;
  586.     while (text_pos-- > 0) {
  587.         if (file_string[text_pos] == '}')
  588.             close_brackets++;
  589.         else if (file_string[text_pos] == '{') 
  590.             if (close_brackets >= 0)
  591.                 close_brackets--;
  592.             else 
  593.                 return False;
  594.         else if (file_string[text_pos] == 's') {
  595.             theLine = (char *)(file_string + text_pos);
  596.             if (!strncmp (theLine, "switch", 6))
  597.                 return True;
  598.         }
  599.     }
  600.     return False;
  601. }
  602.                 
  603. /*--------------------------------------------------------------
  604. **      NewLine
  605. **              Indent new line to appropriate syntax sensitive 
  606. **        position.
  607. */
  608. void NewLine(w,event)
  609. Widget      w;
  610. XKeyEvent *event;
  611. {
  612.     XmTextPosition cursorPos;       /* text cursor position    */
  613.     Arg      al[1];
  614.     char     *file_string;
  615.     long     textPos;
  616.     long     oldPos;
  617.     char     spacetab[100];
  618.     char     garbage[100];
  619.     char     *theLine;
  620.     char     *oldLine;
  621.     char     theChar;
  622.     int      i;
  623.     Boolean    inFlag;
  624.     char    line_string[15];
  625.     
  626.     /* get the cursor position */
  627.     XtSetArg(al[0], XmNcursorPosition, &cursorPos);
  628.     XtGetValues(text, al, 1);
  629.     
  630.     /* get the text string */
  631.     file_string = (char *)XmTextGetString(text);
  632.     if ((indent_style==NONE) || (file_string[cursorPos-1] == '\n') || (cursorPos == 0)) {
  633.         XmTextReplace(text, cursorPos, cursorPos, "\n");
  634.         MoveTo(cursorPos+1);
  635.         return;
  636.     }
  637.         
  638.     oldPos = (long)cursorPos;
  639.     theLine = GetPrevLine(file_string, &oldPos, &textPos, &spacetab[0]);
  640.  
  641.     /* indent new line to position of previous line - smart indenting */
  642.     XmTextReplace(text, cursorPos, cursorPos, spacetab);
  643.     cursorPos += strlen (spacetab);
  644.     if (indent_style == SMART) {
  645.         MoveTo(cursorPos);
  646.         return;
  647.     }
  648.     
  649.     /* C syntax sensitive indenting. */
  650.     /* if theLine is not empty, check whether to indent or outdent */
  651.     if (i = strlen(theLine)) {
  652.         if (theLine[i-1] != ';') {
  653.             inFlag = False;
  654.             switch (theLine[0]) {
  655.             case 'c':
  656.                 if (!strncmp (theLine, "case", 4))
  657.                     inFlag = True;
  658.                 break;
  659.             case 'd':
  660.                 if (!strncmp (theLine, "do", 2))
  661.                     inFlag = True;
  662.                 break;
  663.             case 'e':
  664.                 if (!strncmp (theLine, "else", 4))
  665.                     inFlag = True;
  666.                 break;
  667.             case 'f':
  668.                 if (!strncmp (theLine, "for", 3))
  669.                     inFlag = True;
  670.                 break;
  671.             case 'i':
  672.                 if (!strncmp (theLine, "if", 2))
  673.                     inFlag = True;
  674.                 break;
  675.             case 's':
  676.                 if (!strncmp (theLine, "struct", 6))
  677.                     inFlag = True;
  678.                 else if (!strncmp (theLine, "static", 6))
  679.                     inFlag = True;
  680.                 else if (!strncmp (theLine, "switch", 6))
  681.                     if (indent_case || open_brace != 2)
  682.                         inFlag = True;
  683.                 break;
  684.             case 't':
  685.                 if (!strncmp (theLine, "typedef", 7))
  686.                     inFlag = True;
  687.                 break;
  688.             case 'w':
  689.                 if (!strncmp (theLine, "while", 5))
  690.                     inFlag = True;
  691.                 break;
  692.             case '{':
  693.                 if (open_brace != 1 && theLine[1] == '\0') {
  694.                     if (oldPos>0) {
  695.                         theLine = GetPrevLine(file_string, &oldPos, &textPos, &garbage[0]);
  696.                         if (indent_case || strncmp(theLine, "switch", 6))
  697.                             inFlag = True;
  698.                     }
  699.                 }
  700.                 break;
  701.             case '}':
  702.                 if (close_brace == 1)
  703.                     Outdent(spacetab, cursorPos, True);
  704.                 break;
  705.             }
  706.             if (inFlag)
  707.                 Indent (spacetab, cursorPos, True);
  708.         }
  709.         /* Else the previous line ends in a ';'. We need to check the line
  710.         ** before it to decide whether to outdent.
  711.         */
  712.         else {
  713.             /* outdent after a break when in a switch */
  714.             if (!strncmp (theLine, "break", 5)) {
  715.                 if (InSwitch(file_string, oldPos))
  716.                     Outdent (spacetab, cursorPos, True);
  717.             }
  718.             else if (oldPos>0) {
  719.                 theLine = GetPrevLine(file_string, &oldPos, &textPos, &garbage[0]);
  720.                 if (i = strlen(theLine))
  721.                     switch (theLine[i-1]) {
  722.                     case ';':
  723.                     case ':':
  724.                     case '{':
  725.                     case '}':
  726.                         break;
  727.                     default:
  728.                         Outdent (spacetab, cursorPos, True);
  729.                         break;
  730.                     }
  731.             }
  732.         }
  733.     }
  734.     XtFree (file_string);
  735. }
  736.     
  737. /*--------------------------------------------------------------
  738. **      LeftBrace
  739. **              Outdent when a left brace is typed when using
  740. **        syntax sensitive indenting and open_brace==0.
  741. */
  742. void LeftBrace(w,event)
  743. Widget      w;
  744. XKeyEvent *event;
  745. {
  746.     XmTextPosition cursorPos;        /* text cursor position    */
  747.     XmTextPosition thePos;
  748.     long textPos;
  749.     Arg  al[10];
  750.     char *file_string;
  751.     char spacetab[100];
  752.     char *theLine;
  753.     char theChar;
  754.     
  755.     /* get the text string */
  756.     file_string = (char *)XmTextGetString(text);
  757.     /* get cursor position */
  758.     XtSetArg(al[0], XmNcursorPosition, &cursorPos);
  759.     XtGetValues(text, al, 1);
  760.     XmTextReplace(text, cursorPos, cursorPos, "{");
  761.     if ((indent_style==SYNTAX) && (open_brace == 0)) {
  762.         /* we need to make sure this is the first character on the line to
  763.             prevent outdenting { typed in comments */
  764.         thePos = cursorPos;
  765.         while (thePos > 0) {
  766.             thePos--;
  767.             if ((theChar = file_string[thePos]) == '\n') {
  768.                 Outdent (file_string, cursorPos, False);
  769.                 break;
  770.             }
  771.             else if (theChar != ' ' && theChar != '\t')
  772.                 break;
  773.         }
  774.     }
  775.     XtFree (file_string);
  776. }
  777.  
  778. /*--------------------------------------------------------------
  779. **      RightBrace
  780. **              Outdent when a right brace is typed when using
  781. **        syntax sensitive indenting and close_brace==0.
  782. **        It's a little more complex if the right brace follows
  783. **        a break.
  784. */
  785. void RightBrace(w,event)
  786. Widget      w;
  787. XKeyEvent *event;
  788. {
  789.     XmTextPosition cursorPos;        /* text cursor position    */
  790.     XmTextPosition thePos;
  791.     long textPos;
  792.     Arg  al[10];
  793.     char *file_string;
  794.     char spacetab[100];
  795.     char *theLine;
  796.     char theChar;
  797.     
  798.     /* get the text string */
  799.     file_string = (char *)XmTextGetString(text);
  800.     /* get cursor position */
  801.     XtSetArg(al[0], XmNcursorPosition, &cursorPos);
  802.     XtGetValues(text, al, 1);
  803.     XmTextReplace(text, cursorPos, cursorPos, "}");
  804.     if ((close_brace==0) && (indent_style==SYNTAX)) {
  805.         thePos = cursorPos;
  806.         while (thePos > 0) {
  807.             thePos--;
  808.             if ((theChar = file_string[thePos]) == '\n') {
  809.                 thePos = cursorPos;
  810.                 theLine = GetPrevLine(file_string, &thePos, &textPos, &spacetab[0]);
  811.                 if (strncmp(theLine, "break", 5)) {
  812.                     XtFree (file_string);
  813.                     file_string = (char *)XmTextGetString(text);
  814.                     Outdent (file_string, cursorPos, False);
  815.                 }
  816.                 else {
  817.                     if (indent_case || !InSwitch(file_string, thePos)) {
  818.                         XtFree (file_string);
  819.                         file_string = (char *)XmTextGetString(text);
  820.                         Outdent (file_string, cursorPos, False);
  821.                     }
  822.                 }
  823.                 break;
  824.             }
  825.             else if (theChar != ' ' && theChar != '\t')
  826.                 break;
  827.         }
  828.     }
  829.     XtFree (file_string);
  830. }
  831.  
  832. /*-------------------------------------------------------------
  833. **      Goto Line
  834. */
  835. void GotoString(goto_string)
  836. char    *goto_string;
  837. {
  838.     char     *file_string;
  839.     XmTextPosition cursorPos;
  840.     Arg        al[1];
  841.     int        line_number;
  842.     int        i;
  843.     long    j;
  844.     long    string_length;
  845.  
  846.     /* get the text string */
  847.     file_string = (char *)XmTextGetString(text);
  848.     j=0;
  849.     string_length = strlen (file_string);
  850.     sscanf (goto_string, "%d", &line_number);
  851.  
  852.     for (i=0; i<(line_number-1); i++) {
  853.         while (file_string[j++] != '\n') {
  854.            if (j >= string_length) {
  855.                fprintf (stderr, "\7");    /* beep if at end of file */
  856.                break;
  857.             }
  858.         }
  859.         if (j >= string_length) break;
  860.     }
  861.  
  862.     if (j < string_length) {
  863.         MoveTo((XmTextPosition)j);
  864.     }
  865.     XtFree (file_string);
  866. }
  867.  
  868. /*-------------------------------------------------------------
  869. **      MoveTo
  870. **        We needed this function because Motif1.1 seems to
  871. **        have real problems with:
  872. **            XtSetArg (al[0], XmNcursorPosition, position);
  873. **            XtSetValues (text, al, 1);
  874. **        The function:
  875. **            XmTextSetCursorPosition(text, position);
  876. **        works fine, but is unavailable in Motif1.0
  877. */
  878. void MoveTo(position)
  879. XmTextPosition    position;
  880. {
  881.     Arg al[1];
  882.     
  883. #ifdef Motif1.0
  884.     XtSetArg (al[0], XmNcursorPosition, position);
  885.     XtSetValues (text, al, 1);
  886. #else
  887.     XmTextSetCursorPosition(text, position);
  888. #endif
  889. }
  890.  
  891.