home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / text / jed / src / jed.lha / movement.c < prev    next >
C/C++ Source or Header  |  1993-01-16  |  16KB  |  864 lines

  1.  
  2. /*
  3.  * MOVEMENT.C
  4.  * (c) 1992 J.Harper
  5.  */
  6.  
  7. #include "jed.h"
  8. #include "jed_protos.h"
  9.  
  10. Prototype   VALUE * cmd_move        (LONG, VALUE *);
  11. Prototype   VOID    setautomark        (VOID);
  12. Local        LONG    moveautomark    (VOID);
  13. Local        LONG    movebookmark    (WORD);
  14. Local        LONG    setbookmark        (WORD);
  15. Prototype   VOID    killmarklist    (TX *);
  16. Local        LONG    moveblockstart    (VOID);
  17. Local        LONG    moveblockend    (VOID);
  18. Local        LONG    movecolumn        (WORD);
  19. Prototype   LONG    movedownpages    (LONG);
  20. Prototype   LONG    moveuppages        (LONG);
  21. Prototype   LONG    movedownlines    (LONG);
  22. Prototype   LONG    moveuplines        (LONG);
  23. Prototype   LONG    moveeof        (VOID);
  24. Prototype   LONG    moveeol        (VOID);
  25. Prototype   LONG    movesof        (VOID);
  26. Prototype   LONG    movesol        (VOID);
  27. Prototype   LONG    movelinenum        (LONG);
  28. Prototype   LONG    moveleft        (WORD);
  29. Prototype   LONG    moveright        (WORD);
  30. Local        LONG    movematchingbrac    (VOID);
  31. Local        LONG    movenextchar    (LONG);
  32. Local        LONG    moveprevchar    (LONG);
  33. Prototype   LONG    movenexttab        (LONG);
  34. Prototype   LONG    moveprevtab        (LONG);
  35. Prototype   LONG    movenextword    (LONG);
  36. Prototype   LONG    moveprevword    (LONG);
  37. Prototype   BOOL    moveoffset        (LONG);
  38. Prototype   VOID    positioncursorfine    (WORD, WORD);
  39.  
  40. VALUE *
  41. cmd_move(LONG argc, VALUE *argv)
  42. {
  43.     STRPTR arg = ARG1.val_Value.String;
  44.     LONG rc;
  45.     BOOL argok = TRUE;
  46.  
  47.     if(!TPLATE1(VTF_STRING))
  48.     return(&RES);
  49.  
  50.     switch(*arg++)
  51.     {
  52.     case 'a':
  53.         if(*arg == 'm')
  54.         rc = moveautomark();
  55.         break;
  56.     case 'b':
  57.         switch(*arg++)
  58.         {
  59.         case 'm':
  60.             if(ARG2.val_Type == VTF_NUMBER)
  61.             rc = movebookmark((WORD)ARG2.val_Value.Number);
  62.             else
  63.             argok = FALSE;
  64.             break;
  65.         case 's':
  66.             rc = moveblockstart();
  67.             break;
  68.         case 'e':
  69.             rc = moveblockend();
  70.             break;
  71.         }
  72.         break;
  73.     case 'c':
  74.         if(*arg++ == 'n')
  75.         {
  76.         if(ARG2.val_Type == VTF_NUMBER)
  77.             rc = movecolumn((WORD)ARG2.val_Value.Number);
  78.         else
  79.             argok = FALSE;
  80.         }
  81.         break;
  82.     case 'd':
  83.         if(ARG2.val_Type == VTF_NUMBER)
  84.         {
  85.         if(*arg == 'p')
  86.             rc = movedownpages(ARG2.val_Value.Number);
  87.         else
  88.             rc = movedownlines(ARG2.val_Value.Number);
  89.         }
  90.         else
  91.         argok = FALSE;
  92.         break;
  93.     case 'e':
  94.         switch(*arg++)
  95.         {
  96.         case 'f':
  97.             rc = moveeof();
  98.             break;
  99.         case 'l':
  100.             rc = moveeol();
  101.             break;
  102.         }
  103.         break;
  104.     case 'l':
  105.         if(ARG2.val_Type == VTF_NUMBER)
  106.         {
  107.         switch(*arg++)
  108.         {
  109.             case 't':
  110.             rc = moveprevtab(ARG2.val_Value.Number);
  111.             break;
  112.             case 'n':
  113.             rc = movelinenum(ARG2.val_Value.Number);
  114.             default:
  115.             rc = moveleft((WORD)ARG2.val_Value.Number);
  116.             break;
  117.         }
  118.         }
  119.         else
  120.         argok = FALSE;
  121.         break;
  122.     case 'm':
  123.         if(*arg == 'b')
  124.         rc = movematchingbrac();
  125.         break;
  126.     case 'n':
  127.         if(ARG2.val_Type == VTF_NUMBER)
  128.         {
  129.         switch(*arg++)
  130.         {
  131.             case 'c':
  132.             rc = movenextchar(ARG2.val_Value.Number);
  133.             break;
  134.             case 'w':
  135.             rc = movenextword(ARG2.val_Value.Number);
  136.             break;
  137.         }
  138.         }
  139.         else
  140.         argok = FALSE;
  141.         break;
  142.     case 'o':
  143.         if(ARG2.val_Type == VTF_NUMBER)
  144.         rc = moveoffset(ARG2.val_Value.Number);
  145.         else
  146.         argok = FALSE;
  147.         break;
  148.     case 'p':
  149.         if(ARG2.val_Type == VTF_NUMBER)
  150.         {
  151.         switch(*arg++)
  152.         {
  153.             case 'c':
  154.             rc = moveprevchar(ARG2.val_Value.Number);
  155.             break;
  156.             case 'w':
  157.             rc = moveprevword(ARG2.val_Value.Number);
  158.             break;
  159.         }
  160.         }
  161.         else
  162.         argok = FALSE;
  163.         break;
  164.     case 'r':
  165.         if(ARG2.val_Type == VTF_NUMBER)
  166.         {
  167.         switch(*arg++)
  168.         {
  169.             case 't':
  170.             rc = movenexttab(ARG2.val_Value.Number);
  171.             break;
  172.             default:
  173.             rc = moveright((WORD)ARG2.val_Value.Number);
  174.             break;
  175.         }
  176.         }
  177.         else
  178.         argok = FALSE;
  179.         break;
  180.     case 's':
  181.         switch(*arg++)
  182.         {
  183.         case 'f':
  184.             rc = movesof();
  185.             break;
  186.         case 'l':
  187.             rc = movesol();
  188.             break;
  189.         case 'm':
  190.             if(ARG2.val_Type == VTF_NUMBER)
  191.             rc = setbookmark((WORD)ARG2.val_Value.Number);
  192.             else
  193.             argok = FALSE;
  194.             break;
  195.         }
  196.         break;
  197.     case 'u':
  198.         if(ARG2.val_Type == VTF_NUMBER)
  199.         {
  200.         if(*arg == 'p')
  201.             rc = moveuppages(ARG2.val_Value.Number);
  202.         else
  203.             rc = moveuplines(ARG2.val_Value.Number);
  204.         break;
  205.         }
  206.         else
  207.         argok = FALSE;
  208.     default:
  209.         settitle(BadArgMsg);
  210.         rc = FALSE;
  211.     }
  212.     if(!argok)
  213.     {
  214.     settitle("syntax error: argument 2 should be a number");
  215.     rc = FALSE;
  216.     }
  217.     setnumres(rc);
  218.     return(&RES);
  219. }
  220.  
  221. VOID
  222. setautomark(VOID)
  223. {
  224.     VW *vw = CurrVW;
  225.     vw->vw_AutoMark = vw->vw_CursorPos;
  226. }
  227.  
  228. Local LONG
  229. moveautomark(VOID)
  230. {
  231.     VW *vw = CurrVW;
  232.     POS temp = vw->vw_CursorPos;
  233.  
  234.     vw->vw_CursorPos = vw->vw_AutoMark;
  235.     vw->vw_AutoMark = temp;
  236.     resyncxy();
  237.     return(TRUE);
  238. }
  239.  
  240. Local LONG
  241. movebookmark(WORD markNum)
  242. {
  243.     VW *vw = CurrVW;
  244.     TX *tx = vw->vw_Tx;
  245.     MARK *mark;
  246.  
  247.     for(mark = (MARK *)tx->tx_Marks.mlh_Head; mark->mk_Node.mln_Succ; mark = (MARK *)mark->mk_Node.mln_Succ)
  248.     {
  249.     if(mark->mk_Index == markNum)
  250.         break;
  251.     }
  252.     if(mark->mk_Node.mln_Succ)
  253.     {
  254.     setautomark();
  255.     vw->vw_CursorPos = mark->mk_Pos;
  256.     resyncxy();
  257.     return(TRUE);
  258.     }
  259.     settitle("error: no mark of that number");
  260.     return(FALSE);
  261. }
  262.  
  263. Local LONG
  264. setbookmark(WORD markNum)
  265. {
  266.     VW *vw = CurrVW;
  267.     TX *tx = vw->vw_Tx;
  268.     MARK *mark;
  269.  
  270.     for(mark = (MARK *)tx->tx_Marks.mlh_Head; mark->mk_Node.mln_Succ; mark = (MARK *)mark->mk_Node.mln_Succ)
  271.     {
  272.     if(mark->mk_Index == markNum)
  273.         break;
  274.     }
  275.     if(!mark->mk_Node.mln_Succ)
  276.     {
  277.     if(mark = AllocVec(sizeof(MARK), MEMF_CLEAR))
  278.     {
  279.         AddMTail(&tx->tx_Marks, &mark->mk_Node);
  280.         mark->mk_Index = markNum;
  281.     }
  282.     else
  283.     {
  284.         settitle(NoMemMsg);
  285.         return(FALSE);
  286.     }
  287.     }
  288.     mark->mk_Pos = vw->vw_CursorPos;
  289.     settitle("mark set");
  290.     return(TRUE);
  291. }
  292.  
  293. VOID
  294. killmarklist(TX *tx)
  295. {
  296.     MARK *thismark, *nextmark;
  297.     thismark = (MARK *)tx->tx_Marks.mlh_Head;
  298.     while(nextmark = (MARK *)thismark->mk_Node.mln_Succ)
  299.     {
  300.     RemoveM(&thismark->mk_Node);
  301.     FreeVec(thismark);
  302.     thismark = nextmark;
  303.     }
  304. }
  305.  
  306. Local LONG
  307. moveblockstart(VOID)
  308. {
  309.     VW *vw = CurrVW;
  310.     if((!vw->vw_BlockStatus) || (vw->vw_BlockStatus == 1))
  311.     {
  312.     setautomark();
  313.     vw->vw_CursorPos = vw->vw_Block[0];
  314.     resyncxy();
  315.     return(TRUE);
  316.     }
  317.     return(FALSE);
  318. }
  319.  
  320. Local LONG
  321. moveblockend(VOID)
  322. {
  323.     VW *vw = CurrVW;
  324.     if((!vw->vw_BlockStatus) || (vw->vw_BlockStatus == 2))
  325.     {
  326.     setautomark();
  327.     vw->vw_CursorPos = vw->vw_Block[1];
  328.     resyncxy();
  329.     return(TRUE);
  330.     }
  331.     return(FALSE);
  332. }
  333.  
  334. Local LONG
  335. movecolumn(WORD col)
  336. {
  337.     CurrVW->vw_CursorPos.pos_Col = col - 1;
  338.     resyncx();
  339.     return(TRUE);
  340. }
  341.  
  342. LONG
  343. movedownpages(LONG pages)
  344. {
  345.     VW *vw = CurrVW;
  346.     LONG newline, rc;
  347.  
  348.     newline = vw->vw_CursorPos.pos_Line + (pages * vw->vw_MaxY);
  349.     if(newline >= vw->vw_Tx->tx_NumLines)
  350.     {
  351.     newline = vw->vw_Tx->tx_NumLines - 1;
  352.     rc = FALSE;
  353.     }
  354.     else
  355.     {
  356.     vw->vw_StartLine += (pages * vw->vw_MaxY);
  357.     vw->vw_RefreshType |= RFF_ALL;
  358.     rc = TRUE;
  359.     }
  360.     vw->vw_CursorPos.pos_Line = newline;
  361.     resyncy();
  362.     return(rc);
  363. }
  364.  
  365. LONG
  366. moveuppages(LONG pages)
  367. {
  368.     VW *vw = CurrVW;
  369.     LONG newline, rc;
  370.  
  371.     newline = vw->vw_CursorPos.pos_Line - (pages * vw->vw_MaxY);
  372.     if(newline < 0)
  373.     {
  374.     newline = 0;
  375.     rc = FALSE;
  376.     }
  377.     else
  378.     {
  379.     vw->vw_StartLine -= (pages * vw->vw_MaxY);
  380.     if(vw->vw_StartLine < 0)
  381.         vw->vw_StartLine = 0;
  382.     vw->vw_RefreshType |= RFF_ALL;
  383.     rc = TRUE;
  384.     }
  385.     vw->vw_CursorPos.pos_Line = newline;
  386.     resyncy();
  387.     return(rc);
  388. }
  389.  
  390. LONG
  391. movedownlines(LONG lines)
  392. {
  393.     VW *vw = CurrVW;
  394.     LONG newline, rc;
  395.  
  396.     newline = vw->vw_CursorPos.pos_Line + lines;
  397.     if(newline >= vw->vw_Tx->tx_NumLines)
  398.     {
  399.     newline = vw->vw_Tx->tx_NumLines - 1;
  400.     rc = FALSE;
  401.     }
  402.     else
  403.     rc = TRUE;
  404.     vw->vw_CursorPos.pos_Line = newline;
  405.     resyncy();
  406.     return(rc);
  407. }
  408.  
  409. LONG
  410. moveuplines(LONG lines)
  411. {
  412.     VW *vw = CurrVW;
  413.     LONG newline, rc;
  414.  
  415.     newline = vw->vw_CursorPos.pos_Line - lines;
  416.     if(newline < 0)
  417.     {
  418.     newline = 0;
  419.     rc = FALSE;
  420.     }
  421.     else
  422.     rc = TRUE;
  423.     vw->vw_CursorPos.pos_Line = newline;
  424.     resyncy();
  425.     return(rc);
  426. }
  427.  
  428. LONG
  429. moveeof(VOID)
  430. {
  431.     VW *vw = CurrVW;
  432.  
  433.     setautomark();
  434.     vw->vw_CursorPos.pos_Line = vw->vw_Tx->tx_NumLines - 1;
  435.     resyncy();
  436.     return(TRUE);
  437. }
  438.  
  439. LONG
  440. moveeol(VOID)
  441. {
  442.     VW *vw = CurrVW;
  443.  
  444.     vw->vw_CursorPos.pos_Col = vw->vw_Tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1;
  445.     resyncx();
  446.     return(TRUE);
  447. }
  448.  
  449. LONG
  450. movesof(VOID)
  451. {
  452.     setautomark();
  453.     CurrVW->vw_CursorPos.pos_Line = 0;
  454.     resyncy();
  455.     return(TRUE);
  456. }
  457.  
  458. LONG
  459. movesol(VOID)
  460. {
  461.     CurrVW->vw_CursorPos.pos_Col = 0;
  462.     resyncx();
  463.     return(TRUE);
  464. }
  465.  
  466. LONG
  467. movelinenum(LONG line)
  468. {
  469.     VW *vw = CurrVW;
  470.     LONG rc;
  471.  
  472.     if(--line < 0)
  473.     {
  474.     settitle("error: lines start at 1");
  475.     rc = FALSE;
  476.     }
  477.     else
  478.     {
  479.     if(line >= vw->vw_Tx->tx_NumLines)
  480.     {
  481.         settitlefmt("error: line %ld doesn't exist!", line + 1);
  482.         rc = FALSE;
  483.     }
  484.     else
  485.     {
  486.         setautomark();
  487.         vw->vw_CursorPos.pos_Line = line;
  488.         resyncy();
  489.         rc = TRUE;
  490.     }
  491.     }
  492.     return(rc);
  493. }
  494.  
  495. LONG
  496. moveleft(WORD distance)
  497. {
  498.     VW *vw = CurrVW;
  499.     LONG rc;
  500.  
  501.     vw->vw_CursorPos.pos_Col -= distance;
  502.     if(vw->vw_CursorPos.pos_Col < 0)
  503.     {
  504.     vw->vw_CursorPos.pos_Col = 0;
  505.     rc = FALSE;
  506.     }
  507.     else
  508.     rc = TRUE;
  509.     resyncx();
  510.     return(rc);
  511. }
  512.  
  513. LONG
  514. moveright(WORD distance)
  515. {
  516.     VW *vw = CurrVW;
  517.  
  518.     vw->vw_CursorPos.pos_Col += distance;
  519.     resyncx();
  520.     return(TRUE);
  521. }
  522.  
  523. Local LONG
  524. movematchingbrac(VOID)
  525. {
  526. #define NUM_BRAC_TYPES 10
  527.     static UBYTE bracs[] =
  528.     {
  529.     '{', '}',
  530.     '(', ')',
  531.     '[', ']',
  532.     '`', '\'',
  533.     '<', '>'
  534.     };
  535.  
  536.     VW *vw = CurrVW;
  537.     TX *tx = vw->vw_Tx;
  538.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  539.     if(vw->vw_CursorPos.pos_Col < line->ln_Strlen)
  540.     {
  541.     UBYTE startc = line->ln_Line[vw->vw_CursorPos.pos_Col];
  542.     WORD i;
  543.     for(i = 0; i < NUM_BRAC_TYPES; i++)
  544.     {
  545.         if(startc == bracs[i])
  546.         break;
  547.     }
  548.     if(i < NUM_BRAC_TYPES)
  549.     {
  550.         WORD x = vw->vw_CursorPos.pos_Col;
  551.         LONG y = vw->vw_CursorPos.pos_Line;
  552.         WORD braccount = 1;
  553.         BOOL found = FALSE;
  554.         if(i & 1)
  555.         {
  556.         /* search backwards
  557.          */
  558.         UBYTE endc = bracs[i - 1];
  559.         while(!found)
  560.         {
  561.             UBYTE c;
  562.             if(--x < 0)
  563.             {
  564.             if(--y < 0)
  565.             {
  566.                 settitle("error: can't find matching bracket");
  567.                 return(FALSE);
  568.             }
  569.             line--;
  570.             x = line->ln_Strlen - 1;
  571.             }
  572.             c = line->ln_Line[x];
  573.             if(c == startc)
  574.             braccount++;
  575.             else if(c == endc)
  576.             {
  577.             if(!(--braccount))
  578.                 found = TRUE;
  579.             }
  580.         }
  581.         }
  582.         else
  583.         {
  584.         /* search forwards
  585.          */
  586.         UBYTE endc = bracs[i + 1];
  587.         while(!found)
  588.         {
  589.             UBYTE c;
  590.             if(++x >= line->ln_Strlen)
  591.             {
  592.             if(++y >= tx->tx_NumLines)
  593.             {
  594.                 settitle("error: can't find matching bracket");
  595.                 return(FALSE);
  596.             }
  597.             line++;
  598.             x = 0;
  599.             }
  600.             c = line->ln_Line[x];
  601.             if(c == startc)
  602.             braccount++;
  603.             else if(c == endc)
  604.             {
  605.             if(!(--braccount))
  606.                 found = TRUE;
  607.             }
  608.         }
  609.         }
  610.         vw->vw_CursorPos.pos_Col = x;
  611.         vw->vw_CursorPos.pos_Line = y;
  612.         resyncxy();
  613.         return(TRUE);
  614.     }
  615.     }
  616.     settitle("error: cursor must be on a bracket");
  617.     return(FALSE);
  618. }
  619.  
  620. Local LONG
  621. movenextchar(LONG chars)
  622. {
  623.     VW *vw = CurrVW;
  624.     TX *tx = vw->vw_Tx;
  625.     LONG rc = FALSE;
  626.  
  627.     if((vw->vw_CursorPos.pos_Col += chars) >= tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen)
  628.     {
  629.     if(++vw->vw_CursorPos.pos_Line >= tx->tx_NumLines)
  630.     {
  631.         vw->vw_CursorPos.pos_Col -= chars;
  632.         vw->vw_CursorPos.pos_Line--;
  633.     }
  634.     else
  635.     {
  636.         vw->vw_CursorPos.pos_Col = 0;
  637.         resyncxy();
  638.         rc = TRUE;
  639.     }
  640.     }
  641.     else
  642.     {
  643.     resyncx();
  644.     rc = TRUE;
  645.     }
  646.     return(rc);
  647. }
  648.  
  649. Local LONG
  650. moveprevchar(LONG chars)
  651. {
  652.     VW *vw = CurrVW;
  653.     LONG rc = FALSE;
  654.  
  655.     if((vw->vw_CursorPos.pos_Col -= chars) < 0)
  656.     {
  657.     if(--vw->vw_CursorPos.pos_Line < 0)
  658.     {
  659.         vw->vw_CursorPos.pos_Line = 0;
  660.         vw->vw_CursorPos.pos_Col += chars;
  661.     }
  662.     else
  663.     {
  664.         vw->vw_CursorPos.pos_Col = vw->vw_Tx->tx_Lines[vw->vw_CursorPos.pos_Line].ln_Strlen - 1;
  665.         resyncxy();
  666.         rc = TRUE;
  667.     }
  668.     }
  669.     else
  670.     {
  671.     resyncx();
  672.     rc = TRUE;
  673.     }
  674.     return(rc);
  675. }
  676.  
  677. LONG
  678. movenexttab(LONG tabs)
  679. {
  680.     VW *vw = CurrVW;
  681.  
  682.     vw->vw_CursorPos.pos_Col = ((vw->vw_CursorPos.pos_Col / vw->vw_Prefs.prf_TabSize) + 1) * vw->vw_Prefs.prf_TabSize;
  683.     resyncx();
  684.     return(TRUE);
  685. }
  686.  
  687. LONG
  688. moveprevtab(LONG tabs)
  689. {
  690.     VW *vw = CurrVW;
  691.     LONG rc;
  692.  
  693.     if(vw->vw_CursorPos.pos_Col)
  694.     {
  695.     vw->vw_CursorPos.pos_Col = (((vw->vw_CursorPos.pos_Col - 1) / vw->vw_Prefs.prf_TabSize)) * vw->vw_Prefs.prf_TabSize;
  696.     if(vw->vw_CursorPos.pos_Col < 0)
  697.     {
  698.         vw->vw_CursorPos.pos_Col = 0;
  699.         rc = FALSE;
  700.     }
  701.     else
  702.         rc = TRUE;
  703.     resyncx();
  704.     return(rc);
  705.     }
  706.     return(TRUE);
  707. }
  708.  
  709. LONG
  710. movenextword(LONG words)
  711. {
  712.     VW *vw = CurrVW;
  713.     TX *tx = vw->vw_Tx;
  714.     LONG rc = TRUE;
  715.     POS oldcurs = vw->vw_CursorPos;
  716.  
  717.     while(words--)
  718.     {
  719.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  720.     STRPTR word;
  721.     if(vw->vw_CursorPos.pos_Col >= line->ln_Strlen)
  722.         vw->vw_CursorPos.pos_Col = line->ln_Strlen - 1;
  723.     word = line->ln_Line + vw->vw_CursorPos.pos_Col;
  724.     while(isalnum(*word))
  725.         word++;
  726.     while(!isalnum(*word))
  727.     {
  728.         if(*word++ == 0)
  729.         {
  730.         if(++vw->vw_CursorPos.pos_Line >= tx->tx_NumLines)
  731.         {
  732.             vw->vw_CursorPos.pos_Line--;
  733.             word--;
  734.             rc = FALSE;
  735.             goto end;
  736.         }
  737.         line++;
  738.         word = line->ln_Line;
  739.         }
  740.     }
  741.     vw->vw_CursorPos.pos_Col = word - line->ln_Line;
  742.     }
  743. end:
  744.     if(!rc)
  745.     vw->vw_CursorPos = oldcurs;
  746.     else
  747.     resyncxy();
  748.     return(rc);
  749. }
  750.  
  751. LONG
  752. moveprevword(LONG words)
  753. {
  754.     VW *vw = CurrVW;
  755.     TX *tx = vw->vw_Tx;
  756.     LONG rc = TRUE;
  757.     POS oldcurs = vw->vw_CursorPos;
  758.  
  759.     while(words--)
  760.     {
  761.     LINE *line = tx->tx_Lines + vw->vw_CursorPos.pos_Line;
  762.     STRPTR word;
  763.     if(vw->vw_CursorPos.pos_Col >= line->ln_Strlen)
  764.         vw->vw_CursorPos.pos_Col = line->ln_Strlen - 1;
  765.     word = line->ln_Line + vw->vw_CursorPos.pos_Col;
  766.     while(isalnum(*word))
  767.     {
  768.         if(word-- == line->ln_Line)
  769.         {
  770.         if(--vw->vw_CursorPos.pos_Line < 0)
  771.         {
  772.             vw->vw_CursorPos.pos_Line++;
  773.             word++;
  774.             rc = FALSE;
  775.             goto end;
  776.         }
  777.         line--;
  778.         word = line->ln_Line + line->ln_Strlen - 1;
  779.         }
  780.     }
  781.     while(!isalnum(*word))
  782.     {
  783.         if(word-- == line->ln_Line)
  784.         {
  785.         if(--vw->vw_CursorPos.pos_Line < 0)
  786.         {
  787.             vw->vw_CursorPos.pos_Line++;
  788.             word++;
  789.             rc = FALSE;
  790.             goto end;
  791.         }
  792.         line--;
  793.         word = line->ln_Line + line->ln_Strlen - 1;
  794.         }
  795.     }
  796.     while(isalnum(*word))
  797.     {
  798.         if(word-- == line->ln_Line)
  799.         break;
  800.     }
  801.     vw->vw_CursorPos.pos_Col = word - line->ln_Line + 1;
  802.     }
  803. end:
  804.     if(!rc)
  805.     vw->vw_CursorPos = oldcurs;
  806.     else
  807.     resyncxy();
  808.     return(rc);
  809. }
  810.  
  811. BOOL
  812. moveoffset(LONG offset)
  813. {
  814.     VW *vw = CurrVW;
  815.     TX *tx = vw->vw_Tx;
  816.     LINE *line = tx->tx_Lines;
  817.     LONG linenum = 0;
  818.  
  819.     while(linenum < tx->tx_NumLines)
  820.     {
  821.     offset -= line->ln_Strlen;
  822.     if(offset < 0)
  823.     {
  824.         offset += line->ln_Strlen;
  825.         setautomark();
  826.         vw->vw_CursorPos.pos_Col = offset;
  827.         vw->vw_CursorPos.pos_Line = linenum;
  828.         resyncxy();
  829.         return(TRUE);
  830.     }
  831.     linenum++;
  832.     line++;
  833.     }
  834.     return(FALSE);
  835. }
  836.  
  837. VOID
  838. positioncursorfine(WORD x, WORD y)
  839. {
  840.     VW *vw = CurrVW;
  841.     struct Window *wd = vw->vw_Window;
  842.  
  843.     if(x >= wd->Width)
  844.     vw->vw_CursorPos.pos_Col = vw->vw_StartCol + vw->vw_MaxX + 1;
  845.     else if(x <= 0)
  846.     vw->vw_CursorPos.pos_Col = vw->vw_StartCol - 1;
  847.     else
  848.     vw->vw_CursorPos.pos_Col = vw->vw_StartCol + ((x - (WORD)vw->vw_XStartPix) / (WORD)vw->vw_FontX);
  849.  
  850.     if(y >= vw->vw_Window->Height)
  851.     vw->vw_CursorPos.pos_Line = vw->vw_StartLine + vw->vw_MaxY;
  852.     else if(y <= 0)
  853.     vw->vw_CursorPos.pos_Line = vw->vw_StartLine - 1;
  854.     else
  855.     vw->vw_CursorPos.pos_Line = vw->vw_StartLine + ((y - (WORD)vw->vw_YStartPix) / (WORD)vw->vw_FontY);
  856.  
  857.     if(vw->vw_CursorPos.pos_Col < 0)
  858.     vw->vw_CursorPos.pos_Col = 0;
  859.     if(vw->vw_CursorPos.pos_Line < 0)
  860.     vw->vw_CursorPos.pos_Line = 0;
  861.     if(vw->vw_CursorPos.pos_Line >= vw->vw_Tx->tx_NumLines)
  862.     vw->vw_CursorPos.pos_Line = vw->vw_Tx->tx_NumLines - 1;
  863. }
  864.