home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / DEMO / RIM22 / MACROS / C_SMART.RM < prev    next >
Text File  |  1993-12-08  |  41KB  |  1,608 lines

  1. /*
  2.  *    c_smart.rm
  3.  *
  4.  * 'C' smart indenting commands for RimStar Programmer's Editor V2.0
  5.  *
  6.  * Copyright (C) 1993 Free Software Foundation, Inc.
  7.  * Copyright (C) 1993, Brian L. Smith, K. Shane Hartman
  8.  *
  9.  * This file was ported from GNU Emacs.
  10.  *
  11.  * This file is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  *
  16.  * This file is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details (the file COPYING)
  20.  *
  21.  * If you want a copy of the GNU General Public License, write to the
  22.  * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  *
  24.  *        16 Nov 93 - Fixed bug in c_backward_to_noncomment()  causing
  25.  *                        infinite loop when preprocessor command is first
  26.  *                        non-white in file.
  27.  *        21 Nov 93 - Added _c_newline_break() to give alternate to _c_newline()
  28.  *                        this function will break the line instead of just opening a
  29.  *                        a line.
  30.  */
  31.  
  32. #include "macro.h"
  33.  
  34. extern long    IndentSize;    /* built-in editor variable */
  35.  
  36. char *comment_start;
  37. char *comment_end;
  38. short comment_column = 40;
  39.  
  40. long    matchstart = 0;
  41. long    matchend = 0;
  42. BOOL    auto_indent = 1;
  43. BOOL    Matchdelim = 0;
  44.  
  45. /* Enable much faster shortcut (most cases) for Shane's indentation style, 
  46.  * if indentation looks funny for you, set this to 0.  The full indenter
  47.  * is always correct for all settings of the variables below.
  48.  */
  49. int c_indenter_shortcut = 0;
  50.  
  51. /* Indentation of C statements with respect to containing block. */
  52. int c_indent_level = 3;
  53.  
  54. /* Imagined indentation of a C open brace that actually follows a statement. */
  55. int c_brace_imaginary_offset = 0;
  56.  
  57. /* Extra indentation for braces, compared with other text in same context. */
  58. int c_brace_offset = 0;
  59.  
  60. /* If top level braces should be indented set to 1; if you want them pulled
  61.  * back to column 1, set to 0.
  62.  */
  63. int c_indent_toplevel_brace = 0;
  64.  
  65. /* Indentation level of declarations of C function arguments.
  66.  * Note this must be 0 for the quick indenter to work.
  67.  */
  68. int c_argdecl_indent = 4;
  69.  
  70. /* Offset of C label lines relative to usual indentation. */
  71. int c_label_offset = -2;
  72.  
  73. /* Offset of C case statements relative to usual indentation. */
  74. int c_case_offset = -3;
  75.  
  76. /* Extra indent for lines not starting new statements. */
  77. int c_continued_statement_offset = 3;
  78.  
  79. /* If pre-processor statements should start at column 1 set this non-zero */
  80. int c_preproc_col_1 = 0;
  81.  
  82. /* If c_preproc_col_1 == 0 then offset # statements from current indent level */
  83. int c_preproc_offset = -1;
  84.  
  85. /* if you use a space after your open parens, set this to 2 else set it to 1
  86.  * Makes continued statements line up correctly.
  87.  */
  88. int c_paren_extra_space = 2;
  89.  
  90. /* Non-zero means TAB in C mode should always reindent the current line,
  91.  * regardless of where in the line the cursor is when the TAB command is used.
  92.  */
  93. int c_tab_always_indent = 0;
  94.  
  95.  
  96. typedef struct pstate {
  97.     long    beginning_of_defun;
  98.     long    containing_cexp;
  99.     int    incomment;
  100.     int    instring;
  101.     int    quoted;
  102.     int    level;
  103. } PSTATE;
  104.  
  105.  
  106. int  c_backward_to_start_of_do( long limit );
  107. void c_backward_to_start_of_if( long limit );
  108. void c_backward_to_noncomment( long limit );
  109. long calculate_c_indent_in_comment( void );
  110. long calculate_c_indent( PSTATE *state );
  111.  
  112. #define ARE_AT(pat) are_at(1, pat)
  113. #define INDENT_TO(indent) Indent(indent)
  114. #define SKIP_CHARS_BACKWARD(set) skip_chars (-1, (set))
  115. #define SKIP_CHARS_FORWARD(set) skip_chars (1, (set))
  116. #define FORWARD_SEXP() traverse_cexp(1)
  117. #define BACKWARD_SEXP() traverse_cexp(-1)
  118. #define SEARCH_FORWARD(str) find(1, (str))
  119. #define SEARCH_BACKWARD(str) find(-1, (str))
  120. #define AtSOL() (BufQueryColumn() == 1L)
  121. #define BEGINNING_OF_DEFUN() \
  122.     ( find_pat (-1, "^[{A-Za-z0-9$_]+[^A-Za-z0-9$_:]") ? \
  123.          (PosSOL(), 1) : (PosSOF(), 0) )
  124.  
  125. /* replace current indentation with indent to col */
  126. void
  127. Indent(long col) {
  128.     BufDeleteWhitespace();
  129.     BufIndentColumn(BufQueryColumn(), col);
  130. } /* end Indent() */
  131.  
  132.  
  133. int
  134. find(int dir, char *str) {
  135.     long    len;
  136.  
  137.     if ( dir > 0 ) {
  138.         if ( (len = SrchFwd(str, 0, 1, 0, 0L)) > 0L )
  139.             PosNextChar(len);
  140.         else
  141.             PosEOF();
  142.     } else {
  143.         if ( (len = SrchBack(str, 0, 1, 0, 0L)) < 0L )
  144.             PosSOF();
  145.     }
  146.     return len != -1L ? 1 : 0;
  147. } /* end find() */
  148.  
  149.  
  150. int
  151. find_pat(int dir, char *str) {
  152.     long    len;
  153.  
  154.     if ( dir > 0 ) {
  155.         if ( (len = SrchFwd(str, -1, 1, 0, 0L)) > 0L )
  156.             PosNextChar(len);
  157.         else
  158.             PosEOF();
  159.     } else {
  160.         if ( PosPrevChar() )
  161.             return 0;
  162.         if ( (len = SrchBack(str, -1, 1, 0, 0L)) < 0L )
  163.             PosSOF();
  164.     }
  165.     return len != -1 ? 1 : 0;
  166. } /* end find_pat() */
  167.  
  168.  
  169. void
  170. skip_chars(int dir, char *set) {
  171.     if ( dir < 0 )
  172.         PosPrevChar();    
  173.     while ( strchr(set, (BufQueryChar())) )
  174.         if ( PosNextChar((long)dir) )
  175.             break;
  176.     if ( dir < 0 )
  177.         PosNextChar();
  178. } /* end skip_chars() */
  179.  
  180.  
  181. long
  182. query_indent_of_line() {
  183.     long indent;
  184.  
  185.     MarkPushPos();
  186.     PosSOT();
  187.     indent = BufQueryColumn();
  188.     MarkPopPos();
  189.     return indent;
  190. } /* end current_indent() */
  191.  
  192.  
  193. int
  194. Srch(int dir, char *pat) {
  195.     if ( dir > 0 )
  196.         return SrchFwd(pat, -1, 1, 0, 0);
  197.     else {
  198.         if ( PosPrevChar() )
  199.             return -1;
  200.         return SrchBack(pat, -1, 1, 0, 0);
  201.     }
  202. } /* end Srch() */
  203.  
  204.  
  205. int
  206. are_at(int dir, char *pat, char *result) {
  207.       int        rc = 0;
  208.       int    len;
  209.   
  210.     matchend = BufQueryOffset();
  211.     MarkPushPos();
  212.     if ( len = Srch(dir, pat) > 0 ) {
  213.         matchstart = BufQueryOffset();
  214.         if ( matchstart == matchend )
  215.             rc = 1;
  216.         else
  217.             rc = 0;
  218.         matchend = matchstart + len;
  219.     }
  220.     MarkPopPos();
  221.       return rc;
  222. } /* end are_at() */
  223.  
  224.  
  225. int
  226. BufQueryPrevChar() {
  227.     long offset;
  228.  
  229.     if ( (offset = BufQueryOffset()) == 0L )
  230.         return 0;
  231.     return BufQueryChar(offset-1);
  232. } /* end BufQueryPrevChar() */
  233.  
  234.  
  235. char matching_punct[] = "][]}{})()\"\"''";
  236. char opening_punct[] = "[{(";
  237. char closing_punct[] = "]})";
  238.   
  239. char
  240. get_matching_punct(char c) {
  241.     char *s = strchr(matching_punct, c);
  242.  
  243.     if ( !s ) 
  244.         return 0;
  245.     else 
  246.         return s[1];
  247. }
  248.  
  249. void
  250. MovNextLine( void ) {
  251.     PosEOL();
  252.     PosNextChar();
  253. } /* end of MovNextLine */
  254.  
  255. void
  256. MovPrevLine( void ) {
  257.     PosSOL();
  258.     PosPrevChar();
  259. } /* end of MovNextLine */
  260.  
  261. #define is_opening_punct(c) (strchr(opening_punct, (c)) != NULL)
  262. #define is_closing_punct(c) (strchr(closing_punct, (c)) != NULL)
  263.  
  264. int
  265. FindStartOfDef(void) {
  266.  
  267.     if ( SrchBack("^[{A-Za-z0-9$_]+[^A-Za-z0-9$_:]", -1, 1, 0) > 0 )
  268.         return 1;
  269.     PosSOF();
  270.     return 0;
  271. } /* end FindStartOfDef() */
  272.  
  273.  
  274. int
  275. query_matching_slashes (int dir) {
  276.     long slash_count = 0;
  277.  
  278.     MarkPushPos();
  279.     if ( dir > 0 )
  280.         PosPrevChar();
  281.     while ( !PosPrevChar() && BufQueryChar() == '\\' )
  282.         slash_count++;
  283.     MarkPopPos();
  284.     return (int)(slash_count & 1);    /* returns 1 if odd number of slashes 0 if even */
  285. }
  286.  
  287. void
  288. skip_c_comments(int dir) {
  289.     long offset = 1L;
  290.     long last;
  291.     long    cp;
  292.     char c;
  293.     char cc;
  294.   
  295.     last = BufQueryFilesize();
  296.     if (dir != 1) {
  297.         dir     = -1;
  298.         offset = 0;
  299.     }
  300.     while ( find_pat(dir, "[^ \t\n\f]") &&
  301.              (cp = BufQueryOffset()) > 0  && cp < last ) {
  302.         c  = BufQueryChar(cp - offset);
  303.         cc = BufQueryChar(cp - offset + dir);
  304.      
  305.         if ( c == '/' ) {
  306.             if ( cc == '*' )
  307.                 find(dir, dir > 0 ? "*/" : "/*");
  308.             else if ( cc == '/' )    {    /* c++ comment */
  309.                 if ( dir > 0 )    {
  310.                     MovNextLine();
  311.                 } else
  312.                     PosPrevChar();
  313.             }
  314.         } else {
  315.             if ( dir > 0 )
  316.                 PosPrevChar();
  317.             break;
  318.         }
  319.     }
  320. } /* end skip_c_comment() */
  321.  
  322.  
  323. /*
  324. ** move to next/prev c expression
  325. */
  326. long
  327. traverse_cexp(int dir) {
  328.     long level  = 0L;
  329.     char c        = 0;
  330.     char start  = 0;
  331.     char end     = 0;
  332.     long offset = 1L;
  333.     char buf[2];
  334.     char patbuf[40];
  335.     long orig;
  336.  
  337.     orig = BufQueryOffset();
  338.     if ( dir != 1 ) {
  339.         dir = -1;
  340.         offset = 0;
  341.     }
  342.     if ( dir > 0 &&
  343.          orig < BufQueryFilesize() &&
  344.          strchr(":;?,", BufQueryChar())
  345.         )
  346.         PosNextChar();
  347.  
  348.     skip_c_comments(dir);
  349.  
  350.     if ( !strchr(matching_punct, c = (BufQueryChar())) ) {
  351.         if ( find_pat(dir, "[][)(}{\"';:,? \t\n\f]") ) {
  352.             if ( dir < 0 )
  353.                 PosNextChar();
  354.             else
  355.                 PosPrevChar();
  356.             return 1;
  357.         }
  358.         return 0;
  359.     } else if ((is_opening_punct(c) && dir > 0) ||
  360.                   (is_closing_punct(c) && dir < 0) ||
  361.                   c == '"' || c == '\'' )
  362.     {
  363.         if ( dir < 0 )
  364.             PosNextChar();
  365.         strcpy(patbuf, "([][)(}{\"'])|(/\\*)|(\\*/)|(//)");
  366.         while ( find_pat(dir, patbuf) ) {
  367.             buf[0] = c = BufQueryChar(BufQueryOffset() - offset);
  368.             buf[1] = 0;
  369.             if ( start == 0 ) {
  370.                 start = c;
  371.                 end = get_matching_punct(start);
  372.                 if ( !end ) 
  373.                     start = 0;
  374.                 else {
  375.                     strcpy (patbuf, "\\X|\\X|([\"'])|(/\\*)|(\\*/)|(//)");
  376.                     patbuf[1] = start;
  377.                     patbuf[4] = end;
  378.                 }
  379.             }
  380.             if ( c == '"' || c == '\'' ) { 
  381.                 char strpat[8];
  382.  
  383.                 strcpy (strpat, "\\X|\n");
  384.                 strpat[1] = c;
  385.                 while ( find_pat(dir, strpat) && query_matching_slashes(dir) )
  386.                     ;
  387.                 if ( BufQueryPrevChar() == '\n')
  388.                     break;
  389.             } else if ( c == '*' ) {
  390.                 find(dir, dir > 0 ? "*/" : "/*");
  391.             } else if ( c == '/' ) {        /* c++ comment */
  392.                 if ( dir > 0 ) {
  393.                     PosEOL();
  394.                     PosNextChar();
  395.                 }
  396.             }
  397.             if ( c == start )
  398.                 level++;
  399.             if ( c == end && !--level )
  400.                 break;
  401.         }
  402.         return ( level == 0 && start != 0 );
  403.     } else {
  404.         if ( (dir > 0 && c == ')') ||
  405.               (dir < 0 && c == '(') ) {
  406.             PosNextChar((long)dir);
  407.             return 1;
  408.         }
  409.         else
  410.             PosToOffset(orig);
  411.         return 0;
  412.     }
  413. } /* end traverse_cexp() */
  414.  
  415.  
  416. void
  417. parse_partial_cexp(long from, long to, PSTATE* state) {
  418.     char c = 0;
  419.     long stack[64];
  420.     char msg[ 64 ];
  421.     long point;
  422.   
  423.     state->instring  = 0;
  424.     state->incomment = 0;
  425.     state->containing_cexp = -1L;
  426.     state->quoted = 0;
  427.     state->level = -1;
  428.     point = from;
  429.     while ( find_pat (1, "([][(){}\"'])|(/\\*)|(//)") && ( (point = BufQueryOffset() ) < to) ) {
  430.         c = BufQueryPrevChar();
  431.         if ( is_opening_punct(c) ) {
  432.             state->level++;
  433.             if ( state->level > 63 ) {
  434.                 sprintf( msg, "Expression nesting too deep: %d:", state->level);
  435.                 PopupMsg( msg, "parse_partial_cexp" );
  436.                 abort();
  437.             }
  438.             stack[state->level] = point - 1L;
  439.         } else if ( is_closing_punct(c) ) { 
  440.             if ( state->level >= 0 &&
  441.                   get_matching_punct(BufQueryChar(stack[state->level])) == c )
  442.                 state->level--;
  443.             else if ( state->level >= 0 ) {
  444.                 PosToOffset(stack[state->level]);
  445.                 sprintf( msg, "Error: Should have found '%c' but found '%c' instead", BufQueryChar(stack[state->level]), c );
  446.                 PopupMsg( msg, "parse_partial_cexp" );
  447.                 abort();
  448.             }
  449.         } else if ( c == '"' || c == '\'' ) {        /* quotes */
  450.             char strpat[8];
  451.         
  452.             state->quoted = -1;
  453.             strcpy (strpat, "[X\n]");
  454.             strpat[1] = c;
  455.             while ( find_pat(1, strpat)          &&            /* find matching quote or end of line */
  456.                       query_matching_slashes(1) &&            /* single slashe behind it (the quote found is escaped) */
  457.                       (point = BufQueryOffset()) < to )        /* not past where we are indenting */
  458.                 ;
  459.             if ( point < to ) 
  460.                 state->quoted = 0;    /* found the matching quote */
  461.         } else if (c == '*' || c == '/') {
  462.             state->incomment =  1;
  463.             state->quoted     = -2;
  464.             if ( c == '*' ) {
  465.                 find(1, "*/");                        /* find close of comment */
  466.                 if ( BufQueryOffset() < to )
  467.                     state->incomment = state->quoted = 0;
  468.             } else {                                    /* C++ comment - go to next line */
  469.                 MovNextLine();
  470.                 state->incomment = state->quoted = 0;
  471.             }
  472.         }
  473.     }
  474.     if ( state->level >= 0 ) 
  475.         state->containing_cexp = stack[state->level];
  476. } /* end parse_partial_cexp() */
  477.  
  478.  
  479. void
  480. find_matching_delim(void) {
  481.     long        level;
  482.     long        offset;
  483.     int        c;
  484.     int        dir;
  485.     int        start, end;
  486.     char        patbuf[40];
  487.  
  488.     c = BufQueryChar();
  489.     if ( is_opening_punct(c) )    {
  490.         dir = 1;
  491.         offset = 0L;
  492.         PosNextChar();
  493.     } else if ( is_closing_punct(c) ) {
  494.         dir = -1;
  495.         offset = 1L;
  496.     } else
  497.         return;
  498.  
  499.  
  500.     level = 0L;
  501.     start = 0;
  502.     do {
  503.         if ( dir > 0 )
  504.             c = BufQueryPrevChar();
  505.         else
  506.             c = BufQueryChar();
  507.         if ( start == 0 ) {
  508.             start = c;
  509.             end = get_matching_punct(start);
  510.             if ( !end ) 
  511.                 start = 0;
  512.             else {
  513.                 strcpy (patbuf, "\\X|\\X|([\"'])|(/\\*)|(\\*/)|(//)");
  514.                 patbuf[1] = start;
  515.                 patbuf[4] = end;
  516.             }
  517.         }
  518.         if ( c == '"' || c == '\'' ) { 
  519.             char strpat[8];
  520.  
  521.             strcpy (strpat, "\\X|\n");
  522.             strpat[1] = c;
  523.             while ( find_pat(dir, strpat) && query_matching_slashes(dir) )
  524.                 ;
  525.             if ( BufQueryPrevChar() == '\n' )
  526.                 break;
  527.         } else if ( c == '*' ) {
  528.             find(dir, dir > 0 ? "*/" : "/*");
  529.         } else if ( c == '/' ) {        /* c++ comment */
  530.             if ( dir > 0 ) {
  531.                 PosEOL();
  532.                 PosNextChar();
  533.             }
  534.         }
  535.         if ( c == start )
  536.             level++;
  537.         else if ( c == end && !--level )    {
  538.             if ( dir > 0 )
  539.                 PosPrevChar();
  540.             break;
  541.         }
  542.     } while ( find_pat(dir, patbuf) );
  543. } /* end find_matching_delim() */
  544.  
  545.  
  546. /*
  547.  * Indenting functions
  548.  */
  549.  
  550. #if 0
  551. /* This will indent comments nicely but is not hooked up */
  552. long
  553. c_comment_indent() {
  554.     long ret = 0;
  555.     long save_excursion;
  556.     long opoint;
  557.  
  558.     if (ARE_AT("^/\\*"))
  559.         return 0L;            /* Existing comment at bol stays. */
  560.  
  561.     save_excursion = opoint = BufQueryOffset();
  562.     PosSOL();
  563.     if ( ARE_AT("[ \t]*}[ \t]*(\n|(/\\*))") )
  564.         /*
  565.          * A comment following a solitary close-brace 
  566.          * should have only one space. 
  567.          */
  568.     {
  569.         find(1, "}");
  570.         ret = BufQueryColumn() + 1;
  571.     }
  572.     else if ( ARE_AT("^#[ \t]*endif[ \t]*") ||
  573.                  ARE_AT("^#[ \t]*else[ \t]*") )
  574.         ret = 7;                                /* 2 spaces after #endif */
  575.     else if ( PosToOffset(opoint),
  576.                  skip_chars(-1, " \t"),
  577.                  !comment_column && AtSOL() )
  578.         /*
  579.          * If comment_column is 0, and nothing but space
  580.          * before the comment, align it at 0 rather than 1. 
  581.          */
  582.         ret = 0;
  583.     else {
  584.         ret = BufQueryColumn() + 1;     /* Else indent at comment column */
  585.         if ( comment_column > ret ) 
  586.             ret = comment_column;            /* except leave at least one space. */
  587.     }
  588.     PosToOffset(save_excursion);
  589.     return ret;
  590. } /* end c_comment_indent() */
  591. #endif
  592.  
  593.  
  594. /* 
  595.  * Indent current line as C code. This does the work.
  596.  */
  597.  
  598. long
  599. c_indenter_1( PSTATE *state ) {
  600.     long indent;
  601.     long pos;
  602.     long startPos;
  603.     long size = BufQueryFilesize();
  604.     int  ch;
  605.  
  606.     startPos = BufQueryOffset();
  607.     if ( startPos == size ) {    /* at EOF */
  608.         /* 
  609.          * So that indenting in a brand new file works correctly
  610.          * when there are no characters after the indent point.
  611.          */
  612.         BufInsertNewline();    /* BufInsertChar( '\n' ); */
  613.         PosPrevChar();
  614.         ++size;
  615.     }
  616.     pos = size - startPos;
  617.     indent = calculate_c_indent(state);
  618.     PosSOL();
  619.     if ( indent == -1 )                                        /* do not change indent */
  620.         indent = query_indent_of_line();
  621.     else if ( indent == -2 )                                /* in a comment */
  622.         indent = calculate_c_indent_in_comment ();
  623.     else if ( ARE_AT("[ \t]*#") )    {                        /* a preprocessor line */
  624.         if ( c_preproc_col_1 )
  625.             indent = 0L;
  626.         else
  627.             indent += c_preproc_offset;
  628.     } else {
  629.         startPos = BufQueryOffset();
  630.         skip_chars(1, " \t");
  631.         if ( ARE_AT("(case[ \t'(])|(default:)") ) {    /* case or default */
  632.             if ( state->containing_cexp >= 0 ) {
  633.                 PosToOffset( state->containing_cexp );
  634.                 indent = query_indent_of_line() + c_case_offset + c_indent_level;
  635.                 if ( indent < 0L )
  636.                     indent = 0L;
  637.                 PosToOffset( startPos );
  638.             }
  639.         } else if ( ARE_AT("[A-Za-z0-9$_]+:") ) {        /* a label */
  640.             indent += c_label_offset;
  641.             if ( indent < 0L )
  642.                 indent = 0L;
  643.         } else if ( ARE_AT("else[ \t\n]") ) {            /* else followed by whitespace */
  644.             c_backward_to_start_of_if(state->beginning_of_defun);
  645.             indent = query_indent_of_line();
  646.             PosToOffset( startPos );
  647.         } else if ( ARE_AT("}[ \t]*else") ) {            /* cbrace followed by else */
  648.             PosNextChar();                              /* move past brace */
  649.             traverse_cexp(-1);
  650.             indent = query_indent_of_line();
  651.             PosToOffset( startPos );
  652.         } else if ( ARE_AT("while[ \t\n]") ) {            /* `while' statement */
  653.             if ( c_backward_to_start_of_do(state->beginning_of_defun) ) {
  654.                 /* This is a `while' that ends a do-while. */
  655.                 indent = query_indent_of_line();
  656.                 PosToOffset( startPos );
  657.             } else
  658.                 goto next;
  659.         } else {
  660.          next:
  661.             ch = BufQueryChar();
  662.             if ( ch == '}' )
  663.                 indent -= c_indent_level - c_brace_offset;
  664.             else if ( ch == '{' )
  665.                 indent += c_brace_offset;
  666.         }
  667.     }
  668.     PosSOT();
  669.     if ( !c_indenter_shortcut ) {
  670.         ch = BufQueryChar();
  671.         if (ch == '{'         &&
  672.              c_brace_offset &&
  673.              state->containing_cexp <= 0L ) {
  674.             if ( c_indent_toplevel_brace )
  675.                 ++indent;                        /* Indent top level braces */
  676.             else
  677.                 indent -= c_brace_offset;    /* Pull top level brace back a level */
  678.         } else if ( ch == '}' ) {
  679.             startPos = BufQueryOffset();
  680.             PosToOffset( state->containing_cexp );
  681.             if ( AtSOL() )
  682.                 indent = 0;
  683.             PosToOffset( startPos );
  684.         }
  685.     }
  686.     if ( BufQueryColumn() != indent )
  687.         Indent(indent);
  688.     /* 
  689.      * If initial point was within line's indentation,
  690.      * position after the indentation.  Else stay at same point in text. 
  691.      */
  692.     size = BufQueryFilesize();
  693.     if ( size - pos > BufQueryOffset() )
  694.         PosToOffset( size - pos );
  695.     return indent;
  696. } /* end c_indenter_1() */
  697.  
  698.  
  699. int
  700. c_indenter( void ) {
  701.   PSTATE state;
  702.   
  703.   state.beginning_of_defun = -1;
  704.   return c_indenter_1( &state );
  705. }
  706.  
  707.  
  708. void
  709. c_backward_to_exp_start( long lim ) {
  710.  
  711.   if ( strchr( ")\"", BufQueryPrevChar()) )
  712.      traverse_cexp(-1);
  713.   PosSOL();
  714.   if ( BufQueryOffset() <= lim )
  715.      PosToOffset( lim + 1 );
  716.   skip_chars(1, " \t");
  717. }
  718.  
  719.  
  720. /*
  721.  * If point follows a `do' statement, move to beginning of it and return t.
  722.  * Otherwise return nil and don't move point.
  723.  */
  724. int
  725. c_backward_to_start_of_do( long limit ) {
  726.     long save_excursion;
  727.  
  728.     if ( limit < 0 ) {
  729.       #if 0
  730.         save_excursion = BufQueryOffset();
  731.         FindStartOfDef();
  732.         limit = BufQueryOffset();
  733.         PosToOffset(save_excursion);
  734.       #else
  735.         limit = 0;
  736.       #endif     
  737.     }
  738.     {
  739.         long first = 1;
  740.         long startpos = BufQueryOffset();
  741.         long done = 0;
  742.  
  743.         while ( !done ) {
  744.             c_backward_to_noncomment( limit );
  745.             if ( !traverse_cexp(-1) )
  746.                 done = 2;
  747.             else if ( ARE_AT( "do[^A-Za-z0-9_$]" ) )
  748.                 done = 1;
  749.             /* 
  750.              * Otherwise, if we skipped a semicolon, we lose.
  751.              * (Exception: we can skip one semicolon before getting
  752.              * to the last token of the statement, unless that token
  753.              * is a close brace).
  754.              */
  755.             else {
  756.                 save_excursion = BufQueryOffset();
  757.                 if ( traverse_cexp(1) ) {
  758.                     if (!first && BufQueryPrevChar() == '}')
  759.                         done = 2;
  760.                     if (!done && BufQueryChar() == ';' && BufQueryPrevChar() == '}')
  761.                         done = 2;
  762.                     if (!done && BufQueryChar() == ';') {
  763.                         if (first) {
  764.                             if ( BufQueryPrevChar() == ')' && traverse_cexp(-1) ) {
  765.                                 if (traverse_cexp(-1) && 
  766.                                      ARE_AT("while") && 
  767.                                      c_backward_to_start_of_do(limit))
  768.                                     continue;
  769.                             }
  770.                         }
  771.                         if (!first) 
  772.                             done = 2;
  773.                         first = 0;
  774.                     }
  775.                     PosToOffset(save_excursion);
  776.                 }
  777.             }
  778.             /* If we go too far back in the buffer, we lose. */
  779.             if ( BufQueryOffset() < limit && !done)
  780.                 done = 2;
  781.         }
  782.         if (done != 1)
  783.             PosToOffset( startpos );
  784.         return done == 1;
  785.     }
  786. } /* c_backward_to_start_of_do() */
  787.  
  788.  
  789. /* Move to the start of the last "unbalanced" `if'. */
  790. void
  791. c_backward_to_start_of_if( long limit ) {
  792.     if ( limit < 0 ) {
  793.       #if 0
  794.         long save_excursion = BufQueryOffset();
  795.      
  796.         FindStartOfDef();
  797.         limit = BufQueryOffset();
  798.         PosToOffset(save_excursion);
  799. #else
  800.         limit = 0;
  801. #endif
  802.     }
  803.     {
  804.         long if_level = 1;
  805.      
  806.         while ( BufQueryOffset() > 0 && if_level > 0 ) {
  807.             if ( !traverse_cexp(-1) ) {
  808.                 /* not bracketed if */
  809.                 if ( if_level != 1 ) {
  810.                     PopupMsg( "Syntax error", "c_backward_to_start_of_if" );
  811.                     abort();
  812.                 }
  813.                 return;
  814.             }
  815.             if ( ARE_AT("else[^A-Za-z0-9$_]") )
  816.                 if_level++;
  817.             else if ( ARE_AT("if[^A-Za-z0-9$_]") )
  818.                 if_level--;
  819.             else if ( BufQueryOffset() < limit ) {
  820.                 if_level = 0;
  821.                 PosToOffset(limit);
  822.             }
  823.         }
  824.     }
  825. } /* end c_backward_to_start_of_if() */
  826.  
  827.  
  828. void
  829. c_backward_to_noncomment( long lim ) {
  830.     long opoint = 0L;
  831.     long last_point = -1L;
  832.     long stop = 0L;
  833.   
  834.     if ( lim < 0L )
  835.         lim = 0L;
  836.     while ( !stop ) {
  837.         skip_chars(-1, " \t\n\f");
  838.         opoint = BufQueryOffset();
  839.         if ( BufQueryOffset() >= 2L + lim ) {
  840.             PosPrevChar( 2L );
  841.             if (ARE_AT("\\*/")) {
  842.                 if ( !find(-1, "/*") )
  843.                     PosToOffset( lim > 0L ? lim : 0L );
  844.                 continue;
  845.             }
  846.             PosNextChar( 2L );
  847.         }
  848.  
  849.         if ( BufQueryOffset() <= lim || last_point == opoint )
  850.             stop = 1;
  851.         else {
  852.             PosSOL();
  853.             skip_chars(1, " \t");
  854.             if ( BufQueryChar() != '#' && !ARE_AT( "//" ) ) {
  855.                 PSTATE ps;
  856.                 long from = BufQueryOffset();
  857.                 long to;
  858.           
  859.                 PosEOL();
  860.                 to = BufQueryOffset();
  861.                 PosToOffset( from );
  862.                 parse_partial_cexp(from, to, &ps);
  863.                 if ( ps.incomment && are_at (-1, "//.*") )
  864.                     PosToOffset(matchstart);
  865.                 else
  866.                     stop = 1;
  867.             }
  868.             PosToOffset(opoint);
  869.             if ( !stop ) {
  870.                 PosSOL();
  871.                 last_point = opoint;
  872.             }
  873.         }
  874.     }
  875. } /* end c_backward_to_noncomment() */
  876.  
  877.  
  878. /*
  879.  * Return the indentation amount for line inside a block comment.
  880.  */
  881. long
  882. calculate_c_indent_in_comment( void ) {
  883.       long indent = 0;
  884.     long save_excursion = BufQueryOffset();
  885.   
  886.     PosSOL();
  887.     if ( BufQueryOffset() > 0 ) {
  888.         skip_chars(-1, " \t\n");
  889.         PosSOL();
  890.         skip_chars(1, " \t");
  891.         indent = BufQueryColumn();
  892.         if ( ARE_AT("/\\*") )
  893.             indent++;
  894.     }
  895.     PosToOffset( save_excursion );
  896.     return indent;
  897. }
  898.  
  899.  
  900. /*
  901.  * This lookback parser was not part of the original code.  I added it
  902.  * to speed the beast up in most cases.  It works for my indentation style;
  903.  * it may not work for yours since it makes more assumptions than the
  904.  * general indenter.  It is disabled by default, set the variable
  905.  * c-indenter-shortcut to 1 if you want to try it out.  It is much faster
  906.  * if you indent like the style in this file but it WILL misindent code
  907.  * that does not use braces for cues in complicated code.  The general
  908.  * indenter can handle everything.
  909.  */
  910. int
  911. calculate_simple_c_indent(long indent_point) {
  912.     long save_excursion;
  913.     long lim;
  914.     long ret = -1;
  915.  
  916.     save_excursion = BufQueryOffset();
  917.     lim = save_excursion - 512;
  918.     if ( !c_indenter_shortcut )
  919.         return -1;
  920.     if ( lim < 0 )
  921.         lim = -1;
  922.     PosToOffset(indent_point);
  923.     PosSOT();
  924.     indent_point = BufQueryOffset();
  925.     if ( BufQueryChar() == '}' ) {
  926.         PosNextChar();
  927.         if ( traverse_cexp(-1) ) {
  928.             long save_excursion_1 = BufQueryOffset();
  929.  
  930.             PosSOT ();
  931.             if ( BufQueryOffset() == save_excursion_1 )
  932.                 ret = BufQueryColumn() - c_brace_offset + c_indent_level;
  933.         }
  934.         goto finish;
  935.     }
  936.     c_backward_to_noncomment(lim);
  937.     if ( BufQueryOffset() > 0 ) {
  938.         if ( BufQueryPrevChar() == '{') {
  939.             long save_excursion_1 = BufQueryOffset();
  940.  
  941.             PosPrevChar();
  942.             c_backward_to_noncomment(lim);
  943.             if ( BufQueryPrevChar() == ')' )
  944.                 c_backward_to_exp_start(lim);
  945.             else {
  946.                 PosToOffset(save_excursion_1);
  947.                 PosSOT ();
  948.             }
  949.             ret = BufQueryColumn() + c_indent_level;
  950.             if ( BufQueryChar() == '{' )
  951.                 ret -= c_brace_offset;
  952.         }
  953.         else if ( BufQueryPrevChar() == '}' ) {
  954.             PosSOT ();
  955.             ret = BufQueryColumn() - c_brace_offset;
  956.         } else if ( BufQueryPrevChar() == ')' ) {
  957.             long save_excursion_1;
  958.  
  959.             c_backward_to_exp_start(lim);
  960.             save_excursion_1 = BufQueryOffset();
  961.             if ( ARE_AT("((if)|(else)|(else[ \t]+if)|(switch)|(for))[ \t\n(]") ) {
  962.                 PosToOffset(matchend);
  963.                 if ( traverse_cexp(1) && BufQueryOffset() <= indent_point ) {
  964.                     PosToOffset(save_excursion_1);
  965.                     ret = BufQueryColumn();
  966.                     PosToOffset(indent_point);
  967.                     if ( BufQueryChar() != '{' )
  968.                         ret += c_indent_level;
  969.                 }
  970.                 else
  971.                     PosToOffset(save_excursion_1);
  972.             } else
  973.                 PosToOffset(save_excursion_1);
  974.         } else if (BufQueryPrevChar() == ';') {
  975.             PosPrevChar();
  976.             c_backward_to_exp_start(lim);
  977.             if (!ARE_AT("for[ \t\n(]")) {
  978.                 long save_excursion_1 = BufQueryOffset();
  979.  
  980.                 skip_c_comments(-1);
  981.                 if ( BufQueryChar() == ';' ) {
  982.                     PosToOffset(save_excursion_1);
  983.                     ret = query_indent_of_line();
  984.                 } else if ( strchr("{}", BufQueryChar()) ) {
  985.                     PosToOffset(save_excursion_1);
  986.                     ret = query_indent_of_line();
  987.                 } else {
  988.                     PosSOT();
  989.                     if ( ARE_AT("((else)|(if)|(for)|(while)|(switch))[ \t\n(]") )
  990.                         ret = BufQueryColumn();
  991.                     else if ( ARE_AT("(case[ \t'(])|(default:)") )
  992.                         ret = BufQueryColumn() + c_indent_level - c_case_offset;
  993.                 }
  994.                 PosToOffset(indent_point);
  995.                 if ( ARE_AT("(case[ \t'(])|(default:)") )
  996.                     ret -= c_indent_level;
  997.             }
  998.         } else if ( BufQueryPrevChar() == ':' ) {
  999.             PosSOT();
  1000.             if ( ARE_AT("(case[ \t'(])|(default:)") ) {
  1001.                 ret = BufQueryColumn() + c_indent_level;
  1002.                 PosToOffset(indent_point);
  1003.                 if ( ARE_AT("(case[ \t'(])|(default:)") )
  1004.                     ret -= c_indent_level;
  1005.                 else if ( BufQueryChar() == '{' )
  1006.                     ret -= c_case_offset + c_indent_level;
  1007.             }
  1008.         }
  1009.     }
  1010.  finish:
  1011.     if ( ret >= 0 ) {
  1012.         PosToOffset(indent_point);
  1013.         if ( ARE_AT("(case[ \t'(])|(default:)") )
  1014.             ret += c_case_offset;
  1015.     }
  1016.     PosToOffset(save_excursion);
  1017.     return ret;
  1018. } /* end calculate_simple_c_indent() */
  1019.  
  1020.  
  1021. /*
  1022.  * Return appropriate indentation for current line as C code.
  1023.  * In usual case returns an integer: the column to indent to.
  1024.  * Returns -1 if line starts inside a string, -2 if in a comment.
  1025.  */
  1026. long
  1027. calculate_c_indent(PSTATE *state) {
  1028.     long        startPos;
  1029.     long        savePos;
  1030.     long        found;
  1031.     long        colon_line_end;
  1032.     long        indent_point      =  0L;
  1033.     long        parse_start      =  0L;
  1034.     long        containing_cexp = -1L;
  1035.     long        ret                  =  0L;
  1036.     PSTATE    ps;
  1037.     int        stop = 0;
  1038.     char        c;
  1039.  
  1040.     startPos = BufQueryOffset();
  1041.     if ( !state ) {
  1042.         state = &ps;
  1043.         state->beginning_of_defun = -1L;
  1044.     }
  1045.     state->containing_cexp = -1L;
  1046.     PosSOL();
  1047.     if ( BufQueryOffset() > 0L ) {    /* Not at SOF */
  1048.         indent_point = BufQueryOffset();
  1049.         if ( c_indenter_shortcut )    {
  1050.             ret = calculate_simple_c_indent(indent_point);
  1051.             if ( ret >= 0 )
  1052.                 goto finish;
  1053.         }
  1054.         if ( state->beginning_of_defun == -1 ) {
  1055.             FindStartOfDef();
  1056.             state->beginning_of_defun = BufQueryOffset();
  1057.         }
  1058.         PosToOffset(state->beginning_of_defun);
  1059.         ret = 0L;
  1060.         do {
  1061.             parse_start = BufQueryOffset();
  1062.             parse_partial_cexp(parse_start, indent_point, state);
  1063.         } while ( BufQueryOffset() < indent_point );
  1064.         containing_cexp = state->containing_cexp;
  1065.         if ( state->incomment && ARE_AT("[ \t]*//") ) {    /* at start of C++ comment? */
  1066.             state->quoted = 0L;
  1067.             state->incomment = 0L;
  1068.         }
  1069.         if ( state->instring || state->incomment ) {
  1070.             /* return -1 or -2 if should not change this line */
  1071.             ret = state->quoted;
  1072.         } else if ( containing_cexp < 0L ) {
  1073.             /* Line is at top level.  May be data or function definition,
  1074.              * or may be function argument declaration.
  1075.              * Indent like the previous top level line
  1076.              * unless that ends in a closeparen without semicolon,
  1077.              * in which case this line is the first argument decl.
  1078.              */
  1079.             PosToOffset(indent_point);
  1080.             skip_chars(1, " \t");
  1081.             if ( BufQueryChar() == '{' )
  1082.                 ret = 0L;                                /* Unless it starts a function body */
  1083.             else if ( c_argdecl_indent > 0 ) {    /* Handle *ix style arglist */
  1084.                 c_backward_to_noncomment(parse_start > 0L ? parse_start : 0L);
  1085.                 /* 
  1086.                  * look at previous line that's at column 0
  1087.                  * to determine whether we are in top-level decls
  1088.                  * or function's arg decls.
  1089.                  */
  1090.                 find_pat(-1, "^[^ \f\t\n#]");            /* beginning of line no whitespace or preprocessor statements */
  1091.                 if ( ARE_AT("[A-Za-z0-9$_]+[^\"\n=]*\\(") ) {
  1092.                     PosToOffset( matchend-1L );
  1093.                     traverse_cexp(1);
  1094.                     skip_chars(1, " \t\f");
  1095.                     if ( BufQueryOffset() < indent_point &&
  1096.                          !strchr(",;", BufQueryChar()) )
  1097.                         ret = c_argdecl_indent;
  1098.                 }
  1099.             }
  1100.         } else if ( BufQueryChar(containing_cexp) != '{' ) {
  1101.             /*
  1102.              * line is expression, not statement:
  1103.              * indent to just after the surrounding open.
  1104.              */
  1105.             PosToOffset( containing_cexp + c_paren_extra_space );
  1106.             ret = BufQueryColumn();
  1107.         } else {
  1108.             /* 
  1109.              * Statement level.  Is it a continuation or a new statement
  1110.              * Find previous non-comment character.
  1111.              */
  1112.             PosToOffset(indent_point);
  1113.             c_backward_to_noncomment(containing_cexp);
  1114.             /* 
  1115.              * Back up over label lines, since they don't
  1116.              * affect whether our line is a continuation.
  1117.              */
  1118.             while ( (c = BufQueryPrevChar()) == ',' ||
  1119.                      ( c == ':' && ( (c = BufQueryChar(BufQueryOffset()-2)) == '\'' || iscsym(c) ) )
  1120.                      ) {
  1121.                 if ( BufQueryChar() == ',' ) {
  1122.                     PosPrevChar();
  1123.                     c_backward_to_exp_start(containing_cexp);
  1124.                 }
  1125.                 PosSOL();
  1126.                 c_backward_to_noncomment(containing_cexp);
  1127.             }
  1128.             /* 
  1129.              * Check for a preprocessor statement or its continuation lines.
  1130.              * Move back to end of previous non-preprocessor line.
  1131.              */
  1132.             found = BufQueryOffset();
  1133.             stop  = 0;
  1134.             while ( !stop ) {
  1135.                 savePos = BufQueryOffset();
  1136.  
  1137.                 if ( savePos > 0L )
  1138.                     PosEOL();
  1139.                 if ( BufQueryPrevChar() != '\\' ) {
  1140.                     PosToOffset(savePos);
  1141.                     /* 
  1142.                      * This line is not preceded by a backslash.
  1143.                      * So either it starts a preprocessor command
  1144.                      * or any following continuation lines
  1145.                      * should not be skipped.
  1146.                      */
  1147.                     PosSOT();
  1148.                     if ( BufQueryChar() == '#' ) {
  1149.                         PosEOL();
  1150.                         found = BufQueryOffset();
  1151.                     } else
  1152.                         stop = 1;
  1153.                 } else
  1154.                     MovPrevLine();
  1155.             }
  1156.             PosToOffset(found);
  1157.             /* Now we get the answer. */
  1158.             savePos = BufQueryOffset();
  1159.             PosToOffset(indent_point);
  1160.             skip_chars(1, " \t");
  1161.             /*
  1162.              * Don't treat a line with a close-brace
  1163.              * as a continuation.  It is probably the
  1164.              * end of an enum type declaration.
  1165.              */
  1166.             if ( BufQueryChar() != '}' ) {
  1167.                 PosToOffset(savePos);
  1168.                 if ( BufQueryOffset() > 0 && !strchr(",;{}", BufQueryPrevChar()) ) {
  1169.                     /*
  1170.                      * This line is continuation of preceding line's statement
  1171.                      * indent c_continued_statement_offset more than the
  1172.                      * previous line of the statement.
  1173.                      */
  1174.                     c_backward_to_exp_start(containing_cexp);
  1175.                     ret = BufQueryColumn();
  1176.                     PosToOffset(indent_point);
  1177.                     skip_chars(1, " \t");
  1178.                     if ( BufQueryChar() !=  '{' )
  1179.                         ret += c_continued_statement_offset;
  1180.                 } else
  1181.                     goto new_statement;
  1182.             } else {
  1183.              new_statement:            
  1184.                 /* 
  1185.                  * This line starts a new statement.
  1186.                  * Position following last unclosed open.
  1187.                  */
  1188.                 PosToOffset(containing_cexp);
  1189.                 /*
  1190.                  * Is line first statement after an open-brace or after a case.
  1191.                  * If no, find that first statement and indent like it. 
  1192.                  */
  1193.                 PosNextChar();
  1194.                 colon_line_end = 0L;
  1195.                 skip_chars(1, " \t\n");
  1196.                 while ( ARE_AT( "#|(/\\*)|(case[ \t\n'(].*:)|([a-zA-Z0-9_$]*:)" ) ) {
  1197.                     /* Skip over comments and labels following openbrace. */
  1198.                     if ( (c = BufQueryChar()) == '#' )
  1199.                         MovNextLine(); 
  1200.                     else if ( c == '/') {
  1201.                         PosToOffset(BufQueryOffset()+2L);
  1202.                         find(1, "*/");
  1203.                     } else {
  1204.                         /* case or label: */
  1205.                         savePos = BufQueryOffset();
  1206.                         PosEOL();
  1207.                         colon_line_end = BufQueryOffset();
  1208.                         PosToOffset(savePos);
  1209.                         find(1, ":");
  1210.                     }
  1211.                     skip_chars(1, " \t\n");
  1212.                 }
  1213.                 /* 
  1214.                  * The immediately following code counts
  1215.                  * if it is before the line we want to indent.
  1216.                  */
  1217.                 savePos = BufQueryOffset();
  1218.                 if ( savePos < indent_point &&
  1219.                      colon_line_end > 0L     &&
  1220.                      colon_line_end < indent_point ) {
  1221.                     if ( colon_line_end > savePos )
  1222.                         ret = query_indent_of_line() - c_label_offset;
  1223.                     else if ( colon_line_end > 0L &&
  1224.                                 colon_line_end > containing_cexp) {
  1225.                         PosToOffset(colon_line_end);
  1226.                         PosSOT();
  1227.                         if ( ARE_AT("(case[ \t'(])|(default:)") ) {
  1228.                             ret = BufQueryColumn();
  1229.                             PosToOffset(indent_point);
  1230.                             skip_chars(1, " \t");
  1231.                             if ( ! ARE_AT("[{}]") )
  1232.                                 ret += c_indent_level;
  1233.                             else
  1234.                                 ret -= (c_case_offset + c_brace_offset);
  1235.                             PosToOffset(savePos);
  1236.                         } else {
  1237.                             PosToOffset(savePos);
  1238.                             ret = BufQueryColumn();
  1239.                         }
  1240.                                 } else
  1241.                                     goto no_previous;
  1242.                      } else {
  1243.                       no_previous:
  1244.                          /*
  1245.                           * If no previous statement,
  1246.                           * indent it relative to line brace is on (or the last case
  1247.                           * statement).  For open brace in column zero, don't let
  1248.                           * statement start there too.  If c_indent_level is zero,
  1249.                           * use c_brace_offset + c_continued_statement_offset instead.
  1250.                           * For open-braces not the first thing in a line,
  1251.                           * add in c_brace_imaginary_offset.
  1252.                           */
  1253.                          PosToOffset(containing_cexp);
  1254.                          if ( AtSOL() && !c_indent_level )
  1255.                              ret = c_brace_offset + c_continued_statement_offset;
  1256.                          else if ( AtSOL() )
  1257.                              ret = c_indent_level;
  1258.                          else
  1259.                              ret = c_indent_level - c_brace_offset;
  1260.                          /*
  1261.                           * Move back over whitespace before the openbrace.
  1262.                           * If openbrace is not first nonwhite thing on the line,
  1263.                           * add the c_brace_imaginary_offset.
  1264.                           */
  1265.                          skip_chars(-1, " \t");
  1266.                          if ( !AtSOL() )
  1267.                              ret += c_brace_imaginary_offset;
  1268.                          /*
  1269.                           * If the openbrace is preceded by a parenthesized exp,
  1270.                           * move to the beginning of that;
  1271.                           * possibly a different line. 
  1272.                           */
  1273.                          if ( BufQueryPrevChar() == ')' )
  1274.                              traverse_cexp(-1);
  1275.                          /* Get initial indentation of the line we are on. */
  1276.                          ret += query_indent_of_line();
  1277.                      }
  1278.             }
  1279.         }
  1280.     }
  1281.  finish:
  1282.     PosToOffset(startPos);
  1283.     return ret;
  1284. } /* end calculate_c_indent() */
  1285.  
  1286.  
  1287. /*
  1288. ** This function does not work on all styles
  1289. ** of function beginnings, therefore it is not
  1290. ** being used.
  1291. */
  1292. void
  1293. beginning_of_defun() {
  1294.     long    last;
  1295.     char    c, cp;
  1296.  
  1297.     last = BufQueryOffset();
  1298.  
  1299.     while ( FindStartOfDef() ) {
  1300.         long save_excursion;
  1301.         long next;
  1302.  
  1303.         next = BufQueryOffset();
  1304.         if ( BufQueryChar() == '{') {
  1305.             while ( BufQueryOffset() > 0 ) {
  1306.                 MovPrevLine();
  1307.                 save_excursion = BufQueryOffset();
  1308.                 PosSOL();
  1309.                 next = BufQueryOffset();
  1310.                 skip_chars(1, " \t");
  1311.                 if ( BufQueryOffset() == save_excursion ) {
  1312.                     MovNextLine();
  1313.                     break;
  1314.                 }
  1315.                 PosToOffset(next);
  1316.                 if ( ARE_AT("#|(.*\\*/)|(//)") ) {
  1317.                     MovNextLine();
  1318.                     break;
  1319.                 }
  1320.             }
  1321.             break;
  1322.         }
  1323.         skip_c_comments(-1);
  1324.         save_excursion = BufQueryOffset();
  1325.         PosSOL();
  1326.         if ( BufQueryChar() == '#' ) {
  1327.             PosToOffset(next);
  1328.             break;
  1329.         }
  1330.         PosEOL();
  1331.         if ( (c = BufQueryPrevChar()) == '\\' ) {
  1332.             PosToOffset(next);
  1333.             break;
  1334.         } else if ( c == '{' || BufQueryChar() == '{' ) {
  1335.             PosSOL();
  1336.             break;
  1337.         }
  1338.         last = next;
  1339.         PosToOffset(save_excursion);
  1340.         c  = BufQueryChar();
  1341.         cp = BufQueryPrevChar();
  1342.         if ( c == '}'    ||
  1343.              ( c == ';'                    &&
  1344.               save_excursion > 0L    &&
  1345.               ( cp == '}' || cp == ')' ||
  1346.                 (traverse_cexp(-1), 
  1347.                  skip_c_comments (-1), 
  1348.                  BufQueryChar() == '='
  1349.                  )
  1350.                 )
  1351.               )
  1352.              ) {
  1353.             PosToOffset(last);
  1354.             break;
  1355.         }
  1356.         if ( BufQueryOffset() == 0L )
  1357.             break;
  1358.         PosEOL();
  1359.         PosNextChar();
  1360.     }
  1361. } /* end beginning_of_defun() */
  1362.  
  1363.  
  1364. /*
  1365.  * Commands
  1366.  */
  1367.  
  1368. /* make this the default mode for .c, .cpp, .h, .e, and .y files */
  1369.  
  1370. void
  1371. _c_indent() {    /* on Tab key */
  1372.     long lastPos;
  1373.  
  1374.     if ( MarkQuerySelType() ) {
  1375.         slide_in();
  1376.         return;
  1377.     }
  1378.     if ( !c_tab_always_indent ) {
  1379.         lastPos = BufQueryOffset();
  1380.         /* If not in leading whitespace, do a tab */
  1381.         skip_chars(-1, " \t");
  1382.         if ( !AtSOL() ) {
  1383.             PosToOffset(lastPos);
  1384.             BufInsertChar('\t');
  1385.             return;
  1386.         }
  1387.         PosToOffset(lastPos);
  1388.     }
  1389.     c_indenter();
  1390. } /* end _c_indent() */
  1391.  
  1392.  
  1393. /* _c_newline_break - reindents current line, breaks the line, and
  1394.  *        indents to proper position
  1395.  */
  1396. void
  1397. _c_newline_break() {                    /* on Keypad+Enter */
  1398.     if ( auto_indent ) {
  1399.         BufNewlineIndent();
  1400.         c_indenter();
  1401.     } else
  1402.         BufInsertNewline();
  1403. } /* end _c_newline_break() */
  1404.  
  1405.  
  1406. /* _c_newline - reindents current line, opens a new line below, and
  1407.  *        indents to proper position in the new line
  1408.  */
  1409. void
  1410. _c_newline() {                    /* on Enter */
  1411.     if ( auto_indent ) {
  1412.         PosSOT();
  1413.         /* May need to update indenting on current line */
  1414.         if ( ARE_AT("#|((case)|(else))|([A-Za-z0-9$_]+:)|(while[ \t]*\\(.*\\)[ \t]*;)") )
  1415.             c_indenter();
  1416.         PosEOL();
  1417.         BufInsertNewline();
  1418.         c_indenter();
  1419.     } else
  1420.         BufInsertNewline();
  1421. } /* end _c_newline() */
  1422.  
  1423.  
  1424. void
  1425. _c_open() {    /* on '{' */
  1426.     BufInsertChar( '{' );
  1427.     if ( auto_indent )
  1428.         c_indenter();
  1429. } /* end _c_open() */
  1430.  
  1431.  
  1432. void
  1433. _c_close() {    /* on '}' */
  1434.     BufInsertChar( '}' );
  1435.     if ( auto_indent )
  1436.         c_indenter();
  1437. #if 0
  1438.     if ( Matchdelim )
  1439.         find_delimiter();
  1440. #endif
  1441. } /* end _c_close() */
  1442.  
  1443.  
  1444. void
  1445. _c_forward_cexp() {    /* on ALT+CTRL+F */
  1446.     long start;
  1447.     long last;
  1448.   
  1449.     start = BufQueryOffset();
  1450.     if ( !traverse_cexp(1) ) {
  1451.         PosToOffset(start);
  1452.         abort();
  1453.     }
  1454.     last  = BufQueryFilesize();
  1455.     while (strchr (",:;\\", BufQueryChar()) &&
  1456.              BufQueryOffset() < last )
  1457.       PosNextChar();
  1458. }
  1459.  
  1460.  
  1461. void
  1462. _c_backward_cexp() {            /* on Alt+Ctrl+B */
  1463.     long start;
  1464.  
  1465.     start = BufQueryOffset();
  1466.  
  1467.     while ( BufQueryOffset() > 0 &&
  1468.              strchr(",:;\\ \t\n\f", BufQueryPrevChar()) )
  1469.         PosPrevChar();
  1470.     if ( !traverse_cexp(-1) ) {
  1471.         PosToOffset(start);
  1472.         abort();
  1473.     }
  1474. } /* end _c_backward_cexp() */
  1475.  
  1476.  
  1477. void
  1478. _c_start_of_func() {        /* on Alt+Ctrl+A */
  1479.     FindStartOfDef();
  1480.     WinScrollTop();
  1481. }
  1482.  
  1483.  
  1484. void
  1485. _c_end_of_func() {        /* on Alt+Ctrl+E */
  1486.     long orig;
  1487.  
  1488.     orig = BufQueryOffset();
  1489.   
  1490.     traverse_cexp(1);
  1491.     PosNextChar();
  1492.     if ( FindStartOfDef() ) {
  1493.       while ( traverse_cexp(1) && BufQueryPrevChar() != '}' )
  1494.           ;
  1495.       if ( BufQueryPrevChar() != '}' )
  1496.           PosToOffset(orig);
  1497.       else if ( BufQueryChar() == ';' )
  1498.           PosNextChar();
  1499.     }
  1500. } /* end _c_end_of_func() */
  1501.  
  1502.  
  1503. void
  1504. _c_up_level() {    /* on ALT+CTRL+U */
  1505.     PSTATE state;
  1506.     long orig;
  1507.  
  1508.     orig = BufQueryOffset();
  1509.  
  1510.     FindStartOfDef();
  1511.     while ( BufQueryOffset() <= orig ) {
  1512.         parse_partial_cexp(BufQueryOffset(), orig + 1, &state);
  1513.     }
  1514.     if ( state.containing_cexp >= 0 )
  1515.         PosToOffset(state.containing_cexp);
  1516.     else {
  1517.         PosToOffset(orig);
  1518.         PopupMsg("No containing C expression", "up_level");
  1519.         return;
  1520.         /* should do abort() */
  1521.     }
  1522. } /* end _c_up_level() */
  1523.  
  1524.  
  1525. /*
  1526.  * Note: this function can take quite a bit of time
  1527.  * to do it's job.
  1528.  */
  1529. void
  1530. _c_indent_function() {        /* on Alt+Ctrl+Q */
  1531.     PSTATE    ps;
  1532.     long     ret;
  1533.     long    stop;
  1534.  
  1535.     MarkPushPos();
  1536.     FindStartOfDef(); /* beginning_of_defun(); BROKEN */
  1537.     ps.beginning_of_defun = BufQueryOffset();
  1538.     _c_end_of_func();
  1539.     stop = BufQueryOffset();
  1540.     PosToOffset(ps.beginning_of_defun);
  1541.     while ( BufQueryOffset() < stop ) {
  1542.         SysSetHourglass(1);
  1543.         c_indenter_1(&ps);
  1544.         MovNextLine();
  1545.     }
  1546.     MarkPopPos();
  1547.     SysSetHourglass(0);
  1548. } /* end _c_indent_function() */
  1549.  
  1550.  
  1551.  
  1552. /* _c_smart_setup()
  1553.  *    This function is called when this macro file is loaded.
  1554.  *    You can modify this function to change how
  1555.  *    certain constructs are indented relative to indent_size,
  1556.  * if these values do not give the indent style you want.
  1557.  * If you want to change the values that are arguments to this
  1558.  * function, change the call in _init.
  1559.  */
  1560. void
  1561. _c_smart_setup(int indent_size,
  1562.                     int brace_offset,
  1563.                     int imag_offset,
  1564.                     int shortcut )
  1565. {
  1566.     c_indenter_shortcut                = shortcut;
  1567.     c_indent_level                        = indent_size;
  1568.     c_brace_imaginary_offset        = imag_offset;
  1569.     c_brace_offset                        = brace_offset;
  1570.     c_argdecl_indent                    = indent_size+1;
  1571.     c_label_offset                        = -indent_size+1;
  1572.     c_case_offset                        = -indent_size;
  1573.     c_continued_statement_offset    = indent_size;
  1574.     c_preproc_col_1                    = 0;
  1575.     c_preproc_offset                    = -1;
  1576.     c_tab_always_indent                = 0;
  1577. } /* end _c_smart_setup() */
  1578.  
  1579.  
  1580. void
  1581. _init(void) {
  1582.   #if 1
  1583.     /*
  1584.      * If you do not want braces indented to the level of the code
  1585.      *    they enclose, enable this code.
  1586.      */
  1587.     _c_smart_setup(IndentSize,    /* c_indent_level */
  1588.                         0,                /* c_brace_offset */
  1589.                         0,                /* c_brace_imaginary_offset */
  1590.                         0);            /* use shortcut indenter (faster) */
  1591.   #else
  1592.     /*
  1593.      * If you want braces indented to the level of the code
  1594.      *    they enclose, enable this code.
  1595.      */
  1596.     _c_smart_setup(IndentSize,    /* c_indent_level */
  1597.                         IndentSize,    /* c_brace_offset */
  1598.                         IndentSize,    /* c_brace_imaginary_offset */
  1599.                         0);            /* use shortcut indenter (faster) */
  1600.   #endif
  1601. } /* end _init() */
  1602.  
  1603.  
  1604.  
  1605. /*
  1606. ** End module: c_smart.rm
  1607. */
  1608.