home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / fences.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  9KB  |  489 lines

  1. /* 
  2.  *
  3.  *    fences.c
  4.  *
  5.  * Match up various fenceposts, like (), [], {}, */ /*, #if, #el, #en
  6.  *
  7.  * Most code probably by Dan Lawrence or Dave Conroy for MicroEMACS
  8.  * Extensions for vile by Paul Fox
  9.  *
  10.  *    $Log: fences.c,v $
  11.  * Revision 1.4  1992/08/20  23:40:48  foxharp
  12.  * typo fixes -- thanks, eric
  13.  *
  14.  * Revision 1.3  1992/06/08  08:56:05  foxharp
  15.  * fixed infinite loop if simple fence not found, and
  16.  * suppressed beeping in input mode if fence not found
  17.  * ,.
  18.  * 
  19.  *
  20.  * Revision 1.2  1992/06/03  08:37:23  foxharp
  21.  * removed nested comment
  22.  *
  23.  * Revision 1.1  1992/05/29  09:38:33  foxharp
  24.  * Initial revision
  25.  *
  26.  *
  27.  *
  28.  */
  29.  
  30.  
  31. #include    <stdio.h>
  32. #include    "estruct.h"
  33. #include    "edef.h"
  34.  
  35. #if CFENCE
  36. /*    the cursor is moved to a matching fence */
  37. int
  38. matchfence(f,n)
  39. int f,n;
  40. {
  41.     int s = getfence(0, (!f || n > 0) ? FORWARD:REVERSE);
  42.     if (s == FALSE)
  43.         TTbeep();
  44.     return s;
  45. }
  46.  
  47. int
  48. matchfenceback(f,n)
  49. int f,n;
  50. {
  51.     int s = getfence(0, (!f || n > 0) ? REVERSE:FORWARD);
  52.     if (s == FALSE)
  53.         TTbeep();
  54.     return s;
  55. }
  56.  
  57. int
  58. getfence(ch,sdir)
  59. int ch; /* fence type to match against */
  60. int sdir; /* direction to scan if we're not on a fence to begin with */
  61. {
  62.     MARK    oldpos;     /* original pointer */
  63.     register int ofence = 0;    /* open fence */
  64.     int s, i;
  65.     char *otherkey = NULL, *key = NULL;
  66.     char *lookingforkey = NULL;
  67.  
  68.     /* save the original cursor position */
  69.     oldpos = DOT;
  70.  
  71.     /* ch may have been passed, if being used internally */
  72.     if (!ch) {
  73.         if (DOT.o == 0 && (ch = char_at(DOT)) == '#') {
  74.             if (llength(DOT.l) < 3)
  75.                 return FALSE;
  76.         } else if ((ch = char_at(DOT)) == '/' || ch == '*') {
  77.             /* EMPTY */;
  78.         } else if (sdir == FORWARD) {
  79.             /* get the current character */
  80.             if (oldpos.o < llength(oldpos.l)) {
  81.                 do {
  82.                     ch = char_at(oldpos);
  83.                 } while(!isfence(ch) &&
  84.                     ++oldpos.o < llength(oldpos.l));
  85.             }
  86.             if (is_at_end_of_line(oldpos)) {
  87.                 return FALSE;
  88.             }
  89.         } else {
  90.             /* get the current character */
  91.             if (oldpos.o >= 0) {
  92.                 do {
  93.                     ch = char_at(oldpos);
  94.                 } while(!isfence(ch) && --oldpos.o >= 0);
  95.             }
  96.  
  97.             if (oldpos.o < 0) {
  98.                 return FALSE;
  99.             }
  100.         }
  101.  
  102.         /* we've at least found a fence -- move us that far */
  103.         DOT.o = oldpos.o;
  104.     }
  105.  
  106.     /* setup proper matching fence */
  107.     switch (ch) {
  108.         case '(':
  109.             ofence = ')';
  110.             sdir = FORWARD;
  111.             break;
  112.         case ')':
  113.             ofence = '(';
  114.             sdir = REVERSE;
  115.             break;
  116.         case LBRACE:
  117.             ofence = RBRACE;
  118.             sdir = FORWARD;
  119.             break;
  120.         case RBRACE:
  121.             ofence = LBRACE;
  122.             sdir = REVERSE;
  123.             break;
  124.         case '[':
  125.             ofence = ']';
  126.             sdir = FORWARD;
  127.             break;
  128.         case ']':
  129.             ofence = '[';
  130.             sdir = REVERSE;
  131.             break;
  132.         case '#':
  133.             for (i = 1; i < llength(DOT.l) &&
  134.                 isspace(lgetc(DOT.l,i)); i++)
  135.                 ;
  136.             if (i + 2 <= llength(DOT.l)) {
  137.                 if (!strncmp("if",
  138.                         &DOT.l->l_text[i], 2)) {
  139.                     sdir = FORWARD;
  140.                     key = "if";
  141.                     otherkey = "en";
  142.                     lookingforkey = "el";
  143.                     break;
  144.                 } else if (!strncmp("el",
  145.                         &DOT.l->l_text[i], 2)) {
  146.                     if (sdir == FORWARD) {
  147.                         key = "if";
  148.                         lookingforkey =
  149.                             otherkey = "en";
  150.                     } else {
  151.                         key = "en";
  152.                         lookingforkey = 
  153.                             otherkey = "if";
  154.                     }
  155.                     break;
  156.                 } else if (!strncmp("en",
  157.                         &DOT.l->l_text[i], 2)) {
  158.                     sdir = REVERSE;
  159.                     key = "en";
  160.                     lookingforkey = otherkey = "if";
  161.                     break;
  162.                 }
  163.             }
  164.             return FALSE;
  165.         case '*':
  166.             ch = '/';
  167.             if (DOT.o+1 < llength(DOT.l) &&
  168.                 (lgetc(DOT.l, DOT.o+1) == '/')) {
  169.                 sdir = REVERSE;
  170.                 forwchar(TRUE,1);
  171.                 break;
  172.             } else if (DOT.o > 0 &&
  173.                 (lgetc(DOT.l, DOT.o-1) == '/')) {
  174.                 sdir = FORWARD;
  175.                 backchar(TRUE,1);
  176.                 if (doingopcmd)
  177.                     pre_op_dot = DOT;
  178.                 break;
  179.             }
  180.             return FALSE;
  181.         case '/':
  182.             if (DOT.o+1 < llength(DOT.l) &&
  183.                 (lgetc(DOT.l, DOT.o+1) == '*')) {
  184.                 sdir = FORWARD;
  185.                 break;
  186.             } else if (DOT.o > 0 &&
  187.                 (lgetc(DOT.l, DOT.o-1) == '*')) {
  188.                 sdir = REVERSE;
  189.                 break;
  190.             }
  191.             /* FALL THROUGH */
  192.         default: 
  193.             return(FALSE);
  194.     }
  195.  
  196.     /* ops are inclusive of the endpoint */
  197.     if (doingopcmd && sdir == REVERSE) {
  198.         forwchar(TRUE,1);
  199.         pre_op_dot = DOT;
  200.         backchar(TRUE,1);
  201.     }
  202.  
  203.     if (lookingforkey != NULL) {  /* we're searching for a cpp keyword */
  204.         s = cpp_fence(sdir,key,otherkey,lookingforkey);
  205.     } else if (ch == '/') {
  206.         s = comment_fence(sdir);
  207.     } else {
  208.         s = simple_fence(sdir, ch, ofence);
  209.     }
  210.  
  211.     if (s == TRUE)
  212.         return TRUE;
  213.  
  214.     /* restore the current position */
  215.     DOT = oldpos;
  216.     return(FALSE);
  217. }
  218.  
  219. int
  220. simple_fence(sdir, ch, ofence)
  221. int sdir;
  222. int ch;
  223. int ofence;
  224. {
  225.     int count = 1;
  226.     int c, s = FALSE;
  227.  
  228.     /* set up for scan */
  229.     if (sdir == REVERSE)
  230.         backchar(FALSE, 1);
  231.     else
  232.         forwchar(FALSE, 1);
  233.  
  234.     while (count > 0) {
  235.         if (is_at_end_of_line(DOT))
  236.             c = '\n';
  237.         else
  238.             c = char_at(DOT);
  239.  
  240.         if (c == ch)
  241.             ++count;
  242.         else if (c == ofence)
  243.             --count;
  244.  
  245.         if (sdir == FORWARD)
  246.             s = forwchar(FALSE, 1);
  247.         else
  248.             s = backchar(FALSE, 1);
  249.  
  250.         if (s == FALSE || interrupted)
  251.             return FALSE;
  252.     }
  253.  
  254.     /* if count is zero, we have a match, move the sucker */
  255.     if (count == 0) {
  256.         if (s == TRUE) {
  257.             if (sdir == FORWARD) {
  258.                 if (!doingopcmd)
  259.                     backchar(FALSE, 1);
  260.             } else {
  261.                 forwchar(FALSE, 1);
  262.             }
  263.         }
  264.         curwp->w_flag |= WFMOVE;
  265.         return TRUE;
  266.     }
  267.     return FALSE;
  268. }
  269.  
  270. int
  271. comment_fence(sdir)
  272. int sdir;
  273. {
  274.     MARK comstartpos;
  275.     int count = 1;
  276.     int c, s = FALSE;
  277.  
  278.     /* set up for scan */
  279.     if (sdir == REVERSE)
  280.         backchar(FALSE, 1);
  281.     else
  282.         forwchar(FALSE, 1);
  283.  
  284.     comstartpos.l = NULL;
  285.  
  286.     while (count > 0) {
  287.         if (is_at_end_of_line(DOT))
  288.             c = '\n';
  289.         else
  290.             c = char_at(DOT);
  291.  
  292.         if (c == '/') {
  293.             /* is it a comment-end? */
  294.             if ( DOT.o > 0 && lgetc(DOT.l, DOT.o-1) == '*') {
  295.                 if ( sdir == FORWARD) {
  296.                     count = 0;
  297.                 } else {
  298.                     if (comstartpos.l) {
  299.                         DOT = comstartpos;
  300.                         count = 0;
  301.                     } else {
  302.                         return FALSE;
  303.                     }
  304.                 }
  305.             }
  306.             /* is it a comment start? */
  307.             if ( sdir == REVERSE &&
  308.                 DOT.o < llength(DOT.l)-1 &&
  309.                 lgetc(DOT.l, DOT.o+1) == '*') {
  310.                 /* remember where we are */
  311.                 comstartpos = DOT;
  312.             }
  313.  
  314.         }
  315.  
  316.         if (sdir == FORWARD)
  317.             s = forwchar(FALSE, 1);
  318.         else
  319.             s = backchar(FALSE, 1);
  320.  
  321.         if (s == FALSE) {
  322.             if (comstartpos.l) {
  323.                 DOT = comstartpos;
  324.                 count = 0;
  325.                 break;
  326.             }
  327.             return FALSE;
  328.         }
  329.  
  330.         if (interrupted)
  331.             return FALSE;
  332.     }
  333.  
  334.     /* if count is zero, we have a match, move the sucker */
  335.     if (count == 0) {
  336.         if (s == TRUE) {
  337.             if (sdir == FORWARD) {
  338.                 if (!doingopcmd && s)
  339.                     backchar(FALSE, 1);
  340.             } else {
  341.                 forwchar(FALSE, 1);
  342.             }
  343.         }
  344.         curwp->w_flag |= WFMOVE;
  345.         return(TRUE);
  346.     }
  347.     return FALSE;
  348. }
  349.  
  350. int
  351. cpp_fence(sdir,key,otherkey,lookingforkey)
  352. int sdir;
  353. char *key, *otherkey, *lookingforkey;
  354. {
  355.     int count = 1;
  356.     int i;
  357.  
  358.     /* set up for scan */
  359.     if (sdir == REVERSE)
  360.         DOT.l = lback(DOT.l);
  361.     else
  362.         DOT.l = lforw(DOT.l);
  363.     while (count > 0 && !is_header_line(DOT, curbp)) {
  364.         for (i = 1; i < llength(DOT.l) && 
  365.             isspace(lgetc(DOT.l,i)); i++)
  366.             ;
  367.         if (llength(DOT.l) >= i + 2 && char_at(DOT) == '#') {
  368.  
  369.             if (!strncmp(key, &DOT.l->l_text[i], 2))
  370.                 ++count;
  371.             else if (!strncmp(otherkey,
  372.                         &DOT.l->l_text[i], 2))
  373.                 --count;
  374.             if (count == 1 && 
  375.                 strcmp(otherkey, lookingforkey) && 
  376.                 !strncmp(lookingforkey,
  377.                         &DOT.l->l_text[i], 2)) {
  378.                 
  379.                 count = 0;
  380.                 break;
  381.             }
  382.         }
  383.  
  384.         if (count == 0)
  385.             break;
  386.  
  387.         if (sdir == REVERSE)
  388.             DOT.l = lback(DOT.l);
  389.         else
  390.             DOT.l = lforw(DOT.l);
  391.  
  392.         if (is_header_line(DOT,curbp) || interrupted)
  393.             return FALSE;
  394.     }
  395.     if (count == 0) {
  396.         curwp->w_flag |= WFMOVE;
  397.         if (doingopcmd)
  398.             fulllineregions = TRUE;
  399.         return TRUE;
  400.     }
  401.     return FALSE;
  402. }
  403.  
  404. /* get the indent of the line containing the matching brace. */
  405. int
  406. fmatchindent()
  407. {
  408.     int ind;
  409.         
  410.     MK = DOT;
  411.         
  412.     if (getfence(RBRACE,FORWARD) == FALSE) {
  413.         gomark(FALSE,1);
  414.         return previndent(NULL);
  415.     }
  416.  
  417.     ind = indentlen(DOT.l);
  418.  
  419.     gomark(FALSE,1);
  420.         
  421.     return ind;
  422. }
  423.  
  424.  
  425.  
  426. /*    Close fences are matched against their partners, and if
  427.     on screen the cursor briefly lights there        */
  428. int
  429. fmatch(ch)
  430. int ch;    /* fence type to match against */
  431. {
  432.     MARK    oldpos;         /* original position */
  433.     register LINE *toplp;    /* top line in current window */
  434.     register int count; /* current fence level count */
  435.     register char opench;    /* open fence */
  436.     register char c;    /* current character in scan */
  437.  
  438.     /* first get the display update out there */
  439.     update(FALSE);
  440.  
  441.     /* save the original cursor position */
  442.     oldpos = DOT;
  443.  
  444.     /* setup proper open fence for passed close fence */
  445.     if (ch == ')')
  446.         opench = '(';
  447.     else if (ch == RBRACE)
  448.         opench = LBRACE;
  449.     else
  450.         opench = '[';
  451.  
  452.     /* find the top line and set up for scan */
  453.     toplp = lback(curwp->w_line.l);
  454.     count = 1;
  455.     backchar(TRUE, 2);
  456.  
  457.     /* scan back until we find it, or reach past the top of the window */
  458.     while (count > 0 && DOT.l != toplp) {
  459.         if (is_at_end_of_line(DOT))
  460.             c = '\n';
  461.         else
  462.             c = char_at(DOT);
  463.         if (c == ch)
  464.             ++count;
  465.         if (c == opench)
  466.             --count;
  467.         if (backchar(FALSE, 1) != TRUE)
  468.             break;
  469.     }
  470.  
  471.     /* if count is zero, we have a match, display the sucker */
  472.     /* there is a real machine dependent timing problem here we have
  473.        yet to solve......... */
  474.     if (count == 0) {
  475.         forwchar(FALSE, 1);
  476.         update(FALSE);
  477.         /* the idea is to leave the cursor there for about a
  478.             quarter of a second */
  479.         catnap(250);
  480.     }
  481.  
  482.     /* restore the current position */
  483.     DOT = oldpos;
  484.  
  485.     return(TRUE);
  486. }
  487.  
  488. #endif /* CFENCE */
  489.