' "BSpread" - an AmigaBasic(tm) Spread Sheet;
' Written  for  'Amazing Computing'  Magazine
'      by Bryan D. Catley,  August 1987
' -------------------------------------------
'
'    Copyright (c) 1987 by FelineSystems.
'           All rights reserved.
'
'
'*********************************************************
'*                                                       *
'* Using BSpread with AC/BASIC:                          *
'* ----------------------------                          *
'*                                                       *
'* To compile BSpread, you must switch on the N & A      *
'* options.  The N option is for runtime event detection *
'* and the A option is for Long Addressing.              *
'*                                                       *
'*********************************************************
'
CLEAR ,25000:CLEAR ,105000&:OPTION BASE 1
MaxCol=40:MaxRow=50:CWidth=10:NumCols=7:Yes=0
Blk=0:Gra=1:Mag=2:Yel=3:m0=0:menuID=0:menuIT=0
n=0:x=0:y=0:z=0:rowtop=0:colleft=0:oldtop=0:oldleft=0
StartCol=1:EndCol=7:ColLite=0:FirstCol=40:LastCol=600
StartRow=1:EndRow=19:RowLite=0:FirstRow=32:LastRow=184
ErrSw=0:RelSw=0:Total=0:CellMgmt=0:Holding=0:HoldCols=0
TempCol=0:TempRow=0:NoGdgt=0:AllOK=-1:Saved=-1
x%=0:row%=0:col%=0:PrintCol%=6:PrintRow%=5
CellValue$="":TypeFlag$="":Response$="":Cell$=""
TempCol$="":TempRow$="":Prompt$="":Prompt2$=""
a$="":b$="":x$="":y$="":z$="":FileNm$="":TxtNm$=""
Formula$="":ErrMsg$="":op$="":ops$="+-*/!"
Mask$="################.##-":Key$=""
DIM IPcursor%(20),CellLite%(165)
DIM ColHdg$(MaxCol),BSpread$(MaxCol,MaxRow,2),MKeys$(2)
GOSUB Initialize:ON ERROR GOTO BasicError
WHILE MOUSE(0)=0:WEND:WHILE MOUSE(0)<>0:WEND
LINE(40,32)-STEP(560,152),Gra,bf

WaitForUser:
IF ErrSw=0 THEN 
  COLOR Mag,Blk:LOCATE 2,1
  PRINT"Use Project Menus or Select a Cell.";SPACE$(33);
END IF
m0=0:menuID=0:menuIT=0:Key$="":ErrSw=0
MKeys$(1)="LSATPQ":MKeys$(2)="CG"
WHILE m0=0 AND menuID=0 AND Key$=""
  x=MOUSE(1):y=MOUSE(2)
  IF x>FirstCol AND x<LastCol AND y>FirstRow AND y<LastRow THEN
    GOSUB MouseOK
  ELSE
    IF oldtop<>0 THEN PUT(oldleft,oldtop),CellLite%
    oldtop=0:rowtop=0:oldleft=0:colleft=0
  END IF
  m0=MOUSE(0):menuID=MENU(0):menuIT=MENU(1):Key$=INKEY$
WEND
IF Key$<>"" THEN
  FOR n=1 TO 2
    x=INSTR(MKeys$(n),UCASE$(Key$))
    IF x<>0 THEN menuID=n:menuIT=x:n=2
  NEXT
END IF
IF menuID<>0 THEN ON menuID GOTO ProjMgmtI,ProjMgmtII
x=MOUSE(1):y=MOUSE(2):WHILE MOUSE(0)<>0:WEND
IF x>40 AND x<600 AND y>16 AND y<24 THEN NewColumn
IF x>4 AND x<16 AND y>29 AND y<179 THEN NewRow
IF x<FirstCol OR x>600 OR y<FirstRow OR y>184 THEN WaitForUser

CellSelected:
CellCol=INT((x-FirstCol)/(CWidth*8)+StartCol)
CellRow=INT((y-FirstRow)/8+StartRow)
MENU 1,0,0:MENU 2,0,0:MENU 3,0,1:MENU 4,0,1
CellMgmt=-1
NewCellSelection:
COLOR Mag,Blk:LOCATE 2,1
PRINT"Use Cell Menus or Click in Another Cell.";SPACE$(28);
m0=0:menuID=0:menuIT=0:Key$="":MKeys$(1)="DF$$$$$$GX":MKeys$(2)=""
WHILE m0=0 AND menuID=0 AND Key$=""
  m0=MOUSE(0):menuID=MENU(0):menuIT=MENU(1):Key$=INKEY$
WEND
IF Key$<>"" THEN
  x=INSTR(MKeys$(1),UCASE$(Key$))
  IF x<>0 THEN menuID=3:menuIT=x
END IF
IF menuID<>0 THEN
  ON menuID-2 GOTO CellMgmtI,CellMgmtII
ELSE
  x=MOUSE(1):y=MOUSE(2):WHILE MOUSE(0)<>0:WEND
  IF x>40 AND x<600 AND y>16 AND y<24 THEN NewColumn
  IF x>4 AND x<16 AND y>29 AND y<179 THEN NewRow
  IF x>FirstCol AND x<LastCol AND y>FirstRow AND y<LastRow THEN
    GOSUB MouseOK:GOTO CellSelected
  ELSE
    GOTO NewCellSelection
  END IF
END IF

NewColumn:
StartCol=INT((x-40)/14)+1:LastCol=600
IF StartCol+NumCols>MaxCol THEN
  LastCol=((MaxCol+1-StartCol)*(CWidth*8))+40
END IF
GOSUB DoColHdg:GOSUB ShoData
IF CellMgmt THEN CellSelected ELSE WaitForUser

NewRow:
StartRow=INT((y-29)/3)+1:LastRow=184
IF StartRow+19>MaxRow THEN LastRow=((MaxRow+1-StartRow)*8)+32
GOSUB DoRowHdg:GOSUB ShoData:
IF CellMgmt THEN CellSelected ELSE WaitForUser

CellMgmtI:
ON menuIT GOTO CellData,CellFormula,ZeroCell,BlankCell,CopyCell
ON menuIT-5 GOTO MoveCell,PropRight,PropDown,CMGoTo,CellExit

CellData:
CellValue$=BSpread$(CellCol,CellRow,1)
TypeFlag$=BSpread$(CellCol,CellRow,2)
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"New Cell Value? ";
x%=CWidth:GetData CellValue$,"CHAR",x%
IF CellValue$<>"" THEN
  BSpread$(CellCol,CellRow,1)=CellValue$
  BSpread$(CellCol,CellRow,2)=TypeFlag$
ELSE
  BSpread$(CellCol,CellRow,1)=""
  BSpread$(CellCol,CellRow,2)=""
END IF
GOSUB PrintCell:GOTO CellChanged

CellFormula:
CellValue$=MID$(BSpread$(CellCol,CellRow,2),2)
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"New Formula? ";
GetData CellValue$,"CHAR",53:CellValue$=UCASE$(CellValue$)
IF CellValue$<>"" THEN
  BSpread$(CellCol,CellRow,2)="F"+CellValue$
  BSpread$(CellCol,CellRow,1)=STRING$(CWidth,"*")
ELSE
  BSpread$(CellCol,CellRow,1)=""
  BSpread$(CellCol,CellRow,2)=""
END IF
GOSUB PrintCell:GOTO CellChanged

ZeroCell:
BSpread$(CellCol,CellRow,1)="0"
BSpread$(CellCol,CellRow,2)="N"
GOSUB PrintCell:GOTO CellChanged

BlankCell:
BSpread$(CellCol,CellRow,1)=""
BSpread$(CellCol,CellRow,2)=""
GOSUB PrintCell:GOTO CellChanged

CopyCell:
MoveCell:
Prompt$="Target Cell? ":GOSUB GetCellNum
BSpread$(TempCol,TempRow,1)=BSpread$(CellCol,CellRow,1)
BSpread$(TempCol,TempRow,2)=BSpread$(CellCol,CellRow,2)
IF menuIT=6 THEN
  BSpread$(CellCol,CellRow,1)="":GOSUB PrintCell
  BSpread$(CellCol,CellRow,2)=""
END IF
IF TempCol>=StartCol AND TempCol<=EndCol THEN
  IF TempRow>=StartRow AND TempRow<=EndRow THEN
    IF menuIT=6 THEN GOSUB PrintCell
    x=CellCol:y=CellRow:CellCol=TempCol:CellRow=TempRow
    GOSUB PrintCell:CellCol=x:CellRow=y
  END IF
END IF
GOTO CellChanged

PropRight:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"Number of Columns? ";
Response$="":GetData Response$,"INT",2:y=VAL(Response$)
IF Response$<>"" THEN
  IF CellCol+y>MaxCol THEN y=MaxCol-CellCol
  FOR x=CellCol+1 TO CellCol+y
    BSpread$(x,CellRow,1)=BSpread$(CellCol,CellRow,1)
    BSpread$(x,CellRow,2)=BSpread$(CellCol,CellRow,2)
  NEXT
  y=y+EndCol:IF y>EndCol THEN y=EndCol
  x=CellCol:FOR CellCol=x+1 TO y:GOSUB PrintCell:NEXT
  CellCol=x
END IF
GOTO CellChanged

PropDown:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"Number of Rows? ";
Response$="":GetData Response$,"INT",2:y=VAL(Response$)
IF Response$<>"" THEN
  IF CellRow+y>MaxRow THEN y=MaxRow-CellRow
  FOR x=CellRow+1 TO CellRow+y
    BSpread$(CellCol,x,1)=BSpread$(CellCol,CellRow,1)
    BSpread$(CellCol,x,2)=BSpread$(CellCol,CellRow,2)
  NEXT
  y=CellRow+y:IF y>EndRow THEN y=EndRow
  x=CellRow:FOR CellRow=x+1 TO y:GOSUB PrintCell:NEXT
  CellRow=x
END IF
GOTO CellChanged

CMGoTo:
GOSUB GoToCell:GOTO NewCellSelection

CellMgmtII:
ON menuIT GOTO ZeroCol,ZeroRow,BlankCol,BlankRow,InsertCol
ON menuIT-5 GOTO InsertRow,RemoveCol,RemoveRow

ZeroCol:
BlankCol:
COLOR Mag,Blk:LOCATE 2,1:PRINT SPACE$(68)
IF menuIT=1 THEN Prompt$="  Ok to zero":Prompt2$=" this column?"
IF menuIT=1 THEN a$="N":b$="0"
IF menuIT=3 THEN Prompt$="  Ok to blank":Prompt2$=" this column?"
IF menuIT=3 THEN a$="C":b$=""
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
IF menuIT=1 THEN LOCATE 2,1:PRINT"Zeroing column..."
IF menuIT=3 THEN LOCATE 2,1:PRINT"Blanking column..."
FOR TempRow=1 TO MaxRow
  IF BSpread$(CellCol,TempRow,2)=a$ THEN
    BSpread$(CellCol,TempRow,1)=b$
    x=CellRow:CellRow=TempRow:GOSUB PrintCell:CellRow=x
    IF menuIT=3 THEN BSpread$(CellCol,TempRow,2)=""
  END IF
NEXT
GOTO CellChanged

ZeroRow:
BlankRow:
COLOR Mag,Blk:LOCATE 2,1:PRINT SPACE$(68)
IF menuIT=2 THEN Prompt$="  Ok to zero":Prompt2$="   this row?"
IF menuIT=2 THEN a$="N":b$="0"
IF menuIT=4 THEN Prompt$="  Ok to blank":Prompt2$="  this row?"
IF menuIT=4 THEN a$="C":b$=""
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
IF menuIT=2 THEN LOCATE 2,1:PRINT"Zeroing column..."
IF menuIT=4 THEN LOCATE 2,1:PRINT"Blanking column..."
FOR TempCol=1 TO MaxCol
  IF BSpread$(TempCol,CellRow,2)=a$ THEN
    BSpread$(TempCol,CellRow,1)=b$
    x=CellCol:CellCol=TempCol:GOSUB PrintCell:CellCol=x 
    IF menuIT=4 THEN BSpread$(TempCol,CellRow,2)=""   
  END IF
NEXT
GOTO CellChanged

InsertCol:
COLOR Mag,Blk:LOCATE 2,1:PRINT SPACE$(68)
Prompt$="  Ok to loose":Prompt2$="  column  NN?"
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
COLOR Gra,Blk:LOCATE 2,1:PRINT"Inserting column..."
IF CellCol<MaxCol THEN
  FOR TempCol=MaxCol-1 TO CellCol STEP -1
    FOR TempRow=1 TO MaxRow
      BSpread$(TempCol+1,TempRow,1)=BSpread$(TempCol,TempRow,1)
      BSpread$(TempCol+1,TempRow,2)=BSpread$(TempCol,TempRow,2)
    NEXT
  NEXT
END IF
FOR TempRow=1 TO MaxRow
  BSpread$(CellCol,TempRow,1)=""
  BSpread$(CellCol,TempRow,2)=""
NEXT
GOSUB ShoData:GOTO CellChanged

InsertRow:
COLOR Mag,Blk:LOCATE 2,1:PRINT SPACE$(68)
Prompt$="  Ok to loose":Prompt2$="    row 50?"
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
COLOR Gra,Blk:LOCATE 2,1:PRINT"Inserting row..."
IF CellRow<MaxRow THEN
  FOR TempCol=1 TO MaxCol
    FOR TempRow=MaxRow-1 TO CellRow STEP -1
      BSpread$(TempCol,TempRow+1,1)=BSpread$(TempCol,TempRow,1)
      BSpread$(TempCol,TempRow+1,2)=BSpread$(TempCol,TempRow,2)
    NEXT
  NEXT
END IF
FOR TempCol=1 TO MaxCol
  BSpread$(TempCol,CellRow,1)=""
  BSpread$(TempCol,CellRow,2)=""
NEXT
GOSUB ShoData:GOTO CellChanged

RemoveCol:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
Prompt$=" OK to delete":Prompt2$="current column?"
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
LOCATE 2,1:PRINT"Deleting column..."
IF CellCol<MaxCol THEN
  FOR TempCol=CellCol TO MaxCol-1
    FOR TempRow=1 TO MaxRow
      BSpread$(TempCol,TempRow,1)=BSpread$(TempCol+1,TempRow,1)
      BSpread$(TempCol,TempRow,2)=BSpread$(TempCol+1,TempRow,2)
    NEXT
  NEXT
END IF
FOR TempRow=1 TO MaxRow
  BSpread$(MaxCol,TempRow,1)="":BSpread$(MaxCol,TempRow,2)=""
NEXT
GOSUB ShoData:GOTO CellChanged

RemoveRow:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
Prompt$=" OK to delete":Prompt2$=" current row?"
GOSUB YesNo:IF NOT Yes THEN NewCellSelection
LOCATE 2,1:PRINT"Deleting row..."
IF CellRow<MaxRow THEN
  FOR TempCol=1 TO MaxCol
    FOR TempRow=CellRow TO MaxRow-1
      BSpread$(TempCol,TempRow,1)=BSpread$(TempCol,TempRow+1,1)
      BSpread$(TempCol,TempRow,2)=BSpread$(TempCol,TempRow+1,2)
    NEXT
  NEXT
END IF
FOR TempCol=1 TO MaxCol
  BSpread$(TempCol,MaxRow,1)="":BSpread$(TempCol,MaxRow,2)=""
NEXT
GOSUB ShoData:GOTO CellChanged

CellChanged:
Saved=0:LINE(609,9)-STEP(6,6),Mag,bf
GOTO NewCellSelection

CellExit:
IF NOT Holding THEN MENU 1,0,1
MENU 2,0,1:MENU 3,0,0:MENU 4,0,0
CellMgmt=0:GOTO WaitForUser

ProjMgmtI:
ON menuIT GOTO LodSheet,SvSheet,SvSheetAs,SvTxt,prStart,Xit

LodSheet:
IF NOT Saved THEN
  Prompt$="Sheet not saved":Prompt2$="   Continue?"
  GOSUB YesNo:IF NOT Yes THEN WaitForUser
END IF
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"Load sheet? ";
LSget:
COLOR Gra,Blk:LOCATE 2,13:GetData FileNm$,"CHAR",39
IF FileNm$="" THEN WaitForUser
IF RIGHT$(FileNm$,4)<>".bsp" THEN FileNm$=FileNm$+".bsp"
OPEN FileNm$ FOR INPUT AS #1
AfterOpen:
IF ErrSw=1 THEN ErrSw=0:GOTO LSget
LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"Loading sheet ";FileNm$
INPUT#1,CWidth,NumCols,StartCol,EndCol
INPUT#1,LastCol,StartRow,EndRow,LastRow
INPUT#1,Mask$
FOR TempCol=1 TO MaxCol
  FOR TempRow=1 TO MaxRow
    INPUT#1,BSpread$(TempCol,TempRow,1)
    INPUT#1,BSpread$(TempCol,TempRow,2)
  NEXT
NEXT
CLOSE #1:GOSUB DoColHdg:GOSUB DoRowHdg
MENU 2,5,1:MENU 2,6,1:MENU 2,7,1:MENU 2,8,1
x=CWidth/5+4:MENU 2,x,2
Saved=-1:LINE(609,9)-STEP(6,6),Blk,bf:COLOR Yel,Blk
LOCATE 1,16:PRINT RIGHT$(FileNm$,52);SPACE$(52-LEN(FileNm$))
IF MID$(Mask$,17,1)="." THEN TwoDec ELSE NoDec

SvSheet:
SvSheetAs:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
IF FileNm$="" OR menuIT=3 THEN
  LOCATE 2,1:PRINT"Save as sheet? ";
  GetData FileNm$,"CHAR",50
END IF
IF FileNm$="" THEN WaitForUser
IF RIGHT$(FileNm$,4)<>".bsp" THEN FileNm$=FileNm$+".bsp"
LOCATE 2,1:PRINT SPACE$(68)
LOCATE 2,1:PRINT"Saving sheet ";FileNm$
OPEN FileNm$ FOR OUTPUT AS #1
WRITE#1,CWidth,NumCols,StartCol,EndCol
WRITE#1,LastCol,StartRow,EndRow,LastRow
WRITE#1,Mask$
FOR TempCol=1 TO MaxCol
  FOR TempRow=1 TO MaxRow
    WRITE#1,BSpread$(TempCol,TempRow,1)
    WRITE#1,BSpread$(TempCol,TempRow,2)
  NEXT
NEXT
CLOSE #1:Saved=-1:COLOR Yel,Blk
LOCATE 1,16:PRINT RIGHT$(FileNm$,52);SPACE$(52-LEN(FileNm$))
GOTO WaitForUser

SvTxt:
prStart:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68):z$=""
LOCATE 2,1:PRINT"Number of columns? ";:GetData z$,"INT",1
z=VAL(z$):LOCATE 2,1:PRINT SPACE$(68)
IF z>NumCols OR z<1 THEN z=NumCols
IF menuIT=4 THEN
  LOCATE 2,1:PRINT"Save as text file? ";
  GetData TxtNm$,"CHAR",48
  IF TxtNm$="" THEN WaitForUser
  IF RIGHT$(TxtNm$,4)<>".txt" THEN TxtNm$=TxtNm$+".txt"
  LOCATE 2,1:PRINT SPACE$(68)
  LOCATE 2,1:PRINT"Saving text file ";TxtNm$
  OPEN TxtNm$ FOR OUTPUT AS #1
ELSE
  LOCATE 2,1:PRINT"Printing sheet..."
END IF
FOR y=1 TO MaxRow
  FOR x=StartCol TO StartCol+z-1
    x$=BSpread$(x,y,1)
    y$=LEFT$(BSpread$(x,y,2),1)
    IF (y$="N" OR y$="F") AND LEN(x$)>CWidth THEN
      x$="*LEN*"+STRING$(CWidth-5,"*")
    END IF     
    n=CWidth-LEN(x$):IF n<0 THEN n=0
    IF y$="C" OR y$="" OR LEFT$(x$,1)="*" THEN
      IF menuIT=4 THEN 
        PRINT#1,x$;SPACE$(n);
      ELSE
        LPRINT x$+SPACE$(n);
      END IF
    ELSE
      IF menuIT=4 THEN
        PRINT#1,USING RIGHT$(Mask$,CWidth);VAL(x$);
      ELSE
        LPRINT USING RIGHT$(Mask$,CWidth);VAL(x$);
      END IF
    END IF
  NEXT
  IF menuIT=4 THEN PRINT#1," " ELSE LPRINT " "
NEXT
IF menuIT=4 THEN CLOSE#1
GOTO WaitForUser

ProjMgmtII:
ON menuIT GOTO Calculate,PRGoTo,ClrSheet,ResetSheet,CSz5
ON menuIT-5 GOTO CSz10,CSz15,CSz20,TwoDec,NoDec,HoldRlse
ON menuIT-11 GOTO Template

Calculate:
COLOR Gra,Blk:LOCATE 2,1:PRINT"Calculating...";SPACE$(54);
FOR CellRow=1 TO MaxRow
  FOR CellCol=1 TO MaxCol
    IF LEFT$(BSpread$(CellCol,CellRow,2),1)="F" THEN
      Formula$=MID$(BSpread$(CellCol,CellRow,2),2)
      Total=0:ErrSw=0
      IF Formula$="TOTCOL" THEN
        GOSUB TotalCols
      ELSEIF Formula$="TOTROW" THEN
        GOSUB TotalRows
      ELSEIF Formula$<>"" THEN
        GOSUB Evaluate
      END IF
      IF LEN(STR$(Total))>CWidth THEN
        ErrMsg$="Result too big!":ErrSw=1
      END IF
      IF ErrSw=1 THEN
        BEEP:COLOR Mag,Blk:LOCATE 2,1:PRINT SPACE$(68)
        LOCATE 2,67-LEN(ErrMsg$):PRINT ErrMsg$
      END IF
    END IF
  NEXT 
NEXT
GOTO CalcXit

TotalCols:
IF CellRow=1 THEN
  BSpread$(CellCol,CellRow,1)="0"
ELSE
  FOR y=1 TO CellRow-1
    IF LEFT$(BSpread$(CellCol,y,2),1)="N" THEN
      Total=Total+VAL(BSpread$(CellCol,y,1))
    ELSEIF LEFT$(BSpread$(CellCol,y,2),1)="F" THEN
      IF LEFT$(BSpread$(CellCol,y,1),1)<>"*" THEN
        Total=Total+VAL(BSpread$(CellCol,y,1))
      END IF
    END IF
  NEXT
END IF
BSpread$(CellCol,CellRow,1)=STR$(Total):GOSUB PrintCell
RETURN

TotalRows:
IF CellCol=1 THEN
  BSpread$(CellCol,CellRow,1)="0"
ELSE
  FOR x=1 TO CellCol-1
    IF LEFT$(BSpread$(x,CellRow,2),1)="N" THEN
      Total=Total+VAL(BSpread$(x,CellRow,1))
    ELSEIF LEFT$(BSpread$(x,CellRow,2),1)="F" THEN
      IF LEFT$(BSpread$(x,CellRow,1),1)<>"*" THEN
        Total=Total+VAL(BSpread$(x,CellRow,1))
      END IF
    END IF
  NEXT
END IF
BSpread$(CellCol,CellRow,1)=STR$(Total):GOSUB PrintCell
RETURN

Evaluate:
op$="+":CellValue$="":Formula$=Formula$+"!"
FOR x=1 TO LEN(Formula$)
  x$=MID$(Formula$,x,1):y=INSTR(ops$,x$)
  IF (x$="[" OR RelSw=1) THEN
    RelSw=1:CellValue$=CellValue$+x$
    IF x$="]" THEN RelSw=0
  ELSEIF (y=0) OR (y<>0 AND CellValue$="") THEN
    CellValue$=CellValue$+x$
  ELSE
    y$=LEFT$(CellValue$,1)
    IF (y$<CHR$(48) OR y$>CHR$(57)) AND (y$<>"-" AND y$<>".") THEN
      Cell$=CellValue$:GOSUB GetCellID
      IF AllOK THEN
        y$=BSpread$(TempCol,TempRow,1)
        z$=BSpread$(TempCol,TempRow,2)
        IF LEFT$(z$,1)="N" THEN
          CellValue$=y$
        ELSEIF LEFT$(z$,1)="F" THEN
          IF LEFT$(y$,1)<>"*" THEN
            CellValue$=y$
          ELSE
            ErrMsg$="Unresolved Formula at "+CellValue$:ErrSw=1
          END IF
        ELSE
          ErrMsg$="Character/Null at "+CellValue$:ErrSw=1
        END IF
      END IF
    END IF
    IF ErrSw<>1 THEN
      IF op$="+" THEN Total=Total+VAL(CellValue$)
      IF op$="-" THEN Total=Total-VAL(CellValue$)
      IF op$="*" THEN Total=Total*VAL(CellValue$)
      IF op$="/" THEN Total=Total/VAL(CellValue$)
      op$=x$:CellValue$=""
    ELSE
      x=LEN(Formula$)
    END IF
  END IF
NEXT    
IF ErrSw=0 THEN
  BSpread$(CellCol,CellRow,1)=STR$(Total):GOSUB PrintCell
END IF
RETURN

CalcXit:
LINE(609,9)-STEP(6,6),Mag,bf:Saved=0
GOTO WaitForUser

PRGoTo:
GOSUB GoToCell:GOTO WaitForUser

ClrSheet:
Prompt$="  OK to clear":Prompt2$="     Sheet?":GOSUB YesNo
IF NOT Yes THEN WaitForUser
COLOR Gra,Blk:LOCATE 2,1:PRINT"Clearing Sheet...";SPACE$(51)
FOR x=1 TO MaxCol
  FOR y=1 TO MaxRow
    BSpread$(x,y,1)=""
    BSpread$(x,y,2)=""
  NEXT
NEXT
LINE(40,32)-STEP(560,152),Gra,bf
LINE(609,9)-STEP(6,6),Blk,bf
Saved=-1:GOTO WaitForUser

ResetSheet:
Prompt$="  OK to reset":Prompt2$="     Sheet?":GOSUB YesNo
IF NOT Yes THEN WaitForUser
COLOR Gra,Blk:LOCATE 2,1:PRINT"Resetting Sheet...";SPACE$(50)
FOR CellRow=1 TO MaxRow
  FOR CellCol=1 TO MaxCol
    IF LEFT$(BSpread$(CellCol,CellRow,2),1)="F" THEN
      BSpread$(CellCol,CellRow,1)=STRING$(CWidth,"*")
      GOSUB PrintCell
    END IF
  NEXT
NEXT
LINE(609,9)-STEP(6,6),Blk,bf
Saved=0:GOTO WaitForUser

CSz5:
CSz10:
CSz15:
CSz20:
MENU 2,5,1:MENU 2,6,1:MENU 2,7,1:MENU 2,8,1
IF menuIT=5 THEN MENU 2,5,2:CWidth= 5:NumCols=14
IF menuIT=6 THEN MENU 2,6,2:CWidth=10:NumCols= 7
IF menuIT=7 THEN MENU 2,7,2:CWidth=15:NumCols= 4
IF menuIT=8 THEN MENU 2,8,2:CWidth=20:NumCols= 3
GOSUB DoColHdg:GOSUB ShoData:GOTO WaitForUser

TwoDec:
MENU 2,9,2:MENU 2,10,1:Mask$="################.##-"
GOSUB ShoData:GOTO WaitForUser

NoDec:
MENU 2,9,1:MENU 2,10,2:Mask$="###################-"
GOSUB ShoData:GOTO WaitForUser

HoldRlse:
IF NOT Holding THEN
  COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68)
  LOCATE 2,1:PRINT"How Many? ";
  Response$="":GetData Response$,"INT",1:HoldCols=VAL(Response$)
  IF HoldCols=>NumCols THEN HoldCols=NumCols-1
  StartCol=StartCol+HoldCols:FirstCol=40+CWidth*8*HoldCols
  NumCols=NumCols-HoldCols:PrintCol%=6+CWidth*HoldCols
  MENU 2,5,0:MENU 2,6,0:MENU 2,7,0:MENU 2,8,0
  MENU 2,11,1," Release Cols    ":Holding=-1:GOSUB DoColHdg
  MENU 1,0,0:MENU 2,12,0:MENU 4,6,0:MENU 4,8,0
ELSE
  StartCol=StartCol=HoldCols
  IF StartCol<1 THEN StartCol=1
  FirstCol=40:PrintCol%=6:Holding=0
  MENU 2,5,1:MENU 2,6,1:MENU 2,7,1:MENU 2,8,1
  IF CWidth= 5 THEN MENU 2,5,1:NumCols=14
  IF CWidth=10 THEN MENU 2,6,2:NumCols= 7
  IF CWidth=15 THEN MENU 2,7,2:NumCols= 4
  IF CWidth=20 THEN MENU 2,8,2:NumCols= 3
  MENU 2,11,1," Hold 1st Cols   "
  GOSUB DoColHdg:GOSUB ShoData
  MENU 1,0,1:MENU 2,12,1:MENU 4,6,1:MENU 4,8,1
END IF
GOTO WaitForUser

Template:
Prompt$="  OK to  Make":Prompt2$="  a Template?":GOSUB YesNo
IF NOT Yes THEN WaitForUser
COLOR Gra,Blk:LOCATE 2,1:PRINT"Making Template...";SPACE$(50)
FOR CellRow=1 TO MaxRow
  FOR CellCol=1 TO MaxCol
    x$=LEFT$(BSpread$(CellCol,CellRow,2),1)
    IF x$="N" THEN
      BSpread$(CellCol,CellRow,1)=""
      BSpread$(CellCol,CellRow,2)=""
      GOSUB PrintCell
    ELSEIF x$="F" THEN
      BSpread$(CellCol,CellRow,1)=STRING$(CWidth,"*")
      GOSUB PrintCell
    END IF
  NEXT
NEXT
LINE(609,9)-STEP(6,6),Blk,bf
Saved=0:GOTO WaitForUser

Xit:
IF NOT Saved THEN
  Prompt$="Sheet not saved":Prompt2$="Quit 'BSpread'?"
  GOSUB YesNo:IF NOT Yes THEN WaitForUser
END IF
MENU RESET:COLOR Gra,Blk
' $IGNORE ON
CLEAR ,25000
' $IGNORE OFF
CLS:END

YesNo:
WINDOW 2,,(120,51)-(258,97),0,-1
COLOR Blk,Yel:x=22
FOR n=32 TO 0 STEP -1
  LINE(0,n)-STEP(137,0),Yel
  x=x+1
  LINE(0,x)-STEP(137,0),Yel
NEXT
LINE(15,31)-STEP(32,16),Blk,bf:LINE(95,31)-STEP(32,16),Blk,bf
LINE(12,28)-STEP(32,16),Gra,bf:LINE(92,28)-STEP(32,16),Gra,bf
LINE(12,28)-STEP(32,16),Mag,b:LINE(92,28)-STEP(32,16),Mag,b
LINE(13,29)-STEP(30,14),Mag,b:LINE(93,29)-STEP(30,14),Mag,b
LOCATE 2,2:PRINT Prompt$:LOCATE 3,2:PRINT Prompt2$
COLOR Mag,Gra:LOCATE 5,3:PRINT"Yes";PTAB(100);"No";
NoGdgt=-1
WHILE NoGdgt
  WHILE MOUSE(0)=0:WEND
    x=MOUSE(1):y=MOUSE(2)
    IF y>28 AND y<44 THEN
      IF x>12 AND x<52 THEN
        Yes=-1:NoGdgt=0
      ELSEIF x>92 AND x<122 THEN
        Yes=0:NoGdgt=0
      END IF
    END IF
  WHILE MOUSE(0)<>0:WEND
WEND
WINDOW CLOSE 2
RETURN

GoToCell:
Prompt$="Go To Cell? ":GOSUB GetCellNum
StartCol=TempCol:LastCol=600
IF StartCol+NumCols>MaxCol THEN
  LastCol=((MaxCol+1-StartCol)*(CWidth*8))+40
END IF
StartRow=TempRow:LastRow=184
IF StartRow+19>MaxRow THEN LastRow=((MaxRow+1-StartRow)*8)+32
GOSUB DoColHdg:GOSUB DoRowHdg:GOSUB ShoData
RETURN

GetCellNum:
COLOR Gra,Blk:LOCATE 2,1:PRINT SPACE$(68):Cell$=""
GCNget:
LOCATE 2,1:PRINT Prompt$;
GetData Cell$,"CHAR",4:GOSUB GetCellID
IF NOT AllOK THEN
  COLOR Mag,Blk:LOCATE 2,67-LEN(ErrMsg$)
  PRINT ErrMsg$:BEEP
  COLOR Gra,Blk:GOTO GCNget
END IF
RETURN

GetCellID:
Cell$=UCASE$(Cell$):AllOK=-1:ErrSw=0
IF LEFT$(Cell$,1)="[" THEN
  n=1:GOSUB RelCell
  IF AllOK AND MID$(Cell$,n,1)="," THEN
    GOSUB RelCell
  ELSE
    IF MID$(Cell$,n,1)="]" THEN
      ErrMsg$="Missing Col/Row: "+Cell$:ErrSw=1:AllOK=0
    ELSE
      IF ErrSw=0 THEN GOSUB RelCell
    END IF
  END IF
ELSE
  GOSUB AbsCell
END IF
RETURN

RelCell:
z$=MID$(Cell$,n,1)
IF z$="[" OR z$="," THEN
  n=n+1:z$=MID$(Cell$,n,1)
  IF z$="C" OR z$="R" THEN
    n=n+1:a$=MID$(Cell$,n,1)
    IF a$="+" OR a$="-" THEN
      n=n+1:y$=MID$(Cell$,n+1,1)
      IF y$="," OR y$="]" THEN
        y$=MID$(Cell$,n,1):n=n+1
      ELSE
        y$=MID$(Cell$,n,2):n=n+2
      END IF
      IF z$="C" THEN 
        IF a$="+" THEN TempCol=CellCol+VAL(y$)
        IF a$="-" THEN TempCol=CellCol-VAL(y$)
        IF TempCol<1 OR TempCol>MaxCol THEN
          ErrMsg$="Illegal Column: "+Cell$:ErrSw=1:AllOK=0:TempCol=1
        END IF
      ELSEIF z$="R" THEN
        IF a$="+" THEN TempRow=CellRow+VAL(y$)      
        IF a$="-" THEN TempRow=CellRow-VAL(y$)
        IF TempRow<1 OR TempRow>MaxRow THEN
          ErrMsg$="Illegal Row: "+Cell$:ErrSw=1:AllOK=0:TempRow=1
        END IF
      END IF
    ELSE
      ErrMsg$="Illegal Operator: "+Cell$:ErrSw=1:AllOK=0 
    END IF
  ELSE
    ErrMsg$="Must Specify a C or R: "+Cell$:ErrSw=1:AllOK=0   
  END IF
ELSE
  ErrMsg$="Illegal Relative Format: "+Cell$:ErrSw=1:AllOK=0
END IF
RETURN
      
AbsCell:
TempCol=0
IF LEN(Cell$)<2 THEN ACerr1
IF LEN(Cell$)=2 OR LEN(Cell$)=4 THEN
  n=LEN(Cell$)/2
  TempCol$=LEFT$(Cell$,n):TempRow$=RIGHT$(Cell$,n)
ELSE
  IF MID$(Cell$,2,1)<CHR$(58) THEN
    TempCol$=LEFT$(Cell$,1):TempRow$=RIGHT$(Cell$,2)
  ELSE
    TempCol$=LEFT$(Cell$,2):TempRow$=RIGHT$(Cell$,1)
  END IF
END IF
IF LEN(TempCol$)=2 THEN
  IF LEFT$(TempCol$,1)<>RIGHT$(TempCol$,1) THEN ACerr2
  TempCol=26:TempCol$=RIGHT$(TempCol$,1)
END IF
TempCol=TempCol+ASC(TempCol$)-64
IF TempCol<1 OR TempCol>MaxCol THEN ACerr2
TempRow=VAL(TempRow$)
IF TempRow<1 OR TempRow>MaxRow THEN ACerr3
GOTO ACexit
ACerr1:ErrMsg$="Illegal CellID: ":GOTO ACerrEnd
ACerr2:ErrMsg$="Invalid Column: ":GOTO ACerrEnd
ACerr3:ErrMsg$="Invalid Row: ":GOTO ACerrEnd
ACerrEnd:ErrMsg$=ErrMsg$+Cell$:AllOK=0:ErrSw=1
ACexit:
RETURN

ShoData:
LINE(FirstCol,FirstRow)-(600,192),Gra,bf
rowtop=0:oldtop=0:colleft=0:oldleft=0
FOR CellRow=StartRow TO EndRow
  FOR CellCol=StartCol TO EndCol
    GOSUB PrintCell
  NEXT
NEXT
CellCol=StartCol:CellRow=StartRow
IF CellMgmt THEN x=FirstCol+4:y=FirstRow+4:GOSUB MouseOK
RETURN

MouseOK:
n=CWidth*8
rowtop=INT(y/8)*8:colleft=INT((x-40)/n)*n+40
IF colleft>LastCol-n THEN colleft=LastCol-n
IF rowtop<>oldtop OR colleft<>oldleft THEN
  IF oldtop<>0 THEN PUT(oldleft,oldtop),CellLite%
  PUT(colleft,rowtop),CellLite%
  oldtop=rowtop:oldleft=colleft
END IF
RETURN

PrintCell:
IF colleft<>0 THEN PUT(colleft,rowtop),CellLite%
row%=PrintRow%+CellRow-StartRow
col%=PrintCol%+((CellCol-StartCol)*CWidth)
IF row%<24 AND row%>4 AND col%<(77-CWidth) AND col%=>PrintCol% THEN
  LOCATE row%,col%:COLOR Blk,Gra
  x$=BSpread$(CellCol,CellRow,1)
  y$=LEFT$(BSpread$(CellCol,CellRow,2),1)
  IF (y$="N" OR y$="F") AND (LEN(x$)>CWidth) THEN
    COLOR Mag:PRINT"*LEN*";STRING$(CWidth-5,"*"):COLOR Blk
  ELSE  
    n=CWidth-LEN(x$):IF n<0 THEN n=0
    IF y$="C" OR y$="" OR LEFT$(x$,1)="*" THEN
      PRINT LEFT$(x$,CWidth);SPACE$(n);
    ELSE
      PRINT USING RIGHT$(Mask$,CWidth);VAL(x$);
    END IF
  END IF
END IF
IF colleft<>0 THEN PUT(colleft,rowtop),CellLite%
RETURN

DoColHdg:
COLOR Blk,Mag:LOCATE 4,6:PRINT SPACE$(70):LOCATE 4,PrintCol%
GET(24,24)-(24+CWidth*8-1,31),CellLite%
EndCol=StartCol+NumCols-1:IF EndCol>MaxCol THEN EndCol=MaxCol
FOR n=StartCol TO EndCol
  PRINT SPC(CWidth-3);ColHdg$(n);":";
NEXT
IF ColLite<>0 THEN LINE(ColLite,17)-STEP(10,5),Blk,bf
n=41-13+(14*StartCol)
LINE(n,17)-STEP(10,5),Yel,bf:ColLite=n
RETURN

DoRowHdg:
COLOR Blk,Mag:row%=5
LINE(24,24)-STEP(15,160),Mag,bf
LINE(600,24)-STEP(15,160),Mag,bf
EndRow=StartRow+18:IF EndRow>MaxRow THEN EndRow=MaxRow
FOR n=StartRow TO EndRow
  LOCATE row%,4:PRINT USING "##";n;
  PRINT SPC(70);:PRINT USING "##";n;
  row%=row%+1
NEXT
IF RowLite<>0 THEN LINE(6,RowLite)-STEP(8,1),Blk,bf
n=30-3+(3*StartRow)
LINE(6,n)-STEP(8,1),Yel,bf:RowLite=n
RETURN

BasicError:
COLOR Mag,Blk:BEEP:ErrSw=1
IF ERR=53 THEN
  LOCATE 2,53:PRINT"File Not Found!"
  RESUME AfterOpen
ELSE
  LOCATE 2,1:PRINT SPACE$(68)
  LOCATE 2,1:PRINT"AmigaBasic Error:";ERR;
END IF
MENU 1,0,1:MENU 2,0,1:MENU 3,0,0:MENU 4,0,0
RESUME WaitForUser

Initialize:
FOR n=1 TO MaxCol:READ ColHdg$(n):NEXT
DATA" A"," B"," C"," D"," E"," F"," G"," H"
DATA" I"," J"," K"," L"," M"," N"," O"," P"
DATA" Q"," R"," S"," T"," U"," V"," W"," X"
DATA" Y"," Z","AA","BB","CC","DD","EE","FF"
DATA"GG","HH","II","JJ","KK","LL","MM","NN"
PALETTE 0,0,0,0:PALETTE 1,0,0,0
PALETTE 2,0,0,0:PALETTE 3,0,0,0
COLOR ,Blk:CLS
LINE(24,24)-STEP(592,160),Mag,bf
LINE(40,32)-STEP(560,152),Gra,bf
LINE(40,16)-STEP(560,7),Gra,b
LINE(4,29)-STEP(12,150),Gra,b
FOR n=54 TO 592 STEP 14:LINE(n,16)-STEP(0,7),Gra:NEXT
FOR n=32 TO 176 STEP 3:LINE(4,n)-STEP(12,0),Gra:NEXT
GET(24,24)-(31,31),IPcursor%
GOSUB DoColHdg:GOSUB DoRowHdg
COLOR Gra,Blk:LOCATE 2,69:PRINT"Changed:"
LINE(608,8)-STEP(8,8),Gra,b
COLOR Yel,Blk:LOCATE 1,1:PRINT"Current Sheet: unnamed"
LOCATE 1,69:PRINT"'BSpread'"
MENU 1,0,1,"Project Mgmt I"
MENU 1,1,1," Load     (L)":MENU 1,2,1," Save     (S)"
MENU 1,3,1," Save As  (A)":MENU 1,4,1," Text File(T)"
MENU 1,5,1," Print    (P)":MENU 1,6,1," Quit     (Q)"
MENU 2, 0,1,"Project Mgmt II"
MENU 2, 1,1," Calculate    (C)":MENU 2, 2,1," Go To Cell...(G)"
MENU 2, 3,1," Clear Sheet     ":MENU 2, 4,1," Reset Sheet     "
MENU 2, 5,1,"  Cell Size 5    ":MENU 2, 6,2,"  Cell Size 10   "
MENU 2, 7,1,"  Cell Size 15   ":MENU 2, 8,1,"  Cell Size 20   "
MENU 2, 9,2,"  Two Decimals   ":MENU 2,10,1,"  No Decimals    "
MENU 2,11,1," Hold 1st Cols   ":MENU 2,12,1," Make a Shell    "
MENU 3,0,0,"Cell Mgmt I"
MENU 3,1,1," Cell Data    (D)":MENU 3,2,1," Cell Formula (F)"
MENU 3,3,1," Zero Cell       ":MENU 3,4,1," Blank Cell      "
MENU 3,5,1," Copy Cell       ":MENU 3,6,1," Move Cell       "
MENU 3,7,1," Propogate Right ":MENU 3,8,1," Propogate Down  "
MENU 3,9,1," Go To Cell...(G)":MENU 3,10,1," Exit         (X)"
MENU 4,0,0,"Cell Mgmt II"
MENU 4,1,1," Zero Column  ":MENU 4,2,1," Zero Row     "
MENU 4,3,1," Blank Column ":MENU 4,4,1," Blank Row    "
MENU 4,5,1," Insert Column":MENU 4,6,1," Insert Row   "
MENU 4,7,1," Remove Column":MENU 4,8,1," Remove Row   "
COLOR Blk,Gra:LOCATE 19,32:PRINT"'Click' to Start"
LOCATE 7,19:PRINT"'BSpread' - an AmigaBasic(tm) Spread Sheet"
LOCATE 9,20:PRINT"Written for 'Amazing Computing' Magazine"
LOCATE 11,39:PRINT"by"
LOCATE 15,22:PRINT"Copyright (c) 1987 by  FelineSystems"
LOCATE 16,31:PRINT"All Rights Reserved"
COLOR Mag,Gra:LOCATE 13,32:PRINT"Bryan  D.  Catley"
LOCATE 21,14:PRINT"2221  Glasgow Road  Alexandria  ";
PRINT"Virginia  22307-1819"
PALETTE 0,0,0,0:PALETTE 1,.75,.75,.75
PALETTE 2,1,0,1:PALETTE 3,1,.8,0
RETURN

SUB GetData (Text$,DataType$,maxlen%) STATIC
SHARED TypeFlag$,IPcursor%()
WHILE INKEY$<>"":WEND
Start=POS(0):Cur=0:xpix=(Start-1)*8:ypix=(CSRLIN-1)*8
ShoText:
IF LEN(Text$)=0 THEN TypeFlag$="N"
n=maxlen%+1-LEN(Text$):IF n<0 THEN n=0
PRINT Text$+SPACE$(n);:LOCATE ,Start
xpix=(Start+Cur-1)*8:PUT(xpix,ypix),IPcursor%
NxtChar:
x$="":LeftPart$="":RightPart$=""
WHILE x$="":x$=INKEY$:WEND
IF x$=CHR$(30)  THEN CurRight ' Right-cursor
IF x$=CHR$(31)  THEN CurLeft  ' Left-cursor
IF x$=CHR$(8)   THEN DelLeft  ' Back-space key
IF x$=CHR$(127) THEN DelRight ' Delete key
IF x$=CHR$(27)  THEN ClrText  ' Escape key
IF x$=CHR$(13)  THEN GetDone  ' Return key
IF DataType$="CHAR"  AND TypeFlag$<>"C" THEN
  IF (x$<CHR$(48) OR x$>CHR$(57)) AND (x$<>".") THEN 
    IF LEN(Text$)>0 OR x$<>"-" THEN TypeFlag$="C"
  END IF
ELSEIF DataType$="INT" THEN
  IF x$<CHR$(48) OR x$>CHR$(57) THEN
    BEEP:GOTO NxtChar
  END IF
END IF
InsertChar:
IF LEN(Text$)=maxlen% THEN BEEP:GOTO NxtChar
IF Cur>0 THEN LeftPart$=MID$(Text$,1,Cur)
IF LEN(Text$)>0 THEN RightPart$=MID$(Text$,Cur+1,LEN(Text$)-LEN(LeftPart$))
Text$=LeftPart$+x$+RightPart$:Cur=Cur+1:GOTO ShoText
CurRight:
IF Cur=LEN(Text$) THEN NxtChar
Cur=Cur+1:GOTO ShoText
CurLeft:
IF Cur=0 THEN NxtChar
Cur=Cur-1:GOTO ShoText
DelLeft:
IF LEN(Text$)=0 OR Cur=0 THEN BEEP:GOTO NxtChar
IF Cur>1 THEN LeftPart$=MID$(Text$,1,Cur-1)
IF LEN(Text$)>Cur THEN RightPart$=MID$(Text$,Cur+1,LEN(Text$)-Cur)
Text$=LeftPart$+RightPart$:Cur=Cur-1:GOTO ShoText
DelRight:
IF LEN(Text$)=0 OR Cur=LEN(Text$) THEN BEEP:GOTO NxtChar
IF Cur>0 THEN LeftPart$=MID$(Text$,1,Cur)
IF Cur+1<LEN(Text$) THEN RightPart$=MID$(Text$,Cur+2,LEN(Text$)-Cur+1)
Text$=LeftPart$+RightPart$:GOTO ShoText
ClrText:
PRINT SPACE$(maxlen%+1);:LOCATE ,Start
Cur=0:Text$="":GOTO ShoText
GetDone:
PUT(xpix,ypix),IPcursor%
END SUB
  
