home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
text
/
editors
/
'liner_451
/
source
/
liner.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-06
|
36KB
|
1,290 lines
/*
'Liner Version 2.10. Written by Dave Schreiber
©1988, 1989, 1990 by Dave Schreiber. All Rights Reserved.
2.11 completed Wednesday, December 26, 1990
2.10 completed Thursday, December 13, 1990
2.00 completed Saturday, June 23, 1990
1.32 completed Monday, October 30, 1989
1.31 completed Friday, October 6, 1989
1.30 completed Saturday, February 25, 1989
1.20 completed Friday, November 11, 1988
1.10 completed Friday, October 14, 1988
1.00 completed Friday, September 9, 1988
Length of source code: 7255 lines
Compiled with SAS/C V5.10
To compile: 1> lcliner
*********************************
'Liner is an outliner, with up to six levels of depth, and up to
52 items per level (each isolated section). It has both clipboard and
non-clipboard support of CUT, COPY, and, for single lines of text, PASTE.
It can output files in its own format, or in ASCII (to disk or printer).
It can read files in its own format only. It uses dynamic memory
allocation to allow an infinite number of items (memory providing).
It supports ARexx, Workbench icons, overscanned and interlaced screens
*********************************
Amiga features of note that are used:
console device, disk i/o, printer i/o, clipboard i/o
*********************************
Intuition objects (screen, windows, gadgets, menus, etc.) generated by
PowerWindows Version 2.0
*********************************
*********************************
V1.1 corrects some bugs, doubles the number of characters available
for filenames, and improves PrintItemList() so that it doesn't always
print the entire item list
------------
1.2 allows the toggling between 640x200 & 640x400 screens and the
choice of the order that levels appear in, has a completely reworked
About... window, lets the user change the level of all the items
in a highlighted block, and now displays the current filename
in the title bar.
------------
1.3 adds support for user-selected keymaps, and now prints an asterisk
in the title bar if an outline has been edited but not saved. It also
includes my very own file requester, YAFR (Yet Another File Requester)
based in principal upon Charlie Heath's, but with a lot more buttons.
------------
1.31 changes the default device where files are located from DF0: to
the current directory
------------
1.32 fixed a bug that kept the screen from updating properly after a
paste. Also uses YAFR V1.1
------------
2.00 added a number of things:
-Two way ARexx support
-Search/replace
-Greater Clipboard support (a block of lines that are CUT or COPYed are
now sent to the Clipboard
-Truer WYSIWYG: double spacing is now shown on screen
-Support for more than one line per number
-Icon support: icons now can be created when a document is saved. When
the icon is double clicked on, 'Liner will be run and the document
loaded
-Support for overscanned screens, allowing more rows of text on screen
at once
-Adjustable screen colors
-An option to save various settings in a preferences file
-A new, more compact file format that supports the new 'Liner's
improvements
-The limit of highlighting only one screenful of lines at a time has
been removed. There is now no limit
-Support for up to 52 lines per level, up from 26 in 1.32
-Uses YAFR V1.20. See the file YAFR.c for more details.
In addition, a bug that would cause 'Liner to crash if the user
attempted to load a file that wasn't a 'Liner outline has been removed
------------
2.10 added enhancements related to AmigaOS2.0:
-2.0 "look and feel" (3D gadgets, gadtools menus)
-Support for new screen modes (productivity, A2024, PAL)
-Replaced YAFR with the asl.library file requestor
-Fixed some bugs regarding font handling and overscanned screen sizes
-Added support for "odd" characters (eg: ©°æè, etc.)
-Fixed some bugs in the ARexx port
------------
2.11 got rid of on-screen double spacing (I couldn't get the spacing
to work right on all sized screens; that plus the growing realization
that (IMHO) it was a waste of screen space led to it's demise).
*********************************
*/
#include "globals.h"
/*Outline characters*/
char *OutLineChars[6][99]=
{
{
{"I."},{"II."},{"III."},{"IV."},{"V."},{"VI."},{"VII."},{"VIII."},
{"IX."},{"X."},{"XI."},{"XII."},{"XIII."},{"XIV."},{"XV."},{"XVI."},
{"XVII."},{"XVIII."},{"XIX."},{"XX."},{"XXI."},{"XXII."},{"XXIII."},
{"XXIV."},{"XXV."},{"XXVI."},{"XXVII."},{"XXVIII."},{"XXIX."},{"XXX."},
{"XXXI."},{"XXXII."},{"XXXIII."},{"XXXIV."},{"XXXV."},{"XXXVI."},
{"XXXVII."},{"XXXVIII."},{"IXL."},{"XL."},{"XLI."},{"XLII."},{"XLIII."},
{"XLIV."},{"XLV."},{"XLVI."},{"XLVII."},{"XLVIII."},{"IL."},{"L."},
{"LI."},{"LII."}
},
{
{"A."},{"B."},{"C."},{"D."},{"E."},{"F."},{"G."},{"H."},{"I."},
{"J."},{"K."},{"L."},{"M."},{"N."},{"O."},{"P."},{"Q."},{"R."},
{"S."},{"T."},{"U."},{"V."},{"W."},{"X."},{"Y."},{"Z."},{"AA."},
{"AB."},{"AC."},{"AD."},{"AE."},{"AF."},{"AG."},{"AH."},{"AI."},
{"AJ."},{"AK."},{"AL."},{"AM."},{"AN."},{"AO."},{"AP."},{"AQ."},
{"AR."},{"AS."},{"AT."},{"AU."},{"AV."},{"AW."},{"AX."},{"AY."},
{"AZ."}
},
{
{"1."},{"2."},{"3."},{"4."},{"5."},{"6."},{"7."},{"8."},{"9."},
{"10."},{"11."},{"12."},{"13."},{"14."},{"15."},{"16."},{"17."},
{"18."},{"19."},{"20."},{"21."},{"22."},{"23."},{"24."},{"25."},
{"26."},{"27."},{"28."},{"29."},{"30."},{"31."},{"32."},{"33."},
{"34."},{"35."},{"36."},{"37."},{"38."},{"39."},{"40."},{"41."},
{"42."},{"43."},{"44."},{"45."},{"46."},{"47."},{"48."},{"49."},
{"50."},{"51."},{"52."}
},
{
{"a."},{"b."},{"c."},{"d."},{"e."},{"f."},{"g."},{"h."},{"i."},
{"j."},{"k."},{"l."},{"m."},{"n."},{"o."},{"p."},{"q."},{"r."},
{"s."},{"t."},{"u."},{"v."},{"w."},{"x."},{"y."},{"z."},{"aa."},
{"ab."},{"ac."},{"ad."},{"ae."},{"af."},{"ag."},{"ah."},{"ai."},
{"aj."},{"ak."},{"al."},{"am."},{"an."},{"ao."},{"ap."},{"aq."},
{"ar."},{"as."},{"at."},{"au."},{"av."},{"aw."},{"ax."},{"ay."},
{"az."}
},
{
{"1)"},{"2)"},{"3)"},{"4)"},{"5)"},{"6)"},{"7)"},{"8)"},{"9)"},
{"10)"},{"11)"},{"12)"},{"13)"},{"14)"},{"15)"},{"16)"},{"17)"},
{"18)"},{"19)"},{"20)"},{"21)"},{"22)"},{"23)"},{"24)"},{"25)"},
{"26)"},{"27)"},{"28)"},{"29)"},{"30)"},{"31)"},{"32)"},{"33)"},
{"34)"},{"35)"},{"36)"},{"37)"},{"38)"},{"39)"},{"40)"},{"41)"},
{"42)"},{"43)"},{"44)"},{"45)"},{"46)"},{"47)"},{"48)"},{"49)"},
{"50)"},{"51)"},{"52)"}
},
{
{"a)"},{"b)"},{"c)"},{"d)"},{"e)"},{"f)"},{"g)"},{"h)"},{"i)"},
{"j)"},{"k)"},{"l)"},{"m)"},{"n)"},{"o)"},{"p)"},{"q)"},{"r)"},
{"s)"},{"t)"},{"u)"},{"v)"},{"w)"},{"x)"},{"y)"},{"z)"},{"aa)"},
{"ab)"},{"ac)"},{"ad)"},{"ae)"},{"af)"},{"ag)"},{"ah)"},{"ai)"},
{"aj)"},{"ak)"},{"al)"},{"am)"},{"an)"},{"ao)"},{"ap)"},{"aq)"},
{"ar)"},{"as)"},{"at)"},{"au)"},{"av)"},{"aw)"},{"ax)"},{"ay)"},
{"az)"}
},
};
/*The position of each special character in the array below*/
extern int SCPos[]=
{0,1,4,5,9,13,14,16,17,18,19,20,21,23,25,27,29};
/*Special characters (TAB, RETURN, etc.)*/
extern char SpecChars[]=
{
32,
8,CSI,'P',
0,
0x0D,0x0A,CSI,'L',
0x0D,0x0A,CSI,'L',
0,
CSI,'P',
0,
0,
0,
0,
0,
CSI,'A',
CSI,'S',
CSI,'C',
CSI,'D',
NULL
};
char Inv[]=
{CSI,'7',0x6d,NULL};
char Norm[]=
{CSI,'0',0x6d,NULL};
main() /*The main function*/
{
ULONG Class;
USHORT Code,Qualifier;
APTR IAddress;
SHORT MouseX,MouseY;
int Seconds,Micros;
struct IntuiMessage *Message;
char Buffer[200];
Buffer[0]=NULL; /*Initialize various variables...*/
FileName[0]=SFileName[0]=NULL;
strcpy(PDirName,"");
PDName[0]=PFileName[0]=NULL;
Modified=FALSE; /*No modifications, yet*/
StartingLevel=0;
/*Open all the libraries*/
IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",1);
if(IntuitionBase==NULL) /*Intuition*/
exit(10);
GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",1);
if(GfxBase==NULL) /*Graphics*/
exit(20);
DosBase=OpenLibrary("dos.library",1);
if(DosBase==NULL) /*Dos*/
Leave(30,"Can't open dos.library!");
IconBase=OpenLibrary("icon.library",1);
if(IconBase==NULL) /*Icon*/
Leave(40,"Can't open icon.library!");
AslBase=(struct AslBase *)OpenLibrary(AslName,AslVersion);
if(AslBase==NULL)
Leave(45,"Can't open asl.library! Make sure you're running AmigaOS 2.0");
GadToolsBase=(struct GadToolsBase *)OpenLibrary("gadtools.library",0L);
if(GadToolsBase == NULL)
Leave(47,"Can't open gadtools.library! Make sure you're running AmigaOS 2.0");
OpenARexx(); /*Open the ARexx port*/
ThisProc=(struct Process *)FindTask(NULL);/*Get 'Liner's process structure*/
GetLinerPrefs("liner:liner.prefs"); /*Load the preferences*/
MakeMenus();
InterpretPrefs(); /*Install the preferences*/
SetupClipboard(); /*Open the clipboard*/
/*Setup various system variable*/
DispRows=1;
PtrX=PtrY=LastX=LastY=1;
ButtonState=UP;
InvsMode=ClipMode=NOINV;
FirstItem=LastItem=FirstScrnItem=CurrentItem=(struct LineItem *)
InsertItem(NULL,NULL);
if(FirstItem==NULL)
{
CloseGraphics();
CloseLibrary(GadToolsBase);
CloseLibrary(AslBase);
CloseLibrary(IconBase);
CloseLibrary(GfxBase);
Leave(50,"Memory too fragmented to run 'Liner! Exiting.");
}
FirstItem->Level=1;
FirstItem->ItemNumber=0;
PrintItemList(FirstItem,1);
PlotCursor(MinX(CurrentItem),1);
if(WBenchMsg != 0) /*If called from the Workbench...*/
if(WBenchMsg->sm_NumArgs > 1) /*Outline clicked on instead of 'Liner*/
{
CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
/*Make outline's directory the current directory*/
if(strcmp(WBenchMsg->sm_ArgList[1].wa_Name,"liner.prefs") != 0)
{ /*Make sure user didn't click on liner.prefs icon*/
strcpy(FileName,WBenchMsg->sm_ArgList[1].wa_Name);
strcpy(SFileName,FileName);
/*Store the outline's filename*/
ReadItemList(WBenchMsg->sm_ArgList[1].wa_Name,FALSE);
/*Load the outline*/
TitleErrorCancel();
}
}
for(;;) /*The main loop!*/
{
/*Wait for something to happen*/
Wait((1<<Window->UserPort->mp_SigBit) | ARexxSigBit);
CheckRexxPort(); /*Check the ARexx port for any messages*/
while((Message=(struct IntuiMessage *) /*Get the message if IDCMP*/
GetMsg(Window->UserPort))!=NULL)
{ /*Get the message's information*/
Class=Message->Class;
Code=Message->Code;
Qualifier=Message->Qualifier;
MouseX=Message->MouseX;
MouseY=Message->MouseY;
Seconds=Message->Seconds;
Micros=Message->Micros;
IAddress=(APTR)Message->IAddress;
ReplyMsg(Message); /*Reply to the message*/
/*Decode the message*/
if(HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,
Buffer,Seconds,Micros))
{ /*If the message was a keypress*/
InsertChar(CurrentItem->Text,Buffer[2], /*Print the letter*/
PosInText(CurrentItem->Level)); /*onto the screen*/
CurX++;
WriteConsole(Buffer,-1);
}
}
}
}
/*Decode an IDCMP message*/
HandleIDCMP(Class,Code,Qualifier,MouseX,MouseY,IAddress,Buffer,Secs,Micros)
ULONG Class;
USHORT Code,Qualifier;
APTR IAddress;
SHORT MouseX,MouseY;
int Secs,Micros;
char *Buffer;
{
struct MenuItem *item;
Buffer[0]=CSI;
Buffer[1]=0x40;
Buffer[2]=NULL;
switch(Class)
{
case MENUPICK: /*There was a menu selection*/
if(ErrorInTitle)
TitleErrorCancel();
while(Code != MENUNULL)
{
item=(struct MenuItem *)GetFirstItemAddress(Code);
if(HandleEvent(item))
break; /*User changed the screen size*/
Code=item->NextSelect;
}
case MOUSEBUTTONS: /*The left mouse button was pushed*/
if(Code==SELECTDOWN)
HandleButton(Secs,Micros);
break;
case MOUSEMOVE: /*The mouse was moved*/
MovedMouse(MouseX,MouseY);
break;
/*A key was pressed*/
case VANILLAKEY:
if(ErrorInTitle)
TitleErrorCancel();
switch(Code)
{
case 0x09: /*TAB (in or out)*/
HandleTAB(0);
return(FALSE);
case 0x0d: /*Return and Enter: insert a line*/
HandleReturn(Qualifier);
return(FALSE);
case 0x08: /*Backspace over a character*/
if(DelInvs())
{
CheckModified();
return(FALSE);
}
HandleBS();
return(FALSE);
case 0x7f: /*Delete a character*/
CheckModified();
if(DelInvs())
return(FALSE);;
if(CurX<MaxX(CurrentItem)) /*If there's room...*/
{
strcpy(Buffer,&SpecChars[SCPos[6]]);
Buffer[SCPos[7]-SCPos[6]]=NULL;
DeleteChar(CurrentItem->Text,
PosInText(CurrentItem->Level));
WriteConsole(Buffer,-1);
}
return(FALSE);
case 0x1b:
return(FALSE);
}
CheckModified();
if(InvsMode < NOINV) /*If a block of lines was highlighted*/
{ /*when a key was pressed, cancel the*/
EndBlockInvs(); /*highlight*/
return(FALSE);
}
/*If a key was pressed when TEXT was*/
if(InvsMode) /*highlighted, delete the text & replace*/
DelTextBlock(); /*it with the letter pressed*/
Buffer[2]=Code;
Buffer[3]=NULL;
/*If the current line isn't full*/
if(strlen(CurrentItem->Text)<MaxLen(CurrentItem->Level))
return(TRUE); /*OK to print the character*/
else
return(FALSE); /*Otherwise not*/
case RAWKEY:
if(ErrorInTitle)
TitleErrorCancel();
switch(Code) /*Handle all the "special" characters*/
{
case 0x4d: /*Move cursor down one*/
CancelLineInvs();
if(Qualifier & 3) /*Handle SHIFT-DOWN*/
WholeScreenDown();
else if(Qualifier & 8) /*Handle CTRL-DOWN*/
JumpToBottom();
else
CursorDown();
break;
case 0x4c: /*Move cursor up one*/
CancelLineInvs();
if(Qualifier & 3) /*Check for shift*/
WholeScreenUp();
else if(Qualifier & 8) /*Check for control*/
JumpToTop();
else
CursorUp();
break;
case 0x4e: /*Move cursor one to the right*/
CursorRight(Qualifier);
break;
case 0x4f: /*Move cursor one to the left*/
CursorLeft(Qualifier);
break;
case 0x42: /*TAB (in or out)*/
HandleTAB(Qualifier);
break;
case 0x43: /*Return & Enter */
case 0x44: /*Insert a line*/
HandleReturn(Qualifier);
break;
}
return(FALSE);
}
return(FALSE);
}
/*Close everything*/
void CloseStuff()
{
FreeListMem(FirstItem,LastItem); /*Free the outline's memory*/
if(ClipMode < NOINV)
FreeListMem(ClipStart,ClipEnd); /*Delete any clipped lines*/
CloseARexx(); /*Close the ARexx port*/
ShutDownClipboard();
CloseGraphics(); /*Close the screen, etc...*/
CloseLibrary(IconBase); /*Close the libraries*/
CloseLibrary(GadToolsBase);
CloseLibrary(AslBase);
CloseLibrary(DosBase);
CloseLibrary(GfxBase);
CloseLibrary(IntuitionBase);
exit(0);
}
void HandleBS() /*Handle the pressing of the backspace key*/
{
char Buffer[20];
CheckModified();
if(DelInvs()) /*If something is highlighted*/
return; /*delete it*/
/*Delete the character, if not at the beginning of the line...*/
if(CurX>MinX(CurrentItem))
{
strcpy(Buffer,&SpecChars[SCPos[1]]);
Buffer[SCPos[2]-SCPos[1]]=NULL;
DeleteChar(CurrentItem->Text,
PosInText(CurrentItem->Level)-1);
WriteConsole(Buffer,-1);
CurX--;
}
else /*otherwise, delete the line*/
if(CurrentItem->PrevItem != NULL &&
strlen(CurrentItem->Text)==0 &&
!(CurrentItem->NextItem && !CurrentItem->cont &&
CurrentItem->NextItem->cont))
{
DelBlock(CurrentItem,CurrentItem,CurY,CurY);
if(CurrentItem != LastItem)
CursorUp();
PlotCursor(MaxX(CurrentItem),CurY);
}
}
HandleReturn(Qualifier) /*The return key was pressed, so add a line...*/
USHORT Qualifier;
{
BYTE TempX,TempY;
char Buffer[20];
struct LineItem *WorkingItem;
CheckModified();
if(CancelInvs())
return(FALSE);
if(CurX == MinX(CurrentItem) && strlen(CurrentItem->Text) > 0)
if(!CursorUp())
{
InsertLineAtTop();
return(FALSE);
}
/*If the next item is a continuation and SHIFT wasn't pressed*/
if((CurrentItem->NextItem != NULL) && !(Qualifier & 3) &&
(CurrentItem->NextItem->cont))
return(FALSE); /*Don't do anything*/
WorkingItem=(struct LineItem *) /*Create the line*/
InsertItem(CurrentItem->NextItem,CurrentItem);
if(WorkingItem==NULL)
{
Leave(0,"Memory too fragmented to add line!"); /*Ran out of memory*/
return(FALSE);
}
if((DispRows==SCRNHEIGHT) && (CurY != SCRNHEIGHT))
{ /*If a full screen & cursor isn't at the bottom*/
TempX=CurX; /*Delete the last line*/
TempY=CurY;
PlotCursor(1,SCRNHEIGHT);
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
PlotCursor(TempX,TempY);
}
strcpy(Buffer,&SpecChars[SCPos[4]]); /*Make space for the line*/
WriteConsole(Buffer,4); /*on the screen*/
WorkingItem->Level=CurrentItem->Level;
if(Qualifier & 3) /*If a SHIFT-RETURN*/
{
WorkingItem->cont=TRUE; /*The line is a continuation of the previous*/
WorkingItem->ItemNumber=CurrentItem->ItemNumber; /*line*/
}
else
{ /*Otherwise, it's an independent line*/
WorkingItem->cont=FALSE;
if(CurrentItem->ItemNumber==
MaxNumOnLevel[CurrentItem->Level]-1)
WorkingItem->ItemNumber=0;
else
WorkingItem->ItemNumber=CurrentItem->ItemNumber+1;
}
if(CurY==SCRNHEIGHT) /*If at the bottom of the screen*/
{
strcpy(Buffer,&SpecChars[SCPos[0x0d]]);
WriteConsole(Buffer,2);
ScrnBtm=(struct LineItem *)WorkingItem;
FirstScrnItem=(struct LineItem *)
FirstScrnItem->NextItem;
}
else
{
CurY++;
if(DispRows==SCRNHEIGHT)
ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
else
++DispRows;
}
if(WorkingItem->NextItem==NULL) /*If it's at the end of the outline*/
ScrnBtm=LastItem=(struct LineItem *) /*update appropriate pointers*/
WorkingItem;
AddItem(WorkingItem);
TempY=CurY;
RedrawOutlineChars(WorkingItem,WorkingItem->Level,0);
CurrentItem=(struct LineItem *)WorkingItem; /*Make the new line current*/
PlotCursor(MinX(CurrentItem),TempY); /*and put the cursor on it*/
}
void Leave(err,why) /*If an error occured, tell user, close window & screen*/
int err; /*& exit*/
char *why;
{
char whyindeed[256];
SHORT x;
/*Construct the string for DisplayAlert()*/
x=8*(80-strlen(why))/2;
whyindeed[1]=x;
whyindeed[0]=x>>8;
whyindeed[2]=14;
strcpy(&whyindeed[3],why);
whyindeed[strlen(&whyindeed[3])+4]=NULL;
DisplayAlert(RECOVERY_ALERT,whyindeed,24); /*Display the alert*/
if(err >= 70 && err <=100)
{
ClearMenuStrip(Window);
CloseWindow(Window);
CloseScreen(Screen);
FreeVisualInfo(VisInfo);
}
if(err!=0)
exit(err);
}
PushIn(Item) /*Increase and redraw the level of an item*/
struct LineItem *Item;
{
struct LineItem *Start,*End,*work;
for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
work=(struct LineItem *)work->PrevItem);
Start=(struct LineItem *)work;
for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
(work->NextItem->cont);work=(struct LineItem *)work->NextItem);
End=(struct LineItem *)work;
if(Start != End)
PushInBlock(Start,End,IsOnScreen(Start),FALSE);
else
if(Push(Item))
{
RedrawOutlineChars(Item,Item->Level-1,Item->Level);
return(TRUE);
}
else
return(FALSE);
}
Push(Item) /*Increase the level of an item (I. to A., etc.)*/
struct LineItem *Item;
{
if(Item->Level==6)
return(FALSE);
RemItem(Item);
Item->Level++; /*Increase the level and chop off excess text if it*/
Item->Text[MaxLen(Item->Level)]=NULL; /*would go off the line*/
AddItem(Item);
if(IsOnScreen(Item)) /*Print item if it is on screen*/
PrintItem(Item);
return(TRUE);
}
PullOut(Item) /*Decrease the level of an item and redraw*/
struct LineItem *Item;
{
struct LineItem *Start,*End,*work;
for(work=(struct LineItem *)Item;(work->PrevItem!=NULL) && (work->cont);
work=(struct LineItem *)work->PrevItem);
Start=(struct LineItem *)work;
for(work=(struct LineItem *)Item;(work->NextItem != NULL) &&
(work->NextItem->cont);work=(struct LineItem *)work->NextItem);
End=(struct LineItem *)work;
if(Start != End) /*If the line is a continuation or has continuing lines...*/
PullOutBlock(Start,End,IsOnScreen(Start),FALSE); /*Pull 'em all out*/
else
if(Pull(Item))
{
RedrawOutlineChars(Item,Item->Level+1,Item->Level);
return(TRUE);
}
else
return(FALSE);
}
Pull(Item) /*Decrease the level of an item (a. to 1., etc.)*/
struct LineItem *Item;
{
struct LineItem *wrk;
if(Item->Level==1)
return(FALSE);
for(wrk=(struct LineItem *)Item->NextItem;(wrk != NULL) && (wrk->cont);
wrk=(struct LineItem *)wrk->NextItem);
RemItem(Item);
Item->Level--;
AddItem(Item);
AddItem(wrk);
if(IsOnScreen(Item)) /*Print item if it is on screen*/
PrintItem(Item);
return(TRUE);
}
PushInBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
struct LineItem *TrueStart,*TrueEnd;
UBYTE YStart;
BYTE Inverse;
{
struct LineItem *Item,*Start,*End;
UBYTE OldX=CurX;
UBYTE OldY=CurY;
UBYTE Y=YStart;
/*If Start or End is a continued item, find where the continued items end*/
Start=(struct LineItem *)FindPrevNonCont(TrueStart);
End=(struct LineItem *)FindNextNonCont(TrueEnd);
Item=(struct LineItem *)Start; /*Check to see if any items are as*/
while(Item != End) /*pushed in as possible*/
{
if(Item->Level == 6)
return(FALSE);
Item=(struct LineItem *)Item->NextItem;
}
if(Y=IsOnScreen(Start))
PlotCursor(1,Y);
Item=(struct LineItem *)Start; /*Do first one*/
Push(Item);
while(Item != End) /*Loop until all pushed in*/
{
Item=(struct LineItem *)Item->NextItem;
if(Y=IsOnScreen(Item)) /*If it's on the screen*/
PlotCursor(1,Y);
Push(Item);
}
RemItem(Start);
AddItem(Start);
if(IsOnScreen(Item->NextItem))
{
PlotCursor(1,++Y); /*Redraw outline characters*/
RedrawOutlineChars(End->NextItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(End->NextItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(End->NextItem,2,1);
}
else
if(IsBefore(Item,FirstScrnItem))
{
Y=1;
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(FirstScrnItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,2,1);
}
PlotCursor(1,YStart);
if(Inverse)
RvsBlock(TrueStart,TrueEnd);
if(OldX < MinX(CurrentItem)) /*OldX might no longer be possible if*/
PlotCursor(MinX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
else
PlotCursor(OldX,OldY);
}
PullOutBlock(TrueStart,TrueEnd,YStart,Inverse) /*Indent a reversed block*/
struct LineItem *TrueStart,*TrueEnd;
UBYTE YStart;
BYTE Inverse;
{
struct LineItem *Item,*Start,*End;
UBYTE OldX=CurX;
UBYTE OldY=CurY;
UBYTE Y;
Start=(struct LineItem *)FindPrevNonCont(TrueStart);
End=(struct LineItem *)FindNextNonCont(TrueEnd);
Item=(struct LineItem *)Start; /*Check to see if any items are as*/
while(Item != End) /*pushed in as possible*/
{
if(Item->Level == 1)
return(FALSE);
Item=(struct LineItem *)Item->NextItem;
}
if(Y=IsOnScreen(Start))
PlotCursor(1,Y);
Item=(struct LineItem *)Start; /*Do first one*/
Pull(Item);
while(Item != End) /*Loop until all pushed in*/
{
Item=(struct LineItem *)Item->NextItem;
if(Y=IsOnScreen(Item))
PlotCursor(1,Y);
Pull(Item);
}
Item=(struct LineItem *)Item->NextItem;
RemItem(Start);
AddItem(Start);
if(Y=IsOnScreen(Item))
{
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(Item,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(Item,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(Item,2,1);
}
else
if(IsBefore(Item,FirstScrnItem))
{
Y=1;
PlotCursor(1,Y); /*Redraw outline characters*/
RedrawOutlineChars(FirstScrnItem,6,5);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,4,3);
PlotCursor(1,Y);
RedrawOutlineChars(FirstScrnItem,2,1);
}
PlotCursor(1,YStart);
if(Inverse)
RvsBlock(TrueStart,TrueEnd);
if(OldX > MaxX(CurrentItem)) /*OldX might no longer be possible if*/
PlotCursor(MaxX(CurrentItem),OldY); /*CurrentItem was one pushed in*/
else
PlotCursor(OldX,OldY);
}
void PrintItemList(FrstItem,StartY) /*Prints a specified number of items*/
struct LineItem *FrstItem;
int StartY;
{
struct LineItem *CrntItem;
int y;
char Buffer[3];
CancelLineInvs(); /*Cancel any highlighted text on a line*/
if(InvsMode < NOINV ) /*If a block is highlighted somewhere...*/
if( InvsMode == BLOCK_DOWN)
{ /*and if the line is in the block*/
if( (IsAfter(FrstItem,StartIItem)) && (IsBefore(FrstItem,EndIItem)) )
WriteConsole(Inv,-1);
}
else /*make sure it's highlighted*/
if( (IsAfter(FrstItem,EndIItem)) && (IsBefore(FrstItem,StartIItem)) )
WriteConsole(Inv,-1);
PlotCursor(1,StartY); /*Start at the top...*/
CrntItem=(struct LineItem *)FrstItem;
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
for(y=StartY;y<=SCRNHEIGHT && CrntItem!=NULL;y++)
{
if(InvsMode < 0) /*If inversed at and the start of a block...*/
if((CrntItem == StartIItem) &&
((InvsMode == BLOCK_DOWN) || (InvsMode == BLOCK_PENDING)) )
WriteConsole(Inv,-1); /*Make sure the line is highlighted*/
else
if((CrntItem == EndIItem) && (InvsMode == BLOCK_UP))
WriteConsole(Inv,-1); /*if it's in the block*/
PlotCursor(1,y);
PrintItem(CrntItem);
ScrnBtm=(struct LineItem *)CrntItem;
if(InvsMode < 0) /*If inversed and at the end of a block*/
if((CrntItem == EndIItem) &&
( (InvsMode == BLOCK_DOWN) || (InvsMode==BLOCK_PENDING) ))
WriteConsole(Norm,-1); /*Turn off highlighting*/
else
if((CrntItem == StartIItem) && (InvsMode == BLOCK_UP))
WriteConsole(Norm,-1);
CrntItem=(struct LineItem *)CrntItem->NextItem;
}
DispRows=y-1;
WriteConsole(Norm,-1);
}
void GetOutlineChars(Item,ConsoleBuffer) /*Get the outline chars (IX.,B.,etc.)*/
struct LineItem *Item; /*for an item*/
char *ConsoleBuffer;
{
int Level,StrLen,InsLen,c;
Level=RealLevel(Item)-1;
if(Item->cont)
InsLen=MinX(Item)-3;
else
{
StrLen=strlen(OutLineChars[Level][(Item->ItemNumber)]);
InsLen=PERPOS((Item->Level)-1)-StrLen;
}
for(c=0;c<InsLen;c++)
strcat(ConsoleBuffer," ");
if(!(Item->cont))
strcat(ConsoleBuffer,OutLineChars[Level][(Item->ItemNumber)]);
}
void RedrawOutlineChars(Item,Hi,Lo) /*Redraw the outline characters */
struct LineItem *Item; /*(Lo <= Changed level <= Hi)*/
int Hi,Lo;
{
char Buffer[60];
int x=1;
int y,Level;
Level=Item->Level;
for(y=CurY;y<=SCRNHEIGHT & Item != NULL ;y++)
{
if(Lo == Item->Level || Hi == Item->Level)
{
PlotCursor(x,y);
strcpy(Buffer,"");
GetOutlineChars(Item,Buffer);
WriteConsole(Buffer,-1);
}
Item=(struct LineItem *)Item->NextItem;
}
}
/*Insert an item into the item list*/
extern struct LineItem *InsertItem(NextItem,PrevItem)
struct LineItem *NextItem,*PrevItem;
{
struct LineItem *Item;
Forbid(); /*Make sure that nobody grabs memory inbetween the*/
/*AvailMem() and the AllocMem()*/
if(AvailMem(MEMF_LARGEST)<MINMEMORY) /*If we're out of memory*/
{
Permit();
return(NULL);
}
if((Item=(struct LineItem *)AllocMem(sizeof(struct LineItem),
MEMF_CLEAR))==NULL)
{
Permit();
return(NULL);
}
Permit();
if(NextItem != NULL)
{
NextItem->PrevItem=(struct LineItem *)Item;
Item->NextItem=(struct LineItem *)NextItem;
}
if(PrevItem != NULL)
{
PrevItem->NextItem=(struct LineItem *)Item;
Item->PrevItem=(struct LineItem *)PrevItem;
}
return(Item);
}
RemItem(Item) /*Adjust the ItemNumbers for items after one is removed*/
struct LineItem *Item;
{
int ItemNumber;
struct LineItem *WorkingItem;
if((Item->cont) || Item==NULL) /*If a continued line, or if there*/
return(FALSE); /*is no item, just return*/
if((WorkingItem=(struct LineItem *)FindPrev(Item))==NULL)
ItemNumber=0;
else
ItemNumber=Item->ItemNumber;
while((Item=(struct LineItem *)FindNext(Item))!=NULL)
{
if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
ItemNumber=0;
Item->ItemNumber=ItemNumber++;
}
}
void AddItem(Item) /*Adjust the ItemNumbers after adding an item*/
struct LineItem *Item;
{
int ItemNumber;
struct LineItem *CrntItem;
if(Item->cont) /*If a continued line*/
return; /*just return*/
if((CrntItem=(struct LineItem *)FindPrev(Item))==NULL)
ItemNumber=0;
else
ItemNumber=CrntItem->ItemNumber+1;
do /*Go through the outline, updating ItemNumbers*/
{
if(ItemNumber==MaxNumOnLevel[Item->Level]-1)
ItemNumber=0;
Item->ItemNumber=ItemNumber++;
Item=(struct LineItem *)FindNext(Item);
}
while(Item != NULL && Item->PrevItem->Level >= Item->Level);
}
extern struct LineItem *FindPrev(Item) /*Find the previous item of*/
struct LineItem *Item; /*the same Level as Item*/
{
int Level;
Level=Item->Level;
Item=(struct LineItem *)Item->PrevItem;
while( (Item != NULL) && ((Item->cont) || (Item->Level > Level)) )
Item=(struct LineItem *)Item->PrevItem;
if(Item == NULL || Item->Level < Level )
return(NULL);
else
return(Item);
}
extern struct LineItem *FindNext(Item) /*Find the next item of the same*/
struct LineItem *Item; /*Level as Item*/
{
int Level;
Level=Item->Level;
Item=(struct LineItem *)Item->NextItem;
while( (Item != NULL) && ( (Item->cont) || (Item->Level > Level) ))
Item=(struct LineItem *)Item->NextItem;
/*vvvvvv--Changed (added)!!!*/
if((Item == NULL ) || (Item->Level < Level) || (Item->cont) )
return(NULL);
else
return(Item);
}
void InsertLineAtTop() /*Insert a line at the top of the list*/
{
struct LineItem *WorkingItem;
WorkingItem=(struct LineItem *)
InsertItem(FirstItem,NULL);
if(WorkingItem==NULL) /*Out of memory*/
{
Leave(0,"Memory too fragmented to add line!");
return;
}
WorkingItem->Level=1;
FirstItem=(struct LineItem *)WorkingItem;
AddItem(FirstItem);
PlotCursor(1,1);
RedrawOutlineChars(WorkingItem->NextItem,1,1);
PlotCursor(MinX(CurrentItem),1);
CursorUp();
}
IsOnScreen(item) /*Test to see whether a LineItem is currently*/
struct LineItem *item; /*on the screen, and if so, return its Y position*/
{
struct LineItem *wrk;
int y;
/*Search items on screen for a match*/
for(y=1,wrk=(struct LineItem *)FirstScrnItem;(wrk!=item) && (wrk!=ScrnBtm);
wrk=(struct LineItem *)wrk->NextItem,y++);
if(wrk == item)
return(y); /*It's on screen*/
else
return(FALSE);
}
IsBefore(item,start) /*Checks to see if 'item' if before 'start' in*/
struct LineItem *start,*item; /*the linked list*/
{
for(;(start != item) && (start != NULL);
start=(struct LineItem *)start->PrevItem);
if(start==item)
return(TRUE);
else
return(FALSE);
}
IsAfter(item,start) /*Checks to see if 'item' is after 'start' in the*/
struct LineItem *start,*item; /*linked list*/
{
for(;(start != item) && (start != NULL);
start=(struct LineItem *)start->NextItem);
if(start==item)
return(TRUE);
else
return(FALSE);
}
extern struct LineItem *FindPrevNonCont(Start)/*Find the first line before*/
struct LineItem *Start; /*or at 'Start' that isn't a continuation*/
{
struct LineItem *Item;
for(Item=(struct LineItem *)Start;(Item->PrevItem!=NULL)&&(Item->cont);
Item=(struct LineItem *)Item->PrevItem);
return(Item);
}
extern struct LineItem *FindNextNonCont(Start) /*Find the first non-*/
struct LineItem *Start; /*continuation after 'Start'*/
{
struct LineItem *Item;
for(Item=(struct LineItem *)Start;(Item->NextItem != NULL) &&
(Item->NextItem->cont);Item=(struct LineItem *)Item->NextItem);
return(Item);
}
CursorUp() /*Move the cursor up (scroll screen, etc.)*/
{
char Buffer[20];
int TempX;
CancelLineInvs();
if(ErrorInTitle)
TitleErrorCancel();
if(CurrentItem->PrevItem !=NULL)
{
if(CurrentItem==FirstScrnItem && CurrentItem != FirstItem)
{
TempX=CurX; /*Delete the last line*/
PlotCursor(1,SCRNHEIGHT);
Buffer[0]=0x9b;
Buffer[1]=0x4a;
WriteConsole(Buffer,2);
PlotCursor(TempX,1);
strcpy(Buffer,&SpecChars[SCPos[0x0c]]);
WriteConsole(Buffer,2);
TempX=CurX;
PlotCursor(1,1);
if(InvsMode < NOINV) /*Block Invs is active somewhere*/
switch(InvsMode)
{
case BLOCK_PENDING:
if(CurrentItem->PrevItem == StartIItem)
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_DOWN:
if(IsAfter(CurrentItem->PrevItem,StartIItem) && /*If it's in*/
IsBefore(CurrentItem->PrevItem,EndIItem)) /*the block*/
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_UP:
if(IsAfter(CurrentItem->PrevItem,EndIItem) && /*Same as*/
IsBefore(CurrentItem->PrevItem,StartIItem)) /*above*/
WriteConsole(Inv,-1);
}
PrintItem(CurrentItem->PrevItem);
WriteConsole(Norm,-1); /*Make it normal again*/
++CurY;
if(ScrnBtm==LastItem && DispRows < SCRNHEIGHT)
++DispRows;
else
ScrnBtm=(struct LineItem *)ScrnBtm->PrevItem;
FirstScrnItem=(struct LineItem *)FirstScrnItem->PrevItem;
CurX=TempX;
InvY++;
}
if(CurX < MinX(CurrentItem->PrevItem)) /*If the cursor wouldn't be*/
CurX=MinX(CurrentItem->PrevItem); /*in a legal place on the line*/
else /*now, move it onto the line*/
if(CurX > MaxX(CurrentItem->PrevItem))
CurX=MaxX(CurrentItem->PrevItem);
PlotCursor(CurX,CurY-1); /*Position the cursor*/
CurrentItem=(struct LineItem *) CurrentItem->PrevItem;
return(TRUE);
}
return(FALSE);
}
CursorDown() /*Move the cursor down (scroll screen, etc.)*/
{
unsigned char Buffer[20];
int TempX;
CancelLineInvs();
if(ErrorInTitle)
TitleErrorCancel();
if(CurrentItem->NextItem != NULL)
{
if(CurrentItem==ScrnBtm)
{
strcpy(Buffer,&SpecChars[SCPos[0x0d]]);
WriteConsole(Buffer,2);
TempX=CurX;
PlotCursor(1,CurY);
if(InvsMode < NOINV) /*Block Invs is active somewhere*/
switch(InvsMode)
{
case BLOCK_PENDING:
if(CurrentItem->NextItem == StartIItem)
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_DOWN:
if(IsAfter(CurrentItem->NextItem,StartIItem) && /*If it's in*/
IsBefore(CurrentItem->NextItem,EndIItem)) /*the block*/
WriteConsole(Inv,-1); /*Inverse*/
break;
case BLOCK_UP:
if(IsAfter(CurrentItem->NextItem,EndIItem) && /*Same as*/
IsBefore(CurrentItem->NextItem,StartIItem)) /*above*/
WriteConsole(Inv,-1);
}
PrintItem(CurrentItem->NextItem);
WriteConsole(Norm,-1);
PlotCursor(TempX,CurY-1);
ScrnBtm=(struct LineItem *)CurrentItem->NextItem;
FirstScrnItem=(struct LineItem *)FirstScrnItem->NextItem;
InvY--;
}
if(CurX < MinX(CurrentItem->NextItem)) /*If the cursor wouldn't be on*/
CurX=MinX(CurrentItem->NextItem); /*the new line, move it*/
else
if(CurX > MaxX(CurrentItem->NextItem))
CurX=MaxX(CurrentItem->NextItem);
PlotCursor(CurX,CurY+1);
CurrentItem=(struct LineItem *)CurrentItem->NextItem; /*Update the */
return(TRUE); /*Current line pointer*/
}
return(FALSE);
}
/*~~~End of liner.c*/