home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / snoopdos_451.lzh / 'Liner / Source / Liner.c < prev    next >
C/C++ Source or Header  |  1991-02-06  |  36KB  |  1,290 lines

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