home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / 'liner_394.lzh / 'Liner / Source / Liner.c < prev    next >
C/C++ Source or Header  |  1990-10-28  |  40KB  |  1,256 lines

  1. /*
  2.              'Liner Version 2.00.  Written by Dave Schreiber    
  3.        ©1988, 1989, 1990 by Dave Schreiber.  All Rights Reserved.             
  4.  
  5. 2.00 completed Saturday, June 23, 1990
  6. 1.32 completed Monday, October 30, 1989                                
  7. 1.31 completed Friday, October 6, 1989                                 
  8. 1.30 completed Saturday, February 25, 1989                             
  9. 1.20 completed Friday, November 11, 1988                               
  10. 1.10 completed Friday, October 14, 1988                                
  11. 1.00 completed Friday, September 9, 1988                               
  12.  
  13. Length of source code:  5714 lines
  14.  
  15. Compiled with Lattice C V5.02                                          
  16. To compile:  1> lc -cw -j30 -L+YAFR:YAFR.o 'Liner                      
  17. You must assign YAFR: to the directory where YAFR.o is stored.         
  18. You must also assign LINER: to the directory where the 'Liner source   
  19. is located.                                                            
  20.  
  21. *********************************
  22.  
  23. 'Liner is an outliner, with up to six levels of depth, and up to       
  24. 52 items per level (each isolated section).  It has both clipboard and 
  25. non-clipboard support of CUT, COPY, and, for single lines of text, PASTE.
  26. It can output files in its own format, or in ASCII (to disk or printer).
  27. It can read files in its own format only.  It uses dynamic memory
  28. allocation to allow an infinite number of items (memory providing).
  29. It supports ARexx, Workbench  icons, overscanned and interlaced screens
  30.  
  31. *********************************
  32.  
  33. Amiga features of note that are used:                                  
  34. console device, disk i/o, printer i/o, clipboard i/o                   
  35.  
  36. *********************************
  37.  
  38. Intuition objects (screen, windows, gadgets, menus, etc.) generated by 
  39. PowerWindows Version 2.0
  40.  
  41. *********************************
  42. *********************************
  43.  
  44. V1.1 corrects some bugs, doubles the number of characters available    
  45. for filenames, and improves PrintItemList() so that it doesn't always  
  46. print the entire item list
  47.  
  48. ------------
  49.  
  50. 1.2 allows the toggling between 640x200 & 640x400 screens and the      
  51. choice of the order that levels appear in, has a completely reworked   
  52. About... window, lets the user change the level of all the items       
  53. in a highlighted block, and now displays the current filename          
  54. in the title bar.
  55.  
  56. ------------
  57.  
  58. 1.3 adds support for user-selected keymaps, and now prints an asterisk 
  59. in the title bar if an outline has been edited but not saved.  It also 
  60. includes my very own file requester, YAFR (Yet Another File Requester) 
  61. based in principal upon Charlie Heath's, but with a lot more buttons.  
  62.  
  63. ------------
  64.  
  65. 1.31 changes the default device where files are located from DF0: to   
  66. the current directory                                                  
  67.  
  68. ------------
  69.  
  70. 1.32 fixed a bug that kept the screen from updating properly after a   
  71. paste.  Also uses YAFR V1.1                                            
  72.  
  73. ------------
  74.  
  75. 2.00 added a number of things:                                         
  76. -Two way ARexx support                                                 
  77. -Search/replace                                                             
  78. -Greater Clipboard support (a block of lines that are CUT or COPYed are
  79.     now sent to the Clipboard
  80. -Truer WYSIWYG:  double spacing  is now shown on screen
  81. -Support for more than one line per number
  82. -Icon support:  icons now can be created when a document is saved. When
  83.     the icon is double clicked on, 'Liner will be run and the document 
  84.     loaded
  85. -Support for overscanned screens, allowing more rows of text on screen 
  86.     at once
  87. -Adjustable screen colors
  88. -An option to save various settings in a preferences file
  89. -A new, more compact file format that supports the new 'Liner's        
  90.     improvements
  91. -The limit of highlighting only one screenful of lines at a time has   
  92.     been removed.  There is now no limit
  93. -Support for up to 52 lines per level, up from 26 in 1.32
  94. -Uses YAFR V1.20.  See the file YAFR.c for more details.
  95. In addition, a bug that would cause 'Liner to crash if the user
  96. attempted to load a file that wasn't a 'Liner outline has been removed
  97.  
  98. *********************************
  99.  
  100. */
  101.  
  102. #include "globals.h"
  103.  
  104. /*Outline characters*/
  105. char *OutLineChars[6][99]=
  106. {
  107.    {
  108.       {"I."},{"II."},{"III."},{"IV."},{"V."},{"VI."},{"VII."},{"VIII."},
  109.       {"IX."},{"X."},{"XI."},{"XII."},{"XIII."},{"XIV."},{"XV."},{"XVI."},
  110.       {"XVII."},{"XVIII."},{"XIX."},{"XX."},{"XXI."},{"XXII."},{"XXIII."},
  111.       {"XXIV."},{"XXV."},{"XXVI."},{"XXVII."},{"XXVIII."},{"XXIX."},{"XXX."},
  112.       {"XXXI."},{"XXXII."},{"XXXIII."},{"XXXIV."},{"XXXV."},{"XXXVI."},
  113.       {"XXXVII."},{"XXXVIII."},{"IXL."},{"XL."},{"XLI."},{"XLII."},{"XLIII."},
  114.       {"XLIV."},{"XLV."},{"XLVI."},{"XLVII."},{"XLVIII."},{"IL."},{"L."},
  115.       {"LI."},{"LII."}
  116.    },
  117.  
  118.    {
  119.       {"A."},{"B."},{"C."},{"D."},{"E."},{"F."},{"G."},{"H."},{"I."},
  120.       {"J."},{"K."},{"L."},{"M."},{"N."},{"O."},{"P."},{"Q."},{"R."},
  121.       {"S."},{"T."},{"U."},{"V."},{"W."},{"X."},{"Y."},{"Z."},{"AA."},
  122.       {"AB."},{"AC."},{"AD."},{"AE."},{"AF."},{"AG."},{"AH."},{"AI."},
  123.       {"AJ."},{"AK."},{"AL."},{"AM."},{"AN."},{"AO."},{"AP."},{"AQ."},
  124.       {"AR."},{"AS."},{"AT."},{"AU."},{"AV."},{"AW."},{"AX."},{"AY."},
  125.       {"AZ."}
  126.    },
  127.  
  128.    {
  129.       {"1."},{"2."},{"3."},{"4."},{"5."},{"6."},{"7."},{"8."},{"9."},
  130.       {"10."},{"11."},{"12."},{"13."},{"14."},{"15."},{"16."},{"17."},
  131.       {"18."},{"19."},{"20."},{"21."},{"22."},{"23."},{"24."},{"25."},
  132.       {"26."},{"27."},{"28."},{"29."},{"30."},{"31."},{"32."},{"33."},
  133.       {"34."},{"35."},{"36."},{"37."},{"38."},{"39."},{"40."},{"41."},
  134.       {"42."},{"43."},{"44."},{"45."},{"46."},{"47."},{"48."},{"49."},
  135.       {"50."},{"51."},{"52."}
  136.    },
  137.  
  138.    {
  139.       {"a."},{"b."},{"c."},{"d."},{"e."},{"f."},{"g."},{"h."},{"i."},
  140.       {"j."},{"k."},{"l."},{"m."},{"n."},{"o."},{"p."},{"q."},{"r."},
  141.       {"s."},{"t."},{"u."},{"v."},{"w."},{"x."},{"y."},{"z."},{"aa."},
  142.       {"ab."},{"ac."},{"ad."},{"ae."},{"af."},{"ag."},{"ah."},{"ai."},
  143.       {"aj."},{"ak."},{"al."},{"am."},{"an."},{"ao."},{"ap."},{"aq."},
  144.       {"ar."},{"as."},{"at."},{"au."},{"av."},{"aw."},{"ax."},{"ay."},
  145.       {"az."}   
  146.    },
  147.  
  148.    {
  149.       {"1)"},{"2)"},{"3)"},{"4)"},{"5)"},{"6)"},{"7)"},{"8)"},{"9)"},
  150.       {"10)"},{"11)"},{"12)"},{"13)"},{"14)"},{"15)"},{"16)"},{"17)"},
  151.       {"18)"},{"19)"},{"20)"},{"21)"},{"22)"},{"23)"},{"24)"},{"25)"},
  152.       {"26)"},{"27)"},{"28)"},{"29)"},{"30)"},{"31)"},{"32)"},{"33)"},
  153.       {"34)"},{"35)"},{"36)"},{"37)"},{"38)"},{"39)"},{"40)"},{"41)"},
  154.       {"42)"},{"43)"},{"44)"},{"45)"},{"46)"},{"47)"},{"48)"},{"49)"},
  155.       {"50)"},{"51)"},{"52)"}
  156.    },
  157.  
  158.    {
  159.       {"a)"},{"b)"},{"c)"},{"d)"},{"e)"},{"f)"},{"g)"},{"h)"},{"i)"},
  160.       {"j)"},{"k)"},{"l)"},{"m)"},{"n)"},{"o)"},{"p)"},{"q)"},{"r)"},
  161.       {"s)"},{"t)"},{"u)"},{"v)"},{"w)"},{"x)"},{"y)"},{"z)"},{"aa)"},
  162.       {"ab)"},{"ac)"},{"ad)"},{"ae)"},{"af)"},{"ag)"},{"ah)"},{"ai)"},
  163.       {"aj)"},{"ak)"},{"al)"},{"am)"},{"an)"},{"ao)"},{"ap)"},{"aq)"},
  164.       {"ar)"},{"as)"},{"at)"},{"au)"},{"av)"},{"aw)"},{"ax)"},{"ay)"},
  165.       {"az)"}
  166.    },
  167. };
  168.  
  169. /*The position of each special character in the array below*/
  170. extern int SCPos[]=
  171.    {0,1,4,5,9,13,14,16,17,18,19,20,21,23,25,27,29};
  172.  
  173. /*Special characters (TAB, RETURN, etc.)*/
  174. extern char SpecChars[]=
  175.    {
  176.    32,
  177.    8,CSI,'P',
  178.    0,
  179.    0x0D,0x0A,CSI,'L',
  180.    0x0D,0x0A,CSI,'L',
  181.    0,
  182.    CSI,'P',
  183.    0,
  184.    0,
  185.    0,
  186.    0,
  187.    0,
  188.    CSI,'A',
  189.    CSI,'B',
  190.    CSI,'C',
  191.    CSI,'D',
  192.    NULL
  193.    };
  194.  
  195. char Inv[]=
  196.    {CSI,'7',0x6d,NULL};
  197. char Norm[]=
  198.    {CSI,'0',0x6d,NULL};
  199.  
  200. _main() /*The main function*/
  201. {
  202.    ULONG Class;
  203.    USHORT Code,Qualifier;
  204.    APTR IAddress;
  205.    SHORT MouseX,MouseY;
  206.    int Seconds,Micros;
  207.    struct IntuiMessage *Message;
  208.    char Buffer[200];
  209.    
  210.    Buffer[0]=NULL;      /*Initialize various variables...*/
  211.    FileName[0]=SFileName[0]=SExt[0]=NULL;
  212.    strcpy(PDirName,"");
  213.    PDName[0]=PFileName[0]=PExt[0]=NULL;
  214.    Modified=FALSE;  /*No modifications, yet*/
  215.    StartingLevel=0;
  216.  
  217.    /*Open all the libraries*/
  218.    IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",1);
  219.    if(IntuitionBase==NULL)    /*Intuition*/
  220.       exit(10);
  221.  
  222.    GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",1);
  223.    if(GfxBase==NULL)          /*Graphics*/
  224.       exit(20);
  225.  
  226.    DosBase=OpenLibrary("dos.library",1);
  227.    if(DosBase==NULL)          /*Dos*/
  228.       Leave(30,"Can't open dos.library!");
  229.      
  230.    IconBase=OpenLibrary("icon.library",1);
  231.    if(IconBase==NULL)         /*Icon*/
  232.       Leave(40,"Can't open icon.library!");
  233.  
  234.  
  235.    OpenARexx();  /*Open the ARexx port*/
  236.  
  237.    ThisProc=(struct Process *)FindTask(NULL);/*Get 'Liner's process structure*/
  238.  
  239.    GetLinerPrefs("liner:liner.prefs"); /*Load the preferences*/
  240.    InterpretPrefs(); /*Install the preferences*/
  241.  
  242.    SetupClipboard(); /*Open the clipboard*/
  243.  
  244.    /*Setup various system variable*/
  245.    DispRows=1;
  246.    PtrX=PtrY=LastX=LastY=1;
  247.    ButtonState=UP;
  248.    InvsMode=ClipMode=NOINV;
  249.    FirstItem=LastItem=FirstScrnItem=CurrentItem=(struct LineItem *)
  250.          InsertItem(NULL,NULL);
  251.    if(FirstItem==NULL)
  252.    {
  253.       CloseGraphics();
  254.       CloseLibrary(IconBase);
  255.       CloseLibrary(GfxBase);
  256.       Leave(50,"Memory too fragmented to run 'Liner!  Exiting.");
  257.    }
  258.    FirstItem->Level=1;
  259.    FirstItem->ItemNumber=0;
  260.    PrintItemList(FirstItem,1);
  261.    PlotCursor(MinX(CurrentItem),1);
  262.  
  263.    if(WBenchMsg != 0)  /*If called from the Workbench...*/
  264.       if(WBenchMsg->sm_NumArgs > 1) /*Outline clicked on instead of 'Liner*/
  265.       {
  266.          CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
  267.             /*Make outline's directory the current directory*/
  268.  
  269.          if(strcmp(WBenchMsg->sm_ArgList[1].wa_Name,"liner.prefs") != 0)
  270.          {     /*Make sure user didn't click on liner.prefs icon*/
  271.             strcpy(FileName,WBenchMsg->sm_ArgList[1].wa_Name);
  272.             strcpy(SFileName,FileName);
  273.                /*Store the outline's filename*/
  274.             ReadItemList(WBenchMsg->sm_ArgList[1].wa_Name);
  275.                /*Load the outline*/
  276.             TitleErrorCancel();
  277.          }
  278.       }
  279.  
  280.    for(;;)    /*The main loop!*/
  281.       {
  282.          /*Wait for something to happen*/
  283.       Wait((1<<Window->UserPort->mp_SigBit) | ARexxSigBit);
  284.       
  285.       CheckRexxPort();  /*Check the ARexx port for any messages*/
  286.  
  287.       while((Message=(struct IntuiMessage *) /*Get the message if IDCMP*/
  288.             GetMsg(Window->UserPort))!=NULL)
  289.          {        /*Get the message's information*/
  290.          Class=Message->Class;
  291.          Code=Message->Code;
  292.          Qualifier=Message->Qualifier;
  293.          MouseX=Message->MouseX;
  294.          MouseY=Message->MouseY;
  295.          Seconds=Message->Seconds;
  296.          Micros=Message->Micros;
  297.  
  298.          IAddress=(APTR)Message->IAddress;
  299.  
  300.          ReplyMsg(Message);   /*Reply to the message*/
  301.  
  302.             /*Decode the message*/
  303.          if(HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,
  304.                Buffer,Seconds,Micros))
  305.             {     /*If the message was a keypress*/
  306.             InsertChar(CurrentItem->Text,Buffer[2],   /*Print the letter*/
  307.                   PosInText(CurrentItem->Level));     /*onto the screen*/
  308.             CurX++;
  309.             WriteConsole(Buffer,-1);
  310.             }
  311.          }
  312.       }
  313. }
  314.  
  315. /*Decode an IDCMP message*/
  316. HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,Buffer,Secs,Micros)
  317. ULONG Class;
  318. USHORT Code,Qualifier;
  319. APTR IAddress;
  320. SHORT MouseX,MouseY;
  321. int Secs,Micros;
  322. char *Buffer;
  323. {
  324.    struct MenuItem *item;
  325.    struct InputEvent KeyEvent;
  326.    Buffer[0]=CSI;
  327.    Buffer[1]=0x40;
  328.    Buffer[2]=NULL;
  329.    switch(Class)
  330.       {
  331.       case MENUPICK: /*There was a menu selection*/
  332.          if(ErrorInTitle)
  333.             TitleErrorCancel();
  334.          while(Code != MENUNULL)
  335.             {
  336.             item=(struct MenuItem *)GetFirstItemAddress(Code);
  337.             HandleEvent(item);
  338.             Code=item->NextSelect;
  339.             }
  340.       case MOUSEBUTTONS:   /*The left mouse button was pushed*/
  341.          if(Code==SELECTDOWN)
  342.             HandleButton(Secs,Micros);
  343.          break;
  344.       case MOUSEMOVE:      /*The mouse was moved*/
  345.          MovedMouse(MouseX,MouseY);
  346.          break;
  347.       /*A key was pressed*/
  348.       case RAWKEY:         /*By using IDCMP RAWKEY as input, and the*/
  349.          if(Code & 0x80)   /*console for output, we can both get input*/
  350.             return(FALSE);  /*and IDCMP messsages without having to try*/
  351.          if(ErrorInTitle)   /*and decode ASCII console messages*/
  352.             TitleErrorCancel(); /*(IDCMP structures are MUCH easier)*/
  353.          if(((Code < 0x41) || (0x5a <= Code && Code <= 0x5e) ||
  354.                (Code==0x4a)) && !(Qualifier & 8))
  355.             {    /*^^^==All the RAWKEY codes for alphanumeric characters*/
  356.             CheckModified();
  357.             KeyEvent.ie_NextEvent=NULL;     /*Create a fake input event*/
  358.             KeyEvent.ie_Class=IECLASS_RAWKEY; /*for RawKeyConvert() to */
  359.             KeyEvent.ie_SubClass=NULL; /*munch on.  Using RawKeyConvert()*/
  360.             KeyEvent.ie_Code=Code;   /*insures that the current keymap*/
  361.             KeyEvent.ie_Qualifier=Qualifier; /*is used*/
  362.             RawKeyConvert(&KeyEvent,&Buffer[2],200,&keymap),ConsoleDevice;
  363.             Buffer[3]=NULL;   /* ^^^ == RAWKEY to ASCII*/
  364.  
  365.             if(InvsMode < NOINV) /*If a block of lines was highlighted*/
  366.                {                 /*when a key was pressed, cancel the*/
  367.                EndBlockInvs();   /*highlight*/
  368.                return(FALSE);
  369.                }
  370.                                  /*If a key was pressed when TEXT was*/
  371.             if(InvsMode)         /*highlighted, delete the text & replace*/
  372.                DelTextBlock();   /*it with the letter pressed*/
  373.  
  374.             /*If the current line isn't full*/
  375.             if(strlen(CurrentItem->Text)<MaxLen(CurrentItem->Level))
  376.                return(TRUE);  /*OK to print the character*/
  377.             else
  378.                return(FALSE); /*Otherwise not*/
  379.             }
  380.          else
  381.             switch(Code)   /*Handle all the "special" characters*/
  382.                {
  383.                case 0x4d:        /*Move cursor down one*/
  384.                   CancelLineInvs();
  385.                   if(Qualifier & 3) /*Handle SHIFT-DOWN*/
  386.                      WholeScreenDown();
  387.                   else if(Qualifier & 8) /*Handle CTRL-DOWN*/
  388.                      JumpToBottom();
  389.                   else
  390.                      CursorDown();
  391.                   break;
  392.                case 0x4c:        /*Move cursor up one*/
  393.                   CancelLineInvs();
  394.                   if(Qualifier & 3)     /*Check for shift*/
  395.                      WholeScreenUp();
  396.                   else if(Qualifier & 8) /*Check for control*/
  397.                      JumpToTop();
  398.                   else
  399.                      CursorUp();
  400.                   break;
  401.                case 0x4e:        /*Move cursor one to the right*/
  402.                   CursorRight(Qualifier);
  403.                   break;
  404.                case 0x4f:        /*Move cursor one to the left*/
  405.                   CursorLeft(Qualifier);
  406.                   break;
  407.                case 0x41:        /*Backspace over a character*/
  408.                   HandleBS();
  409.                   break;
  410.                case 0x46:        /*Delete a character*/
  411.                   CheckModified();
  412.                   if(DelInvs())
  413.                      break;
  414.  
  415.                   if(CurX<MaxX(CurrentItem))
  416.                      {
  417.                      strcpy(Buffer,&SpecChars[SCPos[6]]);
  418.                      Buffer[SCPos[7]-SCPos[6]]=NULL;
  419.                      DeleteChar(CurrentItem->Text,
  420.                            PosInText(CurrentItem->Level));
  421.                      WriteConsole(Buffer,-1);
  422.                      }
  423.                   break;
  424.                case 0x42:           /*TAB (in or out)*/
  425.                   HandleTAB(Qualifier);
  426.                   break;
  427.                case 0x43:  /*Return & Enter */
  428.                case 0x44:  /*Insert a line*/
  429.                   HandleReturn(Qualifier);
  430.                   break;
  431.                }
  432.             return(FALSE);
  433.       }
  434.    return(FALSE);
  435.  
  436. }
  437.  
  438. /*Close everything*/
  439. void CloseStuff()
  440. {
  441.    FreeListMem(FirstItem,LastItem);  /*Free the outline's memory*/
  442.    if(ClipMode < NOINV)
  443.       FreeListMem(ClipStart,ClipEnd); /*Delete any clipped lines*/
  444.    CloseARexx();  /*Close the ARexx port*/
  445.  
  446.    ShutDownClipboard();
  447.    CloseGraphics();           /*Close the screen, etc...*/
  448.    CloseLibrary(IconBase);    /*Close the libraries*/
  449.    CloseLibrary(DosBase);
  450.    CloseLibrary(GfxBase);
  451.    CloseLibrary(IntuitionBase);
  452.    exit(0);
  453. }
  454.  
  455. void HandleBS()   /*Handle the pressing of the backspace key*/
  456. {
  457.    char Buffer[20];
  458.    
  459.    CheckModified();
  460.    
  461.    if(DelInvs())  /*If something is highlighted*/
  462.       return;      /*delete it*/
  463.  
  464.    /*Delete the character, if not at the beginning of the line...*/
  465.    if(CurX>MinX(CurrentItem))
  466.    {
  467.       strcpy(Buffer,&SpecChars[SCPos[1]]);
  468.       Buffer[SCPos[2]-SCPos[1]]=NULL;
  469.       DeleteChar(CurrentItem->Text,
  470.       PosInText(CurrentItem->Level)-1);
  471.       WriteConsole(Buffer,-1);
  472.       CurX--;
  473.    }
  474.    else  /*otherwise, delete the line*/
  475.       if(CurrentItem->PrevItem != NULL &&
  476.             strlen(CurrentItem->Text)==0 &&
  477.             !(CurrentItem->NextItem && !CurrentItem->cont &&
  478.             CurrentItem->NextItem->cont))   
  479.       {
  480.          DelBlock(CurrentItem,CurrentItem,CurY,CurY);
  481.          if(CurrentItem != LastItem)
  482.             CursorUp();
  483.          PlotCursor(MaxX(CurrentItem),CurY);
  484.       }
  485. }
  486.  
  487. HandleReturn(Qualifier) /*The return key was pressed, so add a line...*/
  488. USHORT Qualifier;
  489. {
  490.    BYTE TempX,TempY;
  491.    char Buffer[20];
  492.    struct LineItem *WorkingItem;
  493.    
  494.    CheckModified();
  495.    if(CancelInvs())
  496.       return(FALSE);
  497.                     
  498.    if(CurX == MinX(CurrentItem) && strlen(CurrentItem->Text) > 0)
  499.       if(!CursorUp())
  500.       {
  501.          InsertLineAtTop();
  502.          return(FALSE);
  503.       }
  504.  
  505.       /*If the next item is a continuation and SHIFT wasn't pressed*/
  506.    if((CurrentItem->NextItem != NULL) && !(Qualifier & 3) &&
  507.          (CurrentItem->NextItem->cont))
  508.       return(FALSE); /*Don't do anything*/
  509.  
  510.    WorkingItem=(struct LineItem *)  /*Create the line*/
  511.          InsertItem(CurrentItem->NextItem,CurrentItem);
  512.    if(WorkingItem==NULL)
  513.    {
  514.       Leave(0,"Memory too fragmented to add line!"); /*Ran out of memory*/
  515.       return(FALSE);
  516.    }
  517.  
  518.    if((DispRows==SCRNHEIGHT) && (CurY != SCRNHEIGHT))
  519.    {  /*If a full screen & cursor isn't at the bottom*/
  520.       TempX=CurX; /*Delete the last line*/
  521.       TempY=CurY;
  522.       PlotCursor(1,SCRNHEIGHT);
  523.       Buffer[0]=0x9b;
  524.       Buffer[1]=0x4a;
  525.       WriteConsole(Buffer,2);
  526.       PlotCursor(TempX,TempY);
  527.    }
  528.                   
  529.    strcpy(Buffer,&SpecChars[SCPos[4]]);   /*Make space for the line*/
  530.    WriteConsole(Buffer,4);             /*on the screen*/
  531.                 
  532.    if(prefs.DS)      /*If double spaced*/
  533.    {
  534.       WriteConsole(Buffer,4); /*Add an extra line*/
  535.       if((CurrentItem==ScrnBtm) && (Odd))
  536.          WriteConsole(Buffer,4);
  537.    }                
  538.  
  539.    WorkingItem->Level=CurrentItem->Level;
  540.                   
  541.    if(Qualifier & 3)  /*If a SHIFT-RETURN*/
  542.    {
  543.       WorkingItem->cont=TRUE; /*The line is a continuation of the previous*/
  544.       WorkingItem->ItemNumber=CurrentItem->ItemNumber;   /*line*/
  545.    }
  546.    else
  547.    {        /*Otherwise, it's an independent line*/
  548.       WorkingItem->cont=FALSE;
  549.       if(CurrentItem->ItemNumber==
  550.             MaxNumOnLevel[CurrentItem->Level]-1)
  551.          WorkingItem->ItemNumber=0;
  552.       else
  553.          WorkingItem->ItemNumber=CurrentItem->ItemNumber+1;
  554.    }
  555.                   
  556.    if(CurY==SCRNHEIGHT) /*If at the bottom of the screen*/
  557.    {
  558.       if(prefs.DS) /*If double spaced, open up more space*/
  559.          WriteConsole(Buffer,4);
  560.       ScrnBtm=(struct LineItem *)WorkingItem;
  561.       FirstScrnItem=(struct LineItem *)
  562.       FirstScrnItem->NextItem;
  563.    }
  564.    else
  565.    {
  566.       CurY++;
  567.       if(DispRows==SCRNHEIGHT)
  568.          ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
  569.       else
  570.          ++DispRows;
  571.    }
  572.    
  573.    if(WorkingItem->NextItem==NULL)  /*If it's at the end of the outline*/
  574.       ScrnBtm=LastItem=(struct LineItem *)   /*update appropriate pointers*/
  575.             WorkingItem;
  576.  
  577.    AddItem(WorkingItem);
  578.    TempY=CurY;
  579.    RedrawOutlineChars(WorkingItem,WorkingItem->Level,0);
  580.    CurrentItem=(struct LineItem *)WorkingItem; /*Make the new line current*/
  581.    PlotCursor(MinX(CurrentItem),TempY);   /*and put the cursor on it*/
  582. }
  583.  
  584. void Leave(err,why) /*If an error occured, tell user, close window & screen*/
  585. int err;          /*& exit*/
  586. char *why;
  587. {
  588.    char whyindeed[256];
  589.    SHORT x;
  590.    
  591.       /*Construct the string for DisplayAlert()*/
  592.    x=8*(80-strlen(why))/2;
  593.    whyindeed[1]=x;
  594.    whyindeed[0]=x>>8;
  595.    whyindeed[2]=14;
  596.    strcpy(&whyindeed[3],why);
  597.    whyindeed[strlen(&whyindeed[3])+4]=NULL;
  598.    DisplayAlert(RECOVERY_ALERT,whyindeed,24);   /*Display the alert*/
  599.    
  600.    if(err!=0)
  601.       exit(err);
  602. }
  603.  
  604. PushIn(Item)   /*Increase and redraw the level of an item*/
  605. struct LineItem *Item;
  606. {
  607.    struct LineItem *Start,*End,*work;
  608.    
  609.    for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
  610.          work=(struct LineItem *)work->PrevItem);
  611.    Start=(struct LineItem *)work;
  612.    
  613.    for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
  614.          (work->NextItem->cont);work=(struct LineItem *)work->NextItem);
  615.    End=(struct LineItem *)work;
  616.  
  617.    if(Start != End)
  618.       PushInBlock(Start,End,IsOnScreen(Start),FALSE);
  619.    else
  620.       if(Push(Item))
  621.          {
  622.          RedrawOutlineChars(Item,Item->Level-1,Item->Level);
  623.          return(TRUE);
  624.          }
  625.       else
  626.          return(FALSE);
  627. }
  628.  
  629. Push(Item)   /*Increase the level of an item (I. to A., etc.)*/
  630. struct LineItem *Item;
  631. {
  632.    if(Item->Level==6)
  633.       return(FALSE);
  634.  
  635.    RemItem(Item);
  636.    Item->Level++; /*Increase the level and chop off excess text if it*/
  637.    Item->Text[MaxLen(Item->Level)]=NULL; /*would go off the line*/
  638.    AddItem(Item);
  639.    
  640.    if(IsOnScreen(Item)) /*Print item if it is on screen*/
  641.       PrintItem(Item);
  642.    return(TRUE);
  643. }
  644.  
  645. PullOut(Item)  /*Decrease the level of an item and redraw*/
  646. struct LineItem *Item;
  647. {
  648.    struct LineItem *Start,*End,*work;
  649.    
  650.    for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
  651.          work=(struct LineItem *)work->PrevItem);
  652.    Start=(struct LineItem *)work;
  653.    
  654.    for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
  655.          (work->NextItem->cont);work=(struct LineItem *)work->NextItem);
  656.    End=(struct LineItem *)work;
  657.  
  658.    if(Start != End) /*If the line is a continuation or has continuing lines...*/
  659.       PullOutBlock(Start,End,IsOnScreen(Start),FALSE); /*Pull 'em all out*/
  660.    else
  661.       if(Pull(Item))
  662.          {
  663.          RedrawOutlineChars(Item,Item->Level+1,Item->Level);
  664.          return(TRUE);
  665.          }
  666.       else
  667.          return(FALSE);
  668. }
  669.  
  670. Pull(Item)  /*Decrease the level of an item (a. to 1., etc.)*/
  671. struct LineItem *Item;
  672. {
  673.    struct LineItem *wrk;
  674.    if(Item->Level==1)
  675.       return(FALSE);
  676.  
  677.    for(wrk=(struct LineItem *)Item->NextItem;(wrk != NULL) && (wrk->cont);
  678.          wrk=(struct LineItem *)wrk->NextItem);
  679.          
  680.    RemItem(Item);
  681.    Item->Level--;
  682.    AddItem(Item);
  683.    AddItem(wrk);
  684.    if(IsOnScreen(Item)) /*Print item if it is on screen*/
  685.       PrintItem(Item);
  686.  
  687.    return(TRUE);
  688. }
  689.  
  690. PushInBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
  691. struct LineItem *TrueStart,*TrueEnd;
  692. UBYTE YStart;
  693. BYTE Inverse;
  694. {
  695.    struct LineItem *Item,*Start,*End;
  696.    UBYTE OldX=CurX;
  697.    UBYTE OldY=CurY;
  698.    UBYTE Y=YStart;
  699.  
  700.    /*If Start or End is a continued item, find where the continued items end*/
  701.  
  702.    Start=(struct LineItem *)FindPrevNonCont(TrueStart);
  703.    End=(struct LineItem *)FindNextNonCont(TrueEnd);
  704.  
  705.    Item=(struct LineItem *)Start; /*Check to see if any items are as*/
  706.    while(Item != End)             /*pushed in as possible*/
  707.    {
  708.       if(Item->Level == 6)
  709.          return(FALSE);
  710.       Item=(struct LineItem *)Item->NextItem;
  711.    }
  712.    
  713.    if(Y=IsOnScreen(Start))
  714.       PlotCursor(1,Y);
  715.    Item=(struct LineItem *)Start; /*Do first one*/
  716.    Push(Item);
  717.  
  718.    while(Item != End)  /*Loop until all pushed in*/
  719.    {
  720.       Item=(struct LineItem *)Item->NextItem;
  721.       if(Y=IsOnScreen(Item))  /*If it's on the screen*/
  722.          PlotCursor(1,Y);
  723.       Push(Item);
  724.    }
  725.    RemItem(Start);
  726.    AddItem(Start);
  727.  
  728.    if(IsOnScreen(Item->NextItem))
  729.    {
  730.       PlotCursor(1,++Y);      /*Redraw outline characters*/
  731.       RedrawOutlineChars(End->NextItem,6,5);
  732.       PlotCursor(1,Y);
  733.       RedrawOutlineChars(End->NextItem,4,3);
  734.       PlotCursor(1,Y);
  735.       RedrawOutlineChars(End->NextItem,2,1);
  736.    }
  737.    else
  738.       if(IsBefore(Item,FirstScrnItem))
  739.       {
  740.          Y=1;
  741.          PlotCursor(1,Y);      /*Redraw outline characters*/
  742.          RedrawOutlineChars(FirstScrnItem,6,5);
  743.          PlotCursor(1,Y);
  744.          RedrawOutlineChars(FirstScrnItem,4,3);
  745.          PlotCursor(1,Y);
  746.          RedrawOutlineChars(FirstScrnItem,2,1);
  747.       }
  748.    
  749.  
  750.    PlotCursor(1,YStart);
  751.    if(Inverse)
  752.       RvsBlock(TrueStart,TrueEnd);
  753.    if(OldX < MinX(CurrentItem)) /*OldX might no longer be possible if*/
  754.       PlotCursor(MinX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
  755.    else
  756.       PlotCursor(OldX,OldY);
  757. }
  758.  
  759. PullOutBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
  760. struct LineItem *TrueStart,*TrueEnd;
  761. UBYTE YStart;
  762. BYTE Inverse;
  763. {
  764.    struct LineItem *Item,*Start,*End;
  765.    UBYTE OldX=CurX;
  766.    UBYTE OldY=CurY;
  767.    UBYTE Y;
  768.  
  769.    Start=(struct LineItem *)FindPrevNonCont(TrueStart);
  770.    End=(struct LineItem *)FindNextNonCont(TrueEnd);
  771.  
  772.    Item=(struct LineItem *)Start; /*Check to see if any items are as*/
  773.    while(Item != End)             /*pushed in as possible*/
  774.    {
  775.       if(Item->Level == 1)
  776.          return(FALSE);
  777.       Item=(struct LineItem *)Item->NextItem;
  778.    }
  779.  
  780.    if(Y=IsOnScreen(Start))
  781.       PlotCursor(1,Y);
  782.    Item=(struct LineItem *)Start; /*Do first one*/
  783.    Pull(Item);
  784.  
  785.    while(Item != End)  /*Loop until all pushed in*/
  786.    {
  787.       Item=(struct LineItem *)Item->NextItem;
  788.       if(Y=IsOnScreen(Item))
  789.          PlotCursor(1,Y);
  790.       Pull(Item);
  791.    }
  792.    
  793.    Item=(struct LineItem *)Item->NextItem;
  794.    RemItem(Start);
  795.    AddItem(Start);
  796.    if(Y=IsOnScreen(Item))
  797.    {
  798.       PlotCursor(1,Y);    /*Redraw outline characters*/
  799.       RedrawOutlineChars(Item,6,5);
  800.       PlotCursor(1,Y);
  801.       RedrawOutlineChars(Item,4,3);
  802.       PlotCursor(1,Y);
  803.       RedrawOutlineChars(Item,2,1);
  804.    }
  805.    else
  806.       if(IsBefore(Item,FirstScrnItem))
  807.       {
  808.          Y=1;
  809.          PlotCursor(1,Y);      /*Redraw outline characters*/
  810.          RedrawOutlineChars(FirstScrnItem,6,5);
  811.          PlotCursor(1,Y);
  812.          RedrawOutlineChars(FirstScrnItem,4,3);
  813.          PlotCursor(1,Y);
  814.          RedrawOutlineChars(FirstScrnItem,2,1);
  815.       }
  816.  
  817.    
  818.    PlotCursor(1,YStart);
  819.    if(Inverse)
  820.       RvsBlock(TrueStart,TrueEnd);
  821.  
  822.    if(OldX > MaxX(CurrentItem)) /*OldX might no longer be possible if*/
  823.       PlotCursor(MaxX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
  824.    else
  825.       PlotCursor(OldX,OldY);
  826. }
  827.  
  828. void PrintItemList(FrstItem,StartY) /*Prints a specified number of items*/
  829. struct LineItem *FrstItem;
  830. int StartY;
  831. {
  832.    struct LineItem *CrntItem;
  833.    int y;
  834.    char Buffer[3];
  835.  
  836.    CancelLineInvs(); /*Cancel any highlighted text on a line*/
  837.    
  838.    if(InvsMode < NOINV )   /*If a block is highlighted somewhere...*/
  839.       if( InvsMode == BLOCK_DOWN)
  840.       {        /*and if the line is in the block*/
  841.          if( (IsAfter(FrstItem,StartIItem)) && (IsBefore(FrstItem,EndIItem)) )
  842.             WriteConsole(Inv,-1);
  843.       }
  844.       else     /*make sure it's highlighted*/
  845.          if( (IsAfter(FrstItem,EndIItem)) && (IsBefore(FrstItem,StartIItem)) )
  846.             WriteConsole(Inv,-1);
  847.  
  848.    PlotCursor(1,StartY);   /*Start at the top...*/
  849.    CrntItem=(struct LineItem *)FrstItem;
  850.    Buffer[0]=0x9b;
  851.    Buffer[1]=0x4a;
  852.    WriteConsole(Buffer,2);
  853.  
  854.    for(y=StartY;y<=SCRNHEIGHT && CrntItem!=NULL;y++)
  855.       {
  856.       if(InvsMode < 0) /*If inversed at and the start of a block...*/
  857.          if((CrntItem == StartIItem) &&
  858.                ((InvsMode == BLOCK_DOWN) || (InvsMode == BLOCK_PENDING)) )
  859.             WriteConsole(Inv,-1);   /*Make sure the line is highlighted*/
  860.          else
  861.             if((CrntItem == EndIItem) && (InvsMode == BLOCK_UP))
  862.                WriteConsole(Inv,-1); /*if it's in the block*/
  863.  
  864.       PlotCursor(1,y);
  865.       PrintItem(CrntItem);
  866.       ScrnBtm=(struct LineItem *)CrntItem;
  867.       
  868.       if(InvsMode < 0) /*If inversed and at the end of a block*/
  869.          if((CrntItem == EndIItem) &&
  870.                ( (InvsMode == BLOCK_DOWN) || (InvsMode==BLOCK_PENDING) ))
  871.             WriteConsole(Norm,-1);  /*Turn off highlighting*/
  872.         else
  873.             if((CrntItem == StartIItem) && (InvsMode == BLOCK_UP)) 
  874.                WriteConsole(Norm,-1);
  875.  
  876.       CrntItem=(struct LineItem *)CrntItem->NextItem;
  877.       }
  878.    DispRows=y-1;
  879.    WriteConsole(Norm,-1);
  880. }
  881.  
  882. void GetOutlineChars(Item,ConsoleBuffer) /*Get the outline chars (IX.,B.,etc.)*/
  883. struct LineItem *Item;     /*for an item*/
  884. char *ConsoleBuffer;
  885. {
  886.    int Level,StrLen,InsLen,c;
  887.  
  888.    Level=RealLevel(Item)-1;
  889.    if(Item->cont)
  890.       InsLen=MinX(Item)-3;
  891.    else
  892.    {
  893.       StrLen=strlen(OutLineChars[Level][(Item->ItemNumber)]);
  894.       InsLen=PERPOS((Item->Level)-1)-StrLen;
  895.    }
  896.    for(c=0;c<InsLen;c++)
  897.       strcat(ConsoleBuffer," ");
  898.  
  899.    if(!(Item->cont))
  900.       strcat(ConsoleBuffer,OutLineChars[Level][(Item->ItemNumber)]);
  901. }
  902.  
  903. void RedrawOutlineChars(Item,Hi,Lo)   /*Redraw the outline characters */
  904. struct LineItem *Item;  /*(Lo <= Changed level <= Hi)*/
  905. int Hi,Lo;
  906. {
  907.    char Buffer[60];
  908.    int x=1;
  909.    int y,Level;
  910.  
  911.    Level=Item->Level;
  912.  
  913.    for(y=CurY;y<=SCRNHEIGHT & Item != NULL ;y++)
  914.       {
  915.       if(Lo == Item->Level || Hi == Item->Level)
  916.          {
  917.          PlotCursor(x,y);
  918.          strcpy(Buffer,"");
  919.          GetOutlineChars(Item,Buffer);
  920.          WriteConsole(Buffer,-1);
  921.          }
  922.       Item=(struct LineItem *)Item->NextItem;
  923.       }
  924. }
  925.  
  926. /*Insert an item into the item list*/
  927. extern struct LineItem *InsertItem(NextItem,PrevItem)
  928. struct LineItem *NextItem,*PrevItem;
  929. {
  930.    struct LineItem *Item;
  931.  
  932.    Forbid();   /*Make sure that nobody grabs memory inbetween the*/
  933.                /*AvailMem() and the AllocMem()*/
  934.    if(AvailMem(MEMF_LARGEST)<MINMEMORY) /*If we're out of memory*/
  935.    {
  936.       Permit();
  937.       return(NULL);
  938.    }
  939.    if((Item=(struct LineItem *)AllocMem(sizeof(struct LineItem),
  940.          MEMF_CLEAR))==NULL)
  941.    {
  942.       Permit();
  943.       return(NULL);
  944.    }
  945.    Permit();
  946.  
  947.    if(NextItem != NULL)
  948.       {
  949.       NextItem->PrevItem=(struct LineItem *)Item;
  950.       Item->NextItem=(struct LineItem *)NextItem;
  951.       }
  952.  
  953.    if(PrevItem != NULL)
  954.       {
  955.       PrevItem->NextItem=(struct LineItem *)Item;
  956.       Item->PrevItem=(struct LineItem *)PrevItem;
  957.       }
  958.  
  959.    return(Item);
  960. }
  961.  
  962. RemItem(Item)  /*Adjust the ItemNumbers for items after one is removed*/
  963. struct LineItem *Item;
  964. {
  965.    int ItemNumber;
  966.    struct LineItem *WorkingItem;
  967.  
  968.    if((Item->cont) || Item==NULL)  /*If a continued line, or if there*/
  969.       return(FALSE);  /*is no item, just return*/
  970.    if((WorkingItem=(struct LineItem *)FindPrev(Item))==NULL)
  971.       ItemNumber=0;
  972.    else
  973.       ItemNumber=Item->ItemNumber;
  974.  
  975.    while((Item=(struct LineItem *)FindNext(Item))!=NULL)
  976.       {
  977.       if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
  978.          ItemNumber=0;
  979.       Item->ItemNumber=ItemNumber++;
  980.       }
  981. }
  982.  
  983. void AddItem(Item)  /*Adjust the ItemNumbers after adding an item*/
  984. struct LineItem *Item;
  985. {
  986.    int ItemNumber;
  987.    struct LineItem *CrntItem;
  988.  
  989.    if(Item->cont) /*If a continued line*/
  990.       return;     /*just return*/
  991.    if((CrntItem=(struct LineItem *)FindPrev(Item))==NULL)
  992.       ItemNumber=0;
  993.    else
  994.       ItemNumber=CrntItem->ItemNumber+1;
  995.  
  996.    do /*Go through the outline, updating ItemNumbers*/
  997.       {
  998.       if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
  999.          ItemNumber=0;
  1000.       Item->ItemNumber=ItemNumber++;
  1001.       Item=(struct LineItem *)FindNext(Item);
  1002.       }
  1003.    while(Item != NULL && Item->PrevItem->Level >= Item->Level);
  1004. }
  1005.  
  1006. extern struct LineItem *FindPrev(Item) /*Find the previous item of*/
  1007. struct LineItem *Item;  /*the same Level as Item*/
  1008. {
  1009.    int Level;
  1010.  
  1011.    Level=Item->Level;
  1012.    Item=(struct LineItem *)Item->PrevItem;
  1013.  
  1014.    while( ((Item->cont) || (Item->Level > Level)) && (Item !=NULL) )
  1015.       Item=(struct LineItem *)Item->PrevItem;
  1016.  
  1017.    if(Item->Level < Level || Item == NULL)
  1018.       return(NULL);
  1019.    else
  1020.       return(Item);
  1021. }
  1022.  
  1023. extern struct LineItem *FindNext(Item) /*Find the next item of the same*/
  1024. struct LineItem *Item;     /*Level as Item*/
  1025. {
  1026.    int Level;
  1027.  
  1028.    Level=Item->Level;
  1029.    Item=(struct LineItem *)Item->NextItem;
  1030.  
  1031.    while( ( (Item->cont) || (Item->Level > Level) )  && (Item != NULL) )
  1032.       Item=(struct LineItem *)Item->NextItem;
  1033.  
  1034.    if((Item->Level < Level) || (Item->cont) )
  1035.       return(NULL);
  1036.    else
  1037.       return(Item);
  1038. }
  1039.  
  1040. void InsertLineAtTop() /*Insert a line at the top of the list*/
  1041. {
  1042.    struct LineItem *WorkingItem;
  1043.  
  1044.    WorkingItem=(struct LineItem *)
  1045.       InsertItem(FirstItem,NULL);
  1046.    if(WorkingItem==NULL)   /*Out of memory*/
  1047.    {
  1048.       Leave(0,"Memory too fragmented to add line!");
  1049.       return;
  1050.    }
  1051.    WorkingItem->Level=1;
  1052.  
  1053.    FirstItem=(struct LineItem *)WorkingItem;
  1054.    AddItem(FirstItem);
  1055.    PlotCursor(1,1);
  1056.    RedrawOutlineChars(WorkingItem->NextItem,1,1);
  1057.    PlotCursor(MinX(CurrentItem),1);
  1058.    CursorUp();
  1059. }
  1060.  
  1061. IsOnScreen(item)         /*Test to see whether a LineItem is currently*/
  1062. struct LineItem *item;   /*on the screen, and if so, return its Y position*/
  1063. {
  1064.    struct LineItem *wrk;
  1065.    int y;
  1066.    
  1067.       /*Search items on screen for a match*/
  1068.    for(y=1,wrk=(struct LineItem *)FirstScrnItem;(wrk!=item) && (wrk!=ScrnBtm);
  1069.          wrk=(struct LineItem *)wrk->NextItem,y++);   
  1070.  
  1071.    if(wrk == item)
  1072.       return(y);  /*It's on screen*/
  1073.    else
  1074.       return(FALSE);
  1075. }
  1076.  
  1077. IsBefore(item,start)   /*Checks to see if 'item' if before 'start' in*/
  1078. struct LineItem *start,*item;    /*the linked list*/
  1079. {
  1080.    for(;(start != item) && (start != NULL);
  1081.          start=(struct LineItem *)start->PrevItem);
  1082.    if(start==item)
  1083.       return(TRUE);
  1084.    else
  1085.       return(FALSE);
  1086. }
  1087.  
  1088. IsAfter(item,start) /*Checks to see if 'item' is after 'start' in the*/
  1089. struct LineItem *start,*item;       /*linked list*/
  1090. {
  1091.    for(;(start != item) && (start != NULL);
  1092.          start=(struct LineItem *)start->NextItem);
  1093.    if(start==item)
  1094.       return(TRUE);
  1095.    else
  1096.       return(FALSE);
  1097. }
  1098.       
  1099. extern struct LineItem *FindPrevNonCont(Start)/*Find the first line before*/
  1100. struct LineItem *Start;         /*or at 'Start' that isn't a continuation*/
  1101. {
  1102.    struct LineItem *Item;
  1103.    
  1104.    for(Item=(struct LineItem *)Start;(Item->PrevItem!=NULL)&&(Item->cont);
  1105.          Item=(struct LineItem *)Item->PrevItem);
  1106.    
  1107.    return(Item);
  1108. }
  1109.  
  1110. extern struct LineItem *FindNextNonCont(Start) /*Find the first non-*/
  1111. struct LineItem *Start;       /*continuation after 'Start'*/
  1112. {
  1113.    struct LineItem *Item;
  1114.    
  1115.    for(Item=(struct LineItem *)Start;(Item->NextItem != NULL) &&
  1116.             (Item->NextItem->cont);Item=(struct LineItem *)Item->NextItem);
  1117.    
  1118.    return(Item);
  1119. }
  1120.  
  1121. CursorUp()  /*Move the cursor up (scroll screen, etc.)*/
  1122. {
  1123.    char Buffer[20];
  1124.    int TempX;
  1125.  
  1126.    CancelLineInvs();
  1127.    if(ErrorInTitle)
  1128.       TitleErrorCancel();
  1129.    if(CurrentItem->PrevItem !=NULL)
  1130.       {
  1131.       if(CurrentItem==FirstScrnItem && CurrentItem != FirstItem)
  1132.          {
  1133.          TempX=CurX; /*Delete the last line*/
  1134.          PlotCursor(1,SCRNHEIGHT);
  1135.          Buffer[0]=0x9b;
  1136.          Buffer[1]=0x4a;
  1137.          WriteConsole(Buffer,2);
  1138.          PlotCursor(TempX,1);
  1139.          
  1140.          strcpy(Buffer,&SpecChars[SCPos[0x0c]]);
  1141.          WriteConsole(Buffer,2);
  1142.          
  1143.          if(prefs.DS)
  1144.             WriteConsole(Buffer,2); /*If double spaced, scroll twice*/
  1145.          
  1146.          TempX=CurX;
  1147.          PlotCursor(1,1);
  1148.          
  1149.          if(InvsMode < NOINV) /*Block Invs is active somewhere*/
  1150.             switch(InvsMode)
  1151.             {
  1152.                case BLOCK_PENDING:
  1153.                   if(CurrentItem->PrevItem == StartIItem)
  1154.                      WriteConsole(Inv,-1);   /*Inverse*/
  1155.                   break;
  1156.                case BLOCK_DOWN:
  1157.                   if(IsAfter(CurrentItem->PrevItem,StartIItem) && /*If it's in*/
  1158.                         IsBefore(CurrentItem->PrevItem,EndIItem)) /*the block*/
  1159.                      WriteConsole(Inv,-1);   /*Inverse*/
  1160.                   break;
  1161.                case BLOCK_UP:
  1162.                   if(IsAfter(CurrentItem->PrevItem,EndIItem) && /*Same as*/
  1163.                         IsBefore(CurrentItem->PrevItem,StartIItem)) /*above*/
  1164.                      WriteConsole(Inv,-1);
  1165.             }
  1166.                      
  1167.          PrintItem(CurrentItem->PrevItem);
  1168.          WriteConsole(Norm,-1);  /*Make it normal again*/
  1169.          ++CurY;
  1170.          if(ScrnBtm==LastItem && DispRows < SCRNHEIGHT)
  1171.             ++DispRows;
  1172.          else
  1173.             ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
  1174.          FirstScrnItem=(struct LineItem *)FirstScrnItem->PrevItem;
  1175.          CurX=TempX;
  1176.          InvY++;
  1177.          }
  1178.  
  1179.       if(CurX < MinX(CurrentItem->PrevItem)) /*If the cursor wouldn't be*/
  1180.          CurX=MinX(CurrentItem->PrevItem);   /*in a legal place on the line*/
  1181.       else        /*now, move it onto the line*/
  1182.          if(CurX > MaxX(CurrentItem->PrevItem))
  1183.             CurX=MaxX(CurrentItem->PrevItem);
  1184.  
  1185.       PlotCursor(CurX,CurY-1); /*Position the cursor*/
  1186.       CurrentItem=(struct LineItem *) CurrentItem->PrevItem;
  1187.       return(TRUE);
  1188.       }
  1189.    return(FALSE);
  1190. }
  1191.  
  1192. CursorDown()      /*Move the cursor down (scroll screen, etc.)*/
  1193. {
  1194.    char Buffer[20];
  1195.    int TempX;
  1196.  
  1197.    CancelLineInvs();
  1198.    if(ErrorInTitle)
  1199.       TitleErrorCancel();
  1200.    if(CurrentItem->NextItem != NULL)
  1201.       {
  1202.       if(CurrentItem==ScrnBtm)
  1203.          {
  1204.          strcpy(Buffer,&SpecChars[SCPos[0x0d]]); 
  1205.          WriteConsole(Buffer,2);
  1206.  
  1207.          if(prefs.DS) /*If double spaced, scroll twice*/
  1208.          {
  1209.             WriteConsole(Buffer,2);
  1210.             WriteConsole(Buffer,2);
  1211.             if(Odd)
  1212.                WriteConsole(Buffer,2);
  1213.          }
  1214.  
  1215.          TempX=CurX;
  1216.          PlotCursor(1,CurY);
  1217.  
  1218.          if(InvsMode < NOINV) /*Block Invs is active somewhere*/
  1219.             switch(InvsMode)
  1220.             {
  1221.                case BLOCK_PENDING:
  1222.                   if(CurrentItem->NextItem == StartIItem)
  1223.                      WriteConsole(Inv,-1);   /*Inverse*/
  1224.                   break;
  1225.                case BLOCK_DOWN:
  1226.                   if(IsAfter(CurrentItem->NextItem,StartIItem) && /*If it's in*/
  1227.                         IsBefore(CurrentItem->NextItem,EndIItem)) /*the block*/
  1228.                      WriteConsole(Inv,-1);   /*Inverse*/
  1229.                   break;
  1230.                case BLOCK_UP:
  1231.                   if(IsAfter(CurrentItem->NextItem,EndIItem) && /*Same as*/
  1232.                         IsBefore(CurrentItem->NextItem,StartIItem)) /*above*/
  1233.                      WriteConsole(Inv,-1);
  1234.             }
  1235.          
  1236.          PrintItem(CurrentItem->NextItem);
  1237.          WriteConsole(Norm,-1);
  1238.          PlotCursor(TempX,CurY-1);
  1239.          ScrnBtm=(struct LineItem *)CurrentItem->NextItem;
  1240.          FirstScrnItem=(struct LineItem *)FirstScrnItem->NextItem;
  1241.          InvY--;
  1242.          }  
  1243.       if(CurX < MinX(CurrentItem->NextItem)) /*If the cursor wouldn't be on*/
  1244.          CurX=MinX(CurrentItem->NextItem); /*the new line, move it*/
  1245.       else
  1246.          if(CurX > MaxX(CurrentItem->NextItem))
  1247.             CurX=MaxX(CurrentItem->NextItem);
  1248.       PlotCursor(CurX,CurY+1);
  1249.       CurrentItem=(struct LineItem *)CurrentItem->NextItem; /*Update the */
  1250.       return(TRUE);              /*Current line pointer*/
  1251.    }
  1252.    return(FALSE);
  1253. }
  1254.  
  1255. /*End of liner.c*/
  1256.