home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume9 / teco / part02 / te_srch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-03-11  |  14.2 KB  |  422 lines

  1. /* TECO for Ultrix   Copyright 1986 Matt Fichtenbaum                        */
  2. /* This program and its components belong to GenRad Inc, Concord MA 01742    */
  3. /* They may be copied if this copyright notice is included                    */
  4.  
  5. /* te_srch.c   routines associated with search operations   2/5/86 */
  6. #include "te_defs.h"
  7.  
  8. /* routine to read in a string with string-build characters */
  9. /* used for search, tag, file name operations                */
  10. /* returns 0 if empty string entered, nonzero otherwise        */
  11.  
  12. int build_string(buff)
  13.     struct qh *buff;            /* arg is addr of q-reg header */
  14.     {
  15.     int count;                    /* char count */
  16.     struct buffcell *tp;        /* pointer to temporary string */
  17.     char c;                        /* temp character */
  18.  
  19.     term_char = (atflag) ? getcmdc(trace_sw) : ESC;        /* read terminator */
  20.     count = atflag = 0;            /* initialize char count */
  21.     if (!peekcmdc(term_char))    /* if string is not empty */
  22.         {
  23.  
  24. /* create a temporary string and read chars into it until the terminator */
  25.         for (tp = bb.p = get_bcell(), bb.c = 0; (c = getcmdc(trace_sw)) != term_char; )
  26.             {
  27.             if ((c == '^') && !(ed_val & ED_CARET))        /* read next char as CTL */
  28.                 {
  29.                 if ((c = getcmdc(trace_sw)) == term_char) ERROR(msp <= &mstack[0] ? E_UTC : E_UTM);
  30.                 c &= 0x1f;
  31.                 }
  32.             if ((c &= 0177) < ' ')            /* if a control char */
  33.                 {
  34.                 switch (c)
  35.                     {
  36.                     case CTL (Q):            /* take next char literally */
  37.                     case CTL (R):
  38.                         if ((c = getcmdc(trace_sw)) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  39.                         break;                /* fetch character and go store */
  40.  
  41.                     case CTL (V):            /* take next char as lower case */
  42.                         if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  43.                         c = mapch_l[cmdc];
  44.                         break;
  45.  
  46.                     case CTL (W):            /* take next char as upper case */
  47.                         if ((c = getcmdc(trace_sw)) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  48.                         if (islower(c)) c = toupper(c);
  49.                         break;
  50.  
  51.                     case CTL (E):            /* expanded constructs */
  52.                         if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  53.                         switch (mapch_l[cmdc])
  54.                             {
  55.                             case 'u':        /* use char in q-reg */
  56.                                 if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  57.                                 c = qreg[getqspec(1, cmdc)].v & 0x7f;
  58.                                 break;
  59.  
  60.                             case 'q':        /* use string in q-reg */
  61.                                 if (getcmdc(trace_sw) == term_char) ERROR((msp <= &mstack[0]) ? E_UTC : E_UTM);
  62.                                 ll = getqspec(1, cmdc);            /* read the reg spec */
  63.                                 aa.p = qreg[ll].f;                /* set a pointer to it */
  64.                                 aa.c = 0;
  65.                                 for (mm = 0; mm < qreg[ll].z; mm++)
  66.                                     {
  67.                                     bb.p->ch[bb.c] = aa.p->ch[aa.c];        /* store char */
  68.                                     fwdcx(&bb);                    /* store next char */
  69.                                     fwdc(&aa);
  70.                                     ++count;
  71.                                     }
  72.                                 continue;                /* repeat loop without storing */
  73.  
  74.                             default:
  75.                                 bb.p->ch[bb.c] = CTL (E);        /* not special: store the ^E */
  76.                                 fwdcx(&bb);
  77.                                 ++count;
  78.                                 c = cmdc;                        /* and go store the following char */
  79.                                 break;
  80.  
  81.                             }                            /* end ^E switch */
  82.                         }                            /* end outer switch */
  83.                 }                            /* end "if a control char */
  84.             bb.p->ch[bb.c] = c;            /* store character */
  85.             fwdcx(&bb);                    /* advance pointer */
  86.             ++count;                    /* count characters */
  87.             }                        /* end "for" loop */
  88.         free_blist(buff->f);        /* return old buffer */
  89.         buff->f = tp;                /* put in new one */
  90.         buff->f->b = (struct buffcell *) buff;
  91.         buff->z = count;            /* store count of chars in string */
  92.         }                    /* end non-null string */
  93.     else getcmdc(trace_sw);        /* empty string: consume terminator */
  94.     return(count);            /* return char count */
  95.     }            
  96.  
  97.  
  98.  
  99.  
  100. /* routine to handle end of a search operation    */
  101. /* called with pass/fail result from search        */
  102. /* returns same pass/fail result                */
  103.  
  104. int end_search(result)
  105.     int result;
  106.     {
  107.     if (!result)        /* if search failed */
  108.         {
  109.         if (!(esp->flag2 || (ed_val & ED_SFAIL))) dot = 0;        /* if an unbounded search failed, clear ptr */
  110.         if (!colonflag && !peekcmdc(';')) ERROR(E_SRH);        /* if no real or implied colon, error if failure */
  111.         }
  112.     esp->flag1 = colonflag;                /* return a value if a :S command */
  113.     srch_result = esp->val1 = result;    /* and leave it for next ";" */
  114.     esp->flag2 = colonflag = atflag = 0;    /* consume arguments */
  115.     esp->op = OP_START;
  116.     return(result);
  117.     }
  118.  
  119. /* routine to set up for search operation */
  120. /* reads search arguments, returns search count */
  121.  
  122. static struct qp sm, sb;        /* match-string and buffer pointers */
  123. static char *pmap;                /* pointer to character mapping table */
  124. static int locb;                /* reverse search limit */
  125. static int last_z;                /* end point for reverse search */
  126.  
  127. int setup_search()
  128.     {
  129.     int count;                /* string occurrence counter */
  130.  
  131.     set_pointer(dot, &aa);            /* set a pointer to start of search */
  132.     if (colonflag >= 2) esp->flag2 = esp->flag1 = esp->val2 = esp->val1 = 1;    /* ::S is 1,1S */
  133.     if ((count = get_value(1)) == 0) ERROR(E_ISA);     /* read search count: default is 1 */
  134.     else if (count > 0)                /* search forward */
  135.         {
  136.         if (esp->flag2)        /* if bounded search */
  137.             {
  138.             if (esp->val2 < 0) esp->val2 = -(esp->val2);    /* set limit */
  139.             if ((aa.z = dot + esp->val2) > z) aa.z = z;        /* or z, whichever less */
  140.             }
  141.         else aa.z = z;
  142.         }
  143.     else
  144.         {
  145.         if (esp->flag2)        /* if bounded search */
  146.             {
  147.             if (esp->val2 < 0) esp->val2 = -(esp->val2);    /* set limit */
  148.             if ((locb = dot - esp->val2) < 0) locb = 0;        /* or 0, whichever greater */
  149.             }
  150.         else locb = 0;
  151.         }
  152.     return(count);
  153.     }
  154.  
  155. /* routine to do N, _, E_ searches:  search, if search fails, then get    */
  156. /* next page and continue                                                 */
  157.  
  158. do_nsearch(arg)
  159.     char arg;        /* arg is 'n', '_', or 'e' to define which search */
  160.     {
  161.     int scount;        /* search count */
  162.  
  163.     build_string(&sbuf);            /* read the search string */
  164.     if ((scount = get_value(1)) <= 0) ERROR(E_ISA);        /* count must be >0 */
  165.     set_pointer(dot, &aa);            /* start search at dot */
  166.     esp->flag2 = locb = 0;            /* make it unbounded */
  167.  
  168.     while (scount > 0)                /* search until found */
  169.         {
  170.         if (!do_search(1))            /* search forwards */
  171.             {                        /*   if search fails... */
  172.             if (infile->eofsw || !infile->fd) break;    /* if no input, quit */
  173.             if (arg == 'n')
  174.                 {
  175.                 set_pointer(0, &aa);    /* write file if 'n' */
  176.                 write_file(&aa, z, ctrl_e);
  177.                 }
  178.  
  179.             /* not 'n': if _, and an output file, and data to lose, error */
  180.             else if ((arg == '_') && (outfile->fd) && (z) && (ed_val & ED_YPROT)) ERROR(E_YCA);
  181.  
  182.             buff_mod = dot = z = 0;                /* clear buffer */
  183.             set_pointer(0, &aa);
  184.             read_file(&aa, &z, (ed_val & ED_EXPMEM ? -1 : 0) );            /* read next page */
  185.             set_pointer(0, &aa);        /* search next page from beginning */
  186.             }
  187.         else --scount;                    /* search successful: one fewer to look for */
  188.         }
  189.     return( end_search( (scount == 0) ? -1 : 0) );        /* use end_search to clean up */
  190.     }
  191.  
  192.  
  193. /* routine to do "FB" search - m,nFB is search from m to n,    */
  194. /* nFB is search from . to nth line                            */
  195. /* convert arguments to args of normal m,nS command            */
  196.  
  197. int do_fb()                /* returns search result */
  198.     {
  199.     if (esp->flag1 && esp->flag2)    /* if two arguments */
  200.         {
  201.         dot = esp->val2;                        /* start from "m" arg */
  202.         esp->val2 = esp->val1 - esp->val2;        /* get number of chars */
  203.         }
  204.     else                            /* if no or one args, treat as number of lines */
  205.         {
  206.         esp->val2 = lines(get_value(1));        /* number of chars */
  207.         esp->flag2 = esp->flag1 = 1;            /* conjure up two args */
  208.         }
  209.     esp->val1 = (esp->val2 > 0) ? 1 : -1;    /* set search direction */
  210.  
  211.     build_string(&sbuf);        /* read search string and terminator */
  212.     return(end_search(  do_search( setup_search() )  ));    /* do search and return result */
  213.     }
  214.  
  215. /* routine to do search operation: called with search count as argument */
  216. /* returns -1 (pass) or 0 (fail)                                        */
  217.  
  218. int do_search(count)
  219.     int count;
  220.     {
  221.     pmap = (ctrl_x) ? &mapch[0] : &mapch_l[0];        /* set approp. mapping table */
  222.     sm.z = sbuf.z;                    /* copy # of chars in search buffer */
  223.  
  224.     if (count > 0)
  225.         {
  226.         for (sm.dot = 0; count > 0; count--)     /* loop to count occurrences */
  227.             {
  228.             for (; aa.dot < aa.z; aa.dot++)     /* loop to advance search pointer */
  229.                 {
  230.                 for (sb.p = aa.p, sb.c = aa.c, sb.dot = aa.dot, sm.p = sbuf.f, sm.dot = sm.c = 0;
  231.                                             (sb.dot < z) && (sm.dot < sm.z); sm.dot++, sb.dot++)
  232.                     {                                /* for each char in search string */
  233.                     if (spec_chars[ sm.p->ch[sm.c] ] & A_A)        /* if search string char is "special" */
  234.                         {
  235.                         if (!srch_cmp()) break;            /* then use expanded comparison routine */
  236.                         }
  237.                     else if (*(pmap + sb.p->ch[sb.c]) != *(pmap + sm.p->ch[sm.c])) break;        /* else just compare */
  238.                     if (++sm.c > CELLSIZE-1)        /* advance search-string ptr */
  239.                         {
  240.                         sm.p = sm.p->f;
  241.                         sm.c = 0;
  242.                         }
  243.                     if (++sb.c > CELLSIZE-1)        /* advance buffer ptr */
  244.                         {
  245.                         sb.p = sb.p->f;
  246.                         sb.c = 0;
  247.                         }
  248.                     }                    /* end comparison loop */
  249.  
  250.                 if (sm.dot >= sm.z) break;            /* exit if found */
  251.                 if (++aa.c > CELLSIZE-1)            /* else not found: advance buffer pointer */
  252.                     {
  253.                     aa.p = aa.p->f;
  254.                     aa.c = 0;
  255.                     }
  256.                 }                        /* end search loop */
  257.  
  258.             if (sm.dot < sm.z) break;                /* if one search failed, don't do more */
  259.             else
  260.                 {
  261.                 ctrl_s = aa.dot - sb.dot;            /* otherwise save -length of string found */
  262.                 if ((ed_val & ED_SMULT) && (count > 1))        /* if funny "advance by 1" mode */
  263.                     {
  264.                     ++aa.dot;                        /* advance buffer pointer by one only */
  265.                     if (++aa.c > CELLSIZE-1)
  266.                         {
  267.                         aa.p = aa.p->f;
  268.                         aa.c = 0;
  269.                         }
  270.                     }
  271.                 else
  272.                     {
  273.                     aa.dot = sb.dot;                /* advance search pointer past string */
  274.                     aa.p = sb.p;
  275.                     aa.c = sb.c;
  276.                     }
  277.                 }
  278.             }                    /* end "search n times" */
  279.         }                /* end "search forwards" */
  280.  
  281.     else                 /* search backwards */
  282.         {
  283.         for (last_z = z, sm.dot = 0; count < 0; count++)     /* loop to count occurrences */
  284.             {
  285.             for (; aa.dot >= locb; aa.dot--)     /* loop to advance (backwards) search pointer */
  286.                 {
  287.                 for (sb.p = aa.p, sb.c = aa.c, sb.dot = aa.dot, sm.p = sbuf.f, sm.dot = sm.c = 0;
  288.                                                 (sb.dot < last_z) && (sm.dot < sm.z); sm.dot++, sb.dot++)
  289.                     {                                /* loop to compare string */
  290.                     if (spec_chars[ sm.p->ch[sm.c] ] & A_A)        /* if search string char is "special" */
  291.                         {
  292.                         if (!srch_cmp()) break;        /* then use expanded comparison routine */
  293.                         }
  294.                     else if (*(pmap + sb.p->ch[sb.c]) != *(pmap + sm.p->ch[sm.c])) break;        /* else just compare */
  295.                     if (++sm.c > CELLSIZE-1)        /* advance search-string ptr */
  296.                         {
  297.                         sm.p = sm.p->f;
  298.                         sm.c = 0;
  299.                         }
  300.                     if (++sb.c > CELLSIZE-1)        /* advance buffer ptr */
  301.                         {
  302.                         sb.p = sb.p->f;
  303.                         sb.c = 0;
  304.                         }
  305.                     }                    /* end comparison loop */
  306.                 if (sm.dot >= sm.z)                    /* search matches: */
  307.                     {
  308.                     if (!(ed_val & ED_SMULT)) last_z = aa.dot;    /* set last_z to point where this string was found */
  309.                     break;
  310.                     }
  311.                 if (sb.dot >= last_z)                /* or if string is beyond end of buffer */
  312.                     {
  313.                     sm.dot = sm.z;                        /* make search appear to have succeeded */
  314.                     --count;                            /* so as to back up pointer, and force one more look */
  315.                     break;
  316.                     }
  317.                 if (--aa.c < 0)                /* else advance buffer pointer (backwards) */
  318.                     {
  319.                     aa.p = aa.p->b;
  320.                     aa.c = CELLSIZE-1;
  321.                     }
  322.                 }                        /* end search loop */
  323.             if (sm.dot < sm.z) break;                /* if one search failed, don't do more */
  324.             else
  325.                 {
  326.                 if (count < -1) backc(&aa);            /* if this is not last search, back pointer up one */
  327.                 else                    
  328.                     {
  329.                     ctrl_s = aa.dot - sb.dot;        /* otherwise save -length of string found */
  330.                     aa.dot = sb.dot;                /* advance pointer past string */
  331.                     aa.p = sb.p;
  332.                     aa.c = sb.c;
  333.                     }
  334.                 }
  335.             }                    /* end "search n times" */
  336.         }                /* end "search backwards" */
  337.     if (sm.dot >= sm.z) dot = aa.dot;                /* if search succeeded, update pointer    */
  338.     search_flag = 1;                                /* set "search occurred" (for ES)        */
  339.     return((sm.dot >= sm.z) ? -1 : 0);                /* and return -1 (pass) or 0 (fail)        */
  340.     }                /* end "do_search" */
  341.  
  342. /* expanded search comparison */
  343. /* returns 1 if match, 0 if not */
  344.  
  345. int srch_cmp()
  346.     {
  347.     int tq;                        /* q-reg name for ^EGq */
  348.     struct qp tqp;                /* pointer to read q reg */
  349.  
  350.     switch (mapch_l[sm.p->ch[sm.c]])        /* what is search character */
  351.         {
  352.         case CTL (N):                /* match anything but following construct */
  353.             if (sm.dot >= sm.z) ERROR(E_ISS);    /* don't read past end of string */
  354.             fwdc(&sm);                /* skip the ^N */
  355.             return(!srch_cmp());
  356.  
  357.         case CTL (X):                /* match any character */
  358.             return(1);
  359.  
  360.         case CTL (Q):                /* take next char literally */
  361.         case CTL (R):
  362.             if (sm.dot >= sm.z) ERROR(E_ISS);    /* don't read past end of string */
  363.             fwdc(&sm);                /* skip the ^Q */
  364.             return(*(pmap + sb.p->ch[sb.c]) == *(pmap + sm.p->ch[sm.c]));
  365.  
  366.         case CTL (S):                /* match any nonalphanumeric */
  367.             return(!isalnum(sb.p->ch[sb.c]));
  368.  
  369.         case CTL (E):
  370.             if (sm.dot >= sm.z) ERROR(E_ISS);    /* don't read past end of string */
  371.             fwdc(&sm);                /* skip the ^E */
  372.             switch (mapch_l[sm.p->ch[sm.c]])
  373.                 {
  374.                 case 'a':            /* match any alpha */
  375.                     return(isalpha(sb.p->ch[sb.c]));
  376.  
  377.                 case 'b':            /* match any nonalpha */
  378.                     return(!isalnum(sb.p->ch[sb.c]));
  379.  
  380.                 case 'c':            /* rad50 symbol constituent */
  381.                     return(!isalnum(sb.p->ch[sb.c]) || (sb.p->ch[sb.c] == '$') || (sb.p->ch[sb.c] == '.'));
  382.  
  383.                 case 'd':            /* digit */
  384.                     return(isdigit(sb.p->ch[sb.c]));
  385.  
  386.                 case 'l':            /* line terminator LF, VT, FF */
  387.                     return((sb.p->ch[sb.c] == LF) || (sb.p->ch[sb.c] == FF) || (sb.p->ch[sb.c] == VT));
  388.  
  389.                 case 'r':            /* alphanumeric */
  390.                     return(isalnum(sb.p->ch[sb.c]));
  391.  
  392.                 case 'v':            /* lower case */
  393.                     return(islower(sb.p->ch[sb.c]));
  394.  
  395.                 case 'w':            /* upper case */
  396.                     return(isupper(sb.p->ch[sb.c]));
  397.  
  398.                 case 's':            /* any non-null string of spaces or tabs */
  399.                     if (((sb.p->ch[sb.c]&0177) != ' ') && ((sb.p->ch[sb.c]&0177) != TAB)) return(0);    /* failure */
  400.                     /* skip remaining spaces or tabs */
  401.                     for ( fwdc(&sb); ((sb.p->ch[sb.c]&0177) == ' ') || ((sb.p->ch[sb.c]&0177) == TAB); fwdc(&sb) );
  402.                     backc(&sb);        /* back up one char (calling routine will skip it) */
  403.                     return(1);        /* success */
  404.  
  405.                 case 'g':            /* any char in specified q register */
  406.                     if (sm.dot >= sm.z) ERROR(E_ISS);    /* don't read past end of string */
  407.                     fwdc(&sm);        /* get to the next char */
  408.                     tq = getqspec(1, sm.p->ch[sm.c]);        /* read q-reg spec */                    
  409.                     for (tqp.dot = tqp.c = 0, tqp.p = qreg[tq].f; tqp.dot < qreg[tq].z; fwdc(&tqp))
  410.                         if (*(pmap + tqp.p->ch[tqp.c]) == *(pmap + sb.p->ch[sb.c])) return(1);    /* match */
  411.                     return(0);        /* fail */
  412.  
  413.                 default:
  414.                     ERROR(E_ISS);
  415.                 }                            /* end ^E constructions */
  416.  
  417.         default:
  418.             return(*(pmap + sb.p->ch[sb.c]) == *(pmap + sm.p->ch[sm.c]));
  419.         }                                    /* end other constructions */
  420.     }
  421.  
  422.