home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / region.c < prev    next >
Text File  |  1996-04-25  |  15KB  |  628 lines

  1. /*
  2.  * The routines in this file
  3.  * deal with the region, that magic space
  4.  * between "." and mark. Some functions are
  5.  * commands. Some functions are just for
  6.  * internal use.
  7.  */
  8. #include    <stdio.h>
  9. #include    "estruct.h"
  10. #include    "eproto.h"
  11. #include    "edef.h"
  12. #include    "elang.h"
  13.  
  14. /*    reglines:    how many lines in the current region
  15.             used by the trim/entab/detab-region commands
  16. */
  17.  
  18. int PASCAL NEAR reglines()
  19.  
  20. {
  21.     register LINE *linep;    /* position while scanning */
  22.     register int n;     /* number of lines in this current region */
  23.     REGION region;
  24.  
  25.     /* check for a valid region first */
  26.     if (getregion(®ion) != TRUE)
  27.         return(0);
  28.  
  29.     /* start at the top of the region.... */
  30.     linep = region.r_linep;
  31.     region.r_size += region.r_offset;
  32.     n = 0;
  33.  
  34.     /* scan the region... counting lines */
  35.     while (region.r_size > 0L) {
  36.         region.r_size -= lused(linep) + 1;
  37.         linep = lforw(linep);
  38.         n++;
  39.     }
  40.  
  41.     /* place us at the beginning of the region */
  42.     curwp->w_dotp = region.r_linep;
  43.     curwp->w_doto = region.r_offset;
  44.  
  45.     return(n);
  46. }
  47.  
  48. /*
  49.  * Kill the region. Ask "getregion"
  50.  * to figure out the bounds of the region.
  51.  * Move "." to the start, and kill the characters.
  52.  * Bound to "C-W".
  53.  */
  54. PASCAL NEAR killregion(f, n)
  55.  
  56. int f,n;    /* prefix flag and argument */
  57.  
  58. {
  59.     register int    s;
  60.     REGION        region;
  61.  
  62.     /* Don't do this command in read-only mode */
  63.     if (curbp->b_mode&MDVIEW)
  64.         return(rdonly());
  65.  
  66.     /* get the boundries of the region to kill */
  67.     if ((s=getregion(®ion)) != TRUE)
  68.         return(s);
  69.  
  70.     /* flag this command as a kill */
  71.     if ((lastflag&CFKILL) == 0)
  72.         next_kill();
  73.     thisflag |= CFKILL;
  74.  
  75.     /* make sure the cursor gets back to the right place on an undo */
  76.     undo_insert(OP_CPOS, 0L, obj);
  77.  
  78.     /* delete the region */
  79.     curwp->w_dotp = region.r_linep;
  80.     curwp->w_doto = region.r_offset;
  81.     return(ldelete(region.r_size, TRUE));
  82. }
  83.  
  84. /*
  85.  * Copy all of the characters in the
  86.  * region to the kill buffer. Don't move dot
  87.  * at all. This is a bit like a kill region followed
  88.  * by a yank. Bound to "M-W".
  89.  */
  90. PASCAL NEAR copyregion(f, n)
  91.  
  92. int f,n;    /* prefix flag and argument */
  93.  
  94. {
  95.     register LINE    *linep;
  96.     register int    loffs;
  97.     register int    s;
  98.     REGION        region;
  99.  
  100.     if ((s=getregion(®ion)) != TRUE)
  101.         return(s);
  102.     if ((lastflag&CFKILL) == 0)        /* Kill type command.    */
  103.         next_kill();
  104.     thisflag |= CFKILL;
  105.     linep = region.r_linep;         /* Current line.    */
  106.     loffs = region.r_offset;        /* Current offset.    */
  107.     while (region.r_size--) {
  108.         if (loffs == lused(linep)) {  /* End of line.          */
  109.             if ((s=kinsert(FORWARD, '\r')) != TRUE)
  110.                 return(s);
  111.             linep = lforw(linep);
  112.             loffs = 0;
  113.         } else {            /* Middle of line.    */
  114.             if ((s=kinsert(FORWARD, lgetc(linep, loffs))) != TRUE)
  115.                 return(s);
  116.             ++loffs;
  117.         }
  118.     }
  119.     mlwrite(TEXT70);
  120. /*        "[region copied]" */
  121.     return(TRUE);
  122. }
  123.  
  124. /*
  125.  * Lower case region. Zap all of the upper
  126.  * case characters in the region to lower case. Use
  127.  * the region code to set the limits. Scan the buffer,
  128.  * doing the changes. Call "lchange" to ensure that
  129.  * redisplay is done in all buffers. Bound to
  130.  * "C-X C-L".
  131.  */
  132. PASCAL NEAR lowerregion(f, n)
  133.  
  134. int f,n;    /* prefix flag and argument */
  135.  
  136. {
  137.     register LINE *save_dotp;/* pointer and offset to position to preserve */
  138.     register int save_doto;
  139.     register int status;    /* return status from fetching region */
  140.     int c;            /* current character */
  141.     REGION region;        /* region which is being used */
  142.  
  143.     /* don't bother if we are in read only mode */
  144.     if (curbp->b_mode&MDVIEW)
  145.         return(rdonly());
  146.  
  147.     /* get the limits of the current region */
  148.     if ((status = getregion(®ion)) != TRUE)
  149.         return(status);
  150.  
  151.     /* flag that we are changing this text */
  152.     lchange(WFHARD);
  153.  
  154.     /* save the current dot */
  155.     save_dotp = curwp->w_dotp;
  156.     save_doto = curwp->w_doto;
  157.  
  158.     /* scan the region.... */
  159.     curwp->w_dotp = region.r_linep;
  160.     curwp->w_doto = region.r_offset;
  161.     while (region.r_size--) {
  162.  
  163.         if (curwp->w_doto == lused(curwp->w_dotp)) {
  164.  
  165.             /* skip to the next line */
  166.             curwp->w_dotp = lforw(curwp->w_dotp);
  167.             curwp->w_doto = 0;
  168.  
  169.         } else {
  170.  
  171.             /* lowercase this character */
  172.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  173.             if (is_upper(c)) {
  174.                 obj.obj_char = c;
  175.                 c = lowerc(c);
  176.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  177.                 undo_insert(OP_REPC, 1L, obj);
  178.             }
  179.             ++curwp->w_doto;
  180.         }
  181.     }
  182.  
  183.     /* restore the dot position */
  184.     curwp->w_dotp = save_dotp;
  185.     curwp->w_doto = save_doto;
  186.     return(TRUE);
  187. }
  188.  
  189. /*
  190.  * Upper case region. Zap all of the lower
  191.  * case characters in the region to upper case. Use
  192.  * the region code to set the limits. Scan the buffer,
  193.  * doing the changes. Call "lchange" to ensure that
  194.  * redisplay is done in all buffers. Bound to
  195.  * "C-X C-L".
  196.  */
  197. PASCAL NEAR upperregion(f, n)
  198.  
  199. int f,n;    /* prefix flag and argument */
  200.  
  201. {
  202.     register LINE *save_dotp;/* pointer and offset to position to preserve */
  203.     register int save_doto;
  204.     register int status;    /* return status from fetching region */
  205.     int c;            /* current character */
  206.     REGION region;        /* region which is being used */
  207.  
  208.     /* don't bother if we are in read only mode */
  209.     if (curbp->b_mode&MDVIEW)
  210.         return(rdonly());
  211.  
  212.     /* get the limits of the current region */
  213.     if ((status = getregion(®ion)) != TRUE)
  214.         return(status);
  215.  
  216.     /* flag that we are changing this text */
  217.     lchange(WFHARD);
  218.  
  219.     /* save the current dot */
  220.     save_dotp = curwp->w_dotp;
  221.     save_doto = curwp->w_doto;
  222.  
  223.     /* scan the region.... */
  224.     curwp->w_dotp = region.r_linep;
  225.     curwp->w_doto = region.r_offset;
  226.     while (region.r_size--) {
  227.  
  228.         if (curwp->w_doto == lused(curwp->w_dotp)) {
  229.  
  230.             /* skip to the next line */
  231.             curwp->w_dotp = lforw(curwp->w_dotp);
  232.             curwp->w_doto = 0;
  233.  
  234.         } else {
  235.  
  236.             /* uppercase this character */
  237.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  238.             if (is_lower(c)) {
  239.                 obj.obj_char = c;
  240.                 c = upperc(c);
  241.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  242.                 undo_insert(OP_REPC, 1L, obj);
  243.             }
  244.             ++curwp->w_doto;
  245.         }
  246.     }
  247.  
  248.     /* restore the dot position */
  249.     curwp->w_dotp = save_dotp;
  250.     curwp->w_doto = save_doto;
  251.     return(TRUE);
  252. }
  253.  
  254. /*    Narrow-to-region (^X-<) makes all but the current region in
  255.     the current buffer invisable and unchangable
  256. */
  257.  
  258. PASCAL NEAR narrow(f, n)
  259.  
  260. int f,n;    /* prefix flag and argument */
  261.  
  262. {
  263.     register int status;    /* return status */
  264.     BUFFER *bp;        /* buffer being narrowed */
  265.     SCREEN *scrp;        /* screen to fix pointers in */
  266.     EWINDOW *wp;        /* windows to fix up pointers in as well */
  267.     REGION creg;        /* region boundry structure */
  268.     int cmark;        /* current mark */
  269.  
  270.     /* find the proper buffer and make sure we aren't already narrow */
  271.     bp = curwp->w_bufp;        /* find the right buffer */
  272.     if (bp->b_flag&BFNAROW) {
  273.         mlwrite(TEXT71);
  274. /*            "%%This buffer is already narrowed" */
  275.         return(FALSE);
  276.     }
  277.  
  278.     /* find the boundries of the current region */
  279.     if ((status=getregion(&creg)) != TRUE)
  280.         return(status);
  281.     curwp->w_dotp = creg.r_linep;    /* only by full lines please! */
  282.     curwp->w_doto = 0;
  283.     creg.r_size += (long)creg.r_offset;
  284.     if (creg.r_size <= (long)lused(curwp->w_dotp)) {
  285.         mlwrite(TEXT72);
  286. /*            "%%Must narrow at least 1 full line" */
  287.         return(FALSE);
  288.     }
  289.  
  290.     /* archive the top fragment */
  291.     if (bp->b_linep->l_fp != creg.r_linep) {
  292.         bp->b_topline = bp->b_linep->l_fp;
  293.         creg.r_linep->l_bp->l_fp = (LINE *)NULL;
  294.         bp->b_linep->l_fp = creg.r_linep;
  295.         creg.r_linep->l_bp = bp->b_linep;
  296.     }
  297.  
  298.     /* move forward to the end of this region
  299.        (a long number of bytes perhaps) */
  300.     while (creg.r_size > (long)32000) {
  301.         forwchar(TRUE, 32000);
  302.         creg.r_size -= (long)32000;
  303.     }
  304.     forwchar(TRUE, (int)creg.r_size);
  305.     curwp->w_doto = 0;        /* only full lines! */
  306.  
  307.     /* archive the bottom fragment */
  308.     if (bp->b_linep != curwp->w_dotp) {
  309.         bp->b_botline = curwp->w_dotp;
  310.         bp->b_botline->l_bp->l_fp = bp->b_linep;
  311.         bp->b_linep->l_bp->l_fp = (LINE *)NULL;
  312.         bp->b_linep->l_bp = bp->b_botline->l_bp;
  313.     }
  314.  
  315.     /* in all screens.... */
  316.     scrp = first_screen;
  317.     while (scrp) {
  318.  
  319.         /* let all the proper windows be updated */
  320.         wp = scrp->s_first_window;
  321.         while (wp) {
  322.             if (wp->w_bufp == bp) {
  323.                 wp->w_linep = creg.r_linep;
  324.                 wp->w_dotp = creg.r_linep;
  325.                 wp->w_doto = 0;
  326.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  327.                     wp->w_markp[cmark] = creg.r_linep;
  328.                     wp->w_marko[cmark] = 0;
  329.                 }
  330.                 wp->w_flag |= (WFHARD|WFMODE);
  331.             }
  332.             wp = wp->w_wndp;
  333.         }
  334.  
  335.         /* next screen! */
  336.         scrp = scrp->s_next_screen;
  337.     }
  338.  
  339.     /* and now remember we are narrowed */
  340.     bp->b_flag |= BFNAROW;
  341.     mlwrite(TEXT73);
  342. /*        "[Buffer is narrowed]" */
  343.     return(TRUE);
  344. }
  345.  
  346. /*    widen-from-region (^X->) restores a narrowed region    */
  347.  
  348. PASCAL NEAR widen(f, n)
  349.  
  350. int f,n;    /* prefix flag and argument */
  351.  
  352. {
  353.     LINE *lp;    /* temp line pointer */
  354.     BUFFER *bp;    /* buffer being narrowed */
  355.     SCREEN *scrp;    /* screen to fix pointers in */
  356.     EWINDOW *wp;    /* windows to fix up pointers in as well */
  357.     int cmark;    /* current mark */
  358.  
  359.     /* find the proper buffer and make sure we are narrow */
  360.     bp = curwp->w_bufp;        /* find the right buffer */
  361.     if ((bp->b_flag&BFNAROW) == 0) {
  362.         mlwrite(TEXT74);
  363. /*            "%%This buffer is not narrowed" */
  364.         return(FALSE);
  365.     }
  366.  
  367.     /* recover the top fragment */
  368.     if (bp->b_topline != (LINE *)NULL) {
  369.         lp = bp->b_topline;
  370.         while (lp->l_fp != (LINE *)NULL)
  371.             lp = lp->l_fp;
  372.         lp->l_fp = bp->b_linep->l_fp;
  373.         lp->l_fp->l_bp = lp;
  374.         bp->b_linep->l_fp = bp->b_topline;
  375.         bp->b_topline->l_bp = bp->b_linep;
  376.         bp->b_topline = (LINE *)NULL;
  377.     }
  378.  
  379.     /* recover the bottom fragment */
  380.     if (bp->b_botline != (LINE *)NULL) {
  381.  
  382.         /* if the point is at EOF, move it to
  383.            the beginning of the bottom fragment */
  384.         if (curwp->w_dotp == bp->b_linep) {
  385.             curwp->w_dotp = bp->b_botline;
  386.             curwp->w_doto = 0;        /* this should be redundent */
  387.         }
  388.         
  389.         /* if any marks are at EOF, move them to
  390.            the beginning of the bottom fragment */
  391.         for (cmark = 0; cmark < NMARKS; cmark++) {
  392.             if (curwp->w_markp[cmark] == bp->b_linep) {
  393.                 curwp->w_markp[cmark] = bp->b_botline;
  394.                 curwp->w_marko[cmark] = 0;
  395.             }
  396.         }
  397.  
  398.         /* connect the bottom fragment */
  399.         lp = bp->b_botline;
  400.         while (lp->l_fp != (LINE *)NULL)
  401.             lp = lp->l_fp;
  402.         lp->l_fp = bp->b_linep;
  403.         bp->b_linep->l_bp->l_fp = bp->b_botline;
  404.         bp->b_botline->l_bp = bp->b_linep->l_bp;
  405.         bp->b_linep->l_bp = lp;
  406.         bp->b_botline = (LINE *)NULL;
  407.     }
  408.  
  409.     /* in all screens.... */
  410.     scrp = first_screen;
  411.     while (scrp) {
  412.  
  413.         /* let all the proper windows be updated */
  414.         wp = scrp->s_first_window;
  415.         while (wp) {
  416.             if (wp->w_bufp == bp)
  417.                 wp->w_flag |= (WFHARD|WFMODE);
  418.             wp = wp->w_wndp;
  419.         }
  420.  
  421.         /* next screen! */
  422.         scrp = scrp->s_next_screen;
  423.     }
  424.  
  425.     /* and now remember we are not narrowed */
  426.     bp->b_flag &= (~BFNAROW);
  427.     mlwrite(TEXT75);
  428. /*        "[Buffer is widened]" */
  429.     return(TRUE);
  430. }
  431.  
  432. /*
  433.  * This routine figures out the bounds of the region in the current
  434.  * window, and fills in the fields of the "REGION" structure pointed to by
  435.  * "rp". Because the dot and mark are usually very close together, we scan
  436.  * outward from dot looking for mark. This should save time. Return a
  437.  * standard code. Callers of this routine should be prepared to get an
  438.  * "ABORT" status; we might make this have the confirm thing later.
  439.  */
  440.  
  441. PASCAL NEAR getregion(rp)
  442.  
  443. register REGION *rp;
  444.  
  445. {
  446.     register LINE    *flp;
  447.     register LINE    *blp;
  448.     long fsize;
  449.     long bsize;
  450.  
  451.     if (curwp->w_markp[0] == (LINE *)NULL) {
  452.         mlwrite(TEXT76);
  453. /*            "No mark set in this window" */
  454.         return(FALSE);
  455.     }
  456.     if (curwp->w_dotp == curwp->w_markp[0]) {
  457.         rp->r_linep = curwp->w_dotp;
  458.         if (curwp->w_doto < curwp->w_marko[0]) {
  459.             rp->r_offset = curwp->w_doto;
  460.             rp->r_size = (long)(curwp->w_marko[0]-curwp->w_doto);
  461.         } else {
  462.             rp->r_offset = curwp->w_marko[0];
  463.             rp->r_size = (long)(curwp->w_doto-curwp->w_marko[0]);
  464.         }
  465.         return(TRUE);
  466.     }
  467.     blp = curwp->w_dotp;
  468.     bsize = (long)curwp->w_doto;
  469.     flp = curwp->w_dotp;
  470.     fsize = (long)(lused(flp)-curwp->w_doto+1);
  471.     while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
  472.         if (flp != curbp->b_linep) {
  473.             flp = lforw(flp);
  474.             if (flp == curwp->w_markp[0]) {
  475.                 rp->r_linep = curwp->w_dotp;
  476.                 rp->r_offset = curwp->w_doto;
  477.                 rp->r_size = fsize+curwp->w_marko[0];
  478.                 return(TRUE);
  479.             }
  480.             fsize += lused(flp)+1;
  481.         }
  482.         if (lback(blp) != curbp->b_linep) {
  483.             blp = lback(blp);
  484.             bsize += lused(blp)+1;
  485.             if (blp == curwp->w_markp[0]) {
  486.                 rp->r_linep = blp;
  487.                 rp->r_offset = curwp->w_marko[0];
  488.                 rp->r_size = bsize - curwp->w_marko[0];
  489.                 return(TRUE);
  490.             }
  491.         }
  492.     }
  493.     mlwrite(TEXT77);
  494. /*        "Bug: lost mark" */
  495.     return(FALSE);
  496. }
  497.  
  498. /*
  499.  * Copy all of the characters in the region to the string buffer.
  500.  * It is assumed that the buffer size is at least one plus the
  501.  * region size.
  502.  */
  503. char *PASCAL NEAR regtostr(buf, region)
  504.  
  505. char *buf;
  506. REGION *region;
  507.  
  508. {
  509.     register LINE    *linep;
  510.     register int    loffs;
  511.     register long    rsize;
  512.     register char    *ptr;
  513.  
  514.     ptr = buf;
  515.     linep = region->r_linep;        /* Current line.    */
  516.     loffs = region->r_offset;        /* Current offset.    */
  517.     rsize = region->r_size;
  518.     while (rsize--) {
  519.         if (loffs == lused(linep)) {    /* End of line.     */
  520.             *ptr = '\r';
  521.             linep = lforw(linep);
  522.             loffs = 0;
  523.         } else {            /* Middle of line.    */
  524.             *ptr = lgetc(linep, loffs);
  525.             ++loffs;
  526.         }
  527.         ptr++;
  528.     }
  529.     *ptr = '\0';
  530.     return buf;
  531. }
  532.  
  533. char *PASCAL NEAR getreg(value) /* return some of the contents of the current region */
  534.  
  535. char *value;
  536.  
  537. {
  538.     REGION region;
  539.  
  540.     /* get the region limits */
  541.     if (getregion(®ion) != TRUE)
  542.         return(errorm);
  543.  
  544.     /* don't let the region be larger than a string can hold */
  545.     if (region.r_size >= NSTRING)
  546.         region.r_size = NSTRING - 1;
  547.     return(regtostr(value, ®ion));
  548. }
  549.  
  550.  
  551. PASCAL NEAR indent_region(f, n) /* indent a region n tab-stops */
  552.  
  553. int f,n;    /* default flag and numeric repeat count */
  554.  
  555. {
  556.     register int inc;    /* increment to next line [sgn(n)] */
  557.     int count;
  558.  
  559.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  560.         return(rdonly());    /* we are in read only mode    */
  561.  
  562.     if (f == FALSE)
  563.         count = 1;
  564.     else
  565.         count = n;
  566.     n = reglines();
  567.  
  568.     /* loop thru indenting n lines */
  569.     inc = ((n > 0) ? 1 : -1);
  570.     while (n) {
  571.         curwp->w_doto = 0;    /* start at the beginning */
  572.  
  573.         /* shift current line using tabs */
  574.         if (!((curbp->b_mode & MDCMOD) &&
  575.              (lgetc(curwp->w_dotp, curwp->w_doto) == '#')) ) {
  576.                 linsert(count, '\t');
  577.         }
  578.  
  579.         /* advance/or back to the next line */
  580.         forwline(TRUE, inc);
  581.         n -= inc;
  582.     }
  583.  
  584.     curwp->w_doto = 0;
  585.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  586.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  587.     return(TRUE);
  588. }
  589.  
  590. PASCAL NEAR undent_region(f, n) /* undent a region n tab-stops */
  591.  
  592. int f,n;    /* default flag and numeric repeat count */
  593.  
  594. {
  595.     register int inc;    /* increment to next line [sgn(n)] */
  596.     int i, count;
  597.  
  598.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  599.         return(rdonly());    /* we are in read only mode    */
  600.  
  601.     if (f == FALSE)
  602.         count = 1;
  603.     else
  604.         count = n;
  605.     n = reglines();
  606.  
  607.     /* loop thru undenting n lines */
  608.     inc = ((n > 0) ? 1 : -1);
  609.     while (n) {
  610.         /* unshift current line using tabs */
  611.         for (i = 0; i < count; i++) {
  612.             curwp->w_doto = 0;    /* start at the beginning */
  613.             if ((curwp->w_dotp->l_used > 0) &&
  614.                 (lgetc(curwp->w_dotp, curwp->w_doto) == '\t')) {
  615.                 ldelete(1L, FALSE);
  616.             }
  617.         }
  618.  
  619.         /* advance/or back to the next line */
  620.         forwline(TRUE, inc);
  621.         n -= inc;
  622.     }
  623.  
  624.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  625.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  626.     return(TRUE);
  627. }
  628.