
'             Mutual Fund Performance Program  -- version 1.1
'
'  This program reads user inputted price data for mutual funds (or stocks)
'  and creates a table of such data which can be printed to detect trends
'  and performance history.  It stores the data in a file named by the
'  user -- the default file name is MutualFunds, assumed to be in the
'  current directory.  Funds, dates, & prices may be added, deleted,
'  modified, & resequenced thru mouse-driven menus.  The example MutualFunds
'  file contains weekly price data for several funds.
'  See PrintData: comments to reset printer margins, line width, type style.
'  
'  By Bill Strack, Strongsville, Ohio, CA-AUG/BBS (tele. 216-341-4452).
'
CLEAR,40000&,9000&
DEFINT i-n
DIM f$(39),d$(100),p(100,39),pb(39),pl(39),ib(39)
PRINT "Read source code header for a description of this program.": PRINT
filename$="MutualFunds"
  
GetFile:
ON ERROR GOTO trouble
CALL requester ("Input data filename", filename$, "OK", b%)
OPEN "I",#1,filename$: INPUT #1,nfunds,ndates
PRINT "Reading input data from " filename$  " ... ";
FOR i=1 TO nfunds: INPUT #1,f$(i): NEXT
FOR i=1 TO ndates: INPUT #1,d$(i): NEXT 
FOR i=1 TO ndates: FOR j=1 TO nfunds
INPUT #1, p(i,j): NEXT j,i: CLOSE #1
PRINT "successfully read.": PRINT 
true=1: false=0: incre=false: istart=1
PRINT "Select item from menu using mouse."
MENU 5,0,1,"  Menu choices:"
MENU 5,1,1,"  Add fund"
MENU 5,2,1,"  Delete fund"
MENU 5,3,1,"  Relocate fund"
MENU 5,4,1,"  Add date & prices"
MENU 5,5,1,"  Delete date"
MENU 5,6,1,"  Change fund name"
MENU 5,7,1,"  Change date"
MENU 5,8,1,"  Change price"
MENU 5,9,1,"  Delete file"
MENU 5,10,1,"  Display data - incremental"
MENU 5,11,1,"  Display data"
MENU 5,12,1,"  Print data - incremental"
MENU 5,13,1,"  Print data"
MENU 5,14,1,"  Save data"
MENU 5,15,1,"  Quit"
ON MENU GOSUB MenuCheck
             
idle: 
     MENU ON: GOTO idle
      
MenuCheck:
  MENU 5,item,1: item = MENU(1): MENU 5,item,2
  IF item < 9 THEN update=true: BREAK ON: ON BREAK GOSUB Quit
  ON item GOSUB AddFund,DeleteFund,RelocateFund,AddPrices,DeleteDate,ChangeFundName,ChangeDate,ChangePrice,DeleteFile,DisplayData.incre,DisplayData,PrintData.incre,PrintData,SaveData,Quit
  PRINT "Select another option from the main menu.": PRINT
  GOSUB idle
    
AddFund:   f$ = "\12"
  CALL requester ("Enter NAME of new fund", f$ ,"Add\Cancel", b%)
  IF b% = 1 THEN nfunds = nfunds + 1: f$(nfunds)=f$+SPACE$(12-LEN(f$))
  RETURN
 
DeleteFund:
  GOSUB Fund
  CALL requester ("Delete fund " + f$ + " ?", "", "Yes\No", b%)
  IF b% = 1 THEN   
    FOR i = jfund TO nfunds: f$(i) = f$(i+1)
    FOR j = 1 TO ndates: p(j,i) = p(j,i+1): NEXT j,i
    nfunds = nfunds - 1: PRINT f$ " deleted."
  END IF 
  RETURN 
    
RelocateFund:
  GOSUB Fund: mfund = jfund: PRINT f$ " to be relocated."
  PRINT "Select fund to the right of insertion point:  ";: GOSUB Fund
  IF jfund = mfund THEN PRINT "Null move invalid": RETURN
  f$(39) = f$(mfund): FOR k=1 TO ndates: p(k,39) = p(k,mfund): NEXT
  IF jfund > mfund THEN
    FOR j = mfund+1 TO jfund-1: f$(j-1) = f$(j)
    FOR k = 1 TO ndates: p(k,j-1) = p(k,j): NEXT k,j
    f$(jfund-1) = f$(39): FOR k=1 TO ndates: p(k,jfund-1) = p(k,39): NEXT k
   ELSE
    FOR j = mfund-1 TO jfund STEP -1: f$(j+1) = f$(j)
    FOR k = 1 TO ndates: p(k,j+1) = p(k,j): NEXT k,j
    f$(jfund) = f$(39): FOR k=1 TO ndates: p(k,jfund) = p(k,39): NEXT k
   END IF
  PRINT "Relocation completed."
  RETURN
              
AddPrices:
  lastdate$ = d$(ndates) + "\9"
  message$ = "Last date entry is " + d$(ndates) + "\\Enter NEW Date:"
  CALL requester (message$, lastdate$, "Enter\Cancel", b%)
  IF b% = 1 THEN ndates = ndates + 1: d$(ndates) = lastdate$ ELSE RETURN
  PRINT "Enter Prices:"
  FOR i = 1 TO nfunds
    p$=" \6\real": PRINT f$(i);
    PRINT USING ": Last price=###.##"; p(ndates-1,i);: PRINT  " ";
  CALL requester ("", p$,"", b%)
    IF b% <> 0 THEN
      p(ndates,i) = VAL(p$) 
    ELSE
      d$(ndates) = ""
      FOR j = 1 TO i-1: p(ndates,j) = 0: NEXT 
      ndates = ndates - 1: RETURN
    END IF
  NEXT i: RETURN
    
DeleteDate:
  GOSUB Date 
  CALL requester ("Delete date " + d$ + " ?", "", "Yes\No", b%)
  IF b% = 1 THEN 
    FOR j = jdate TO ndates: d$(j) = d$(j+1)
    FOR i = 1 TO nfunds: p(j,i) = p(j+1,i): NEXT i,j
    ndates = ndates - 1: PRINT d$ " deleted."
  END IF
  RETURN
    
ChangeFundName:
  GOSUB Fund: f$ = f$(jfund)+"\12"
  CALL requester ("Change fund name:", f$, "Change\Cancel", b%)
  IF b% = 1 THEN f$(jfund) = f$ + SPACE$(12-LEN(f$(jfund)))
  RETURN
    
ChangeDate:
  GOSUB Date: d$ = d$(jdate) + "\9
  CALL requester ("Change the date:", d$, "Change\Cancel", b%)
  IF b% = 1 THEN d$(jdate) = d$
  RETURN
    
ChangePrice:
  GOSUB Fund: GOSUB Date: p$ = STR$(p(jdate,jfund)) + "\6\real"
  message$ = "Enter new price for " + f$ + " fund on " + d$
  CALL requester (message$, p$, "Change\Cancel", b%)
  IF b% = 1 THEN p(jdate,jfund) = VAL(p$)
  RETURN
                              
DeleteFile:
  ON ERROR GOTO errorfile: file$ = "\40"
  CALL requester ("Enter filename to delete: ", file$, "Delete\Cancel", b%)
  IF b% = 1 THEN KILL file$
  RETURN
  errorfile:
  IF ERR = 53 THEN PRINT "File " file$ " not found.": RESUME NEXT
        
DisplayData.incre:
  incre = true
DisplayData: 
  message$ = "There are " + STR$(ndates) + " dates in the data table."    
  IF a$ = "P" THEN
    message$ = message$ +  "\How many should be printed? "
    nd$ = "All\5\integer"
    CALL requester (message$, nd$, "Print\Cancel", b%)
    IF nd$ = "All" OR VAL(nd$) <= 0 THEN nd = ndates ELSE nd = VAL(nd$)
  ELSE
    OPEN "O",#2,"SCRN:": jj=8: t=30
    message$ = message$ + "\How many should be displayed? "
    nd$ = "15\5\integer"
    CALL requester (message$, nd$, "Display\Cancel", b%): nd = VAL(nd$)
    IF nd <= 0 THEN nd = 15
  END IF
  IF b% <> 1 THEN End.List
  IF nd > ndates THEN nd = ndates
  IF a$ <> "P" THEN CLS ELSE PRINT "Printing data ... ";
  PRINT #2, TAB(t); "Mutual Fund Performance": j1=1
  loop: PRINT #2, "": j2 = j1 + jj: IF j2 > nfunds THEN j2 = nfunds
  PRINT #2, TAB(9);: FOR j = j1 TO j2: pb(j) = 0!
  PRINT #2, LEFT$(f$(j),6) + "  ";: NEXT j: PRINT #2, ""
  PRINT #2, TAB(9);: FOR j = j1 TO j2
  PRINT #2, RIGHT$(f$(j),6) + "  ";: NEXT j: PRINT #2, ""
  idate = ndates - nd + 1: oldyear$ = ""
  FOR i = idate TO ndates
    year$ = RIGHT$(d$(i),2)
    IF year$ <> oldyear$ THEN
      IF oldyear$ <> "" THEN PRINT #2, "":
      PRINT #2, "19" year$: oldyear$ = year$
    END IF
    PRINT #2, LEFT$(d$(i),6) " ";
    FOR j=j1 TO j2: logi = p(i,j) <> 0! AND pb(j) = 0!
    IF logi THEN pb(j) = p(i,j): pl(j) = pb(j): ib(j) = i
    IF p(i,j) = 0! THEN PRINT #2, SPACE$(8);: GOTO NextFund
    IF incre AND i > ib(j) THEN
           PRINT #2, USING " +##.## "; (p(i,j)/pl(j)-1!)*100!;
           pl(j)=p(i,j)
        ELSE
           PRINT #2, USING " ###.## "; p(i,j);
          END IF
          
      NextFund:          
      NEXT j: PRINT #2, "": NEXT i: PRINT #2, ""
    PRINT #2, " Total ";: FOR j=j1 TO j2: k=ndates
    WHILE p(k,j) = 0! 
      k=k-1
    WEND
    PRINT #2, USING "+###.#% "; (p(k,j)/pb(j)-1!)*100!;
    NEXT j: PRINT #2, ""
    IF a$ <> "P" AND j2 < nfunds THEN
     INPUT "Press RETURN to continue listing funds or S to stop. ", a$
     IF UCASE$(a$) = "S" THEN End.List
    END IF   
    IF j2 < nfunds THEN j1 = j2 + 1: PRINT #2, "": GOTO loop
    
  End.List:
    IF a$ = "P" THEN PRINT #2, CHR$(27)"c": PRINT "completed." 
    CLOSE #2: a$ = "": incre = false: RETURN
    
PrintData.incre:
   incre=true
     
PrintData:
   ' Set print style to elite condensed fine, margins: left-1, right-160
   OPEN "O",#2,"PRT:": PRINT #2, CHR$(27)"[4w";CHR$(27)"[2w"
   PRINT #2, CHR$(27)"[1;160s"
   PRINT #2, "": a$ = "P": jj = 18: t = 60: GOTO DisplayData
                                               
SaveData:
   message$ = "Enter filename to save data:"
   CALL requester (message$, filename$, "Save\Cancel", b%)
   IF b% <>1 THEN RETURN
   PRINT "Storing data in "+filename$+" -- ";
   ON ERROR GOTO trouble
   OPEN "O",#1,filename$
   WRITE #1, nfunds,ndates
   FOR i=1 TO nfunds: WRITE #1, f$(i): NEXT i
   FOR i=1 TO ndates: WRITE #1, d$(i): NEXT i
   FOR i=1 TO ndates: FOR j=1 TO nfunds
   WRITE #1, p(i,j): NEXT j,i: CLOSE #1: update=false
   PRINT "data stored successfully.": RETURN
trouble:
  IF ERR = 53 THEN PRINT "File " filename$ " not found.": RESUME GetFile
  IF ERR = 61 THEN PRINT "save cancelled - disk is full.": RESUME tag
  IF ERR > 49 AND ERR < 75 THEN PRINT "cancelled - error " ERR: RESUME tag
  tag:   ON ERROR GOTO 0: CLOSE #1: RETURN       
                                                                 
Quit:
  IF update THEN
    message$ = "You modified the data set.\Don't you want to save it?"
    CALL requester (message$, "", "Yes\No", b%)
    IF b% = 1 THEN GOSUB SaveData
  END IF                                        
  CLOSE: MENU RESET
  END

Fund:
  PRINT "Select fund from menus."
  MENU 6,0,1,"Funds"
  MENU 7,0,1,"Page funds"
  MENU 7,1,1,"  go forward": MENU 7,2,1,"  go backward"
    IF fstart = 0 THEN fstart = 1: fend=1
    f$ = "": GOSUB Listf : ON MENU GOSUB Fund1
    WHILE f$ = ""
      MENU ON
    WEND: RETURN
  Fund1:
    MEN0 = MENU(0): MEN1 = MENU(1) 
    IF MEN0 = 5 THEN GOTO MenuCheck
       IF MEN0 = 6 THEN
         jfund = MEN1 + fstart-1: f$ = f$(jfund)
          MENU 6,0,0: MENU 7,0,0: RETURN
       ELSE ' men0 = 3
         IF MEN1 = 1 AND nfunds > fend THEN
            fstart = fstart + 19: GOSUB Listf
         ELSEIF MEN1 = 2 AND fstart > 19 THEN
            fstart = fstart - 19: GOSUB Listf
         ELSE
            BEEP: CALL requester ("List request out of range.", "", "",b%)
         END IF
       END IF  
       RETURN
       
       Listf:
         j = 1: fend = fstart + 18
         FOR i = fstart TO fend
         MENU 6,j,1,f$(i): j = j+1: NEXT
         RETURN
         END        
             
Date:
  PRINT "Select date from DATES menu."
  MENU 6,0,1,"Dates"
  MENU 7,0,1,"Page dates"
  MENU 7,1,1,"go forward": MENU 7,2,1,"go backward"
  IF dstart = 0 THEN dstart = 1: dend = 1
  d$ = "": GOSUB Listd : ON MENU GOSUB Date1
  WHILE d$ = ""
    MENU ON
  WEND: RETURN
  
  Date1: MEN0 = MENU(0): MEN1 = MENU(1) 
         IF MEN0 = 5 THEN GOTO MenuCheck
         IF MEN0 = 6 THEN
           jdate = MEN1 + dstart - 1: d$ = d$(jdate)
           MENU 6,0,0: MENU 7,0,0: RETURN
         ELSE ' men0 = 5
           IF MEN1 = 1 AND ndates > dend THEN
             dstart = dstart + 19: GOSUB Listd
           ELSEIF MEN1 = 2 AND dstart > 19 THEN
             dstart = dstart - 19: GOSUB Listd
           ELSE
             BEEP: CALL requester("List request out of range.","","",b%)
           END IF
         END IF  
         RETURN
          
  Listd: j = 1: dend = dstart + 18
         FOR i = dstart TO dend
         MENU 6,j,1,d$(i): j = j+1: NEXT
         RETURN
         END '_____________________________________________________________
                 
  
'   A general purpose requester routine with n-buttons and a string gadget.
'    
'     Message$ = Text displayed at top of requester  ("\" separates lines)
'       InOut$ = String gadget initialized by calling program. 
'                Default length is 40 characters, but may be altered by
'                appending "\MaxLength" to initial value of InOut$.
'                Also, append "\real" or "\integer" to receive a real or 
'                integer value rather than a string, and use a VAL(InOut$)
'                command after your CALL.
' ButtonLabel$ = Button labels, user clicks a button or types first 
'                letter of label to select
'      Button% = Button number clicked by user, returned to caller.
                 Zero is returned IF user presses ESCAPE key.

'   Example usage: 
                
'  Message$ =  "The data must be stored on disk.\What filename should be used?"
'  InOut$   =  "df1:filename"
'  ButtonLabel$ =  "Store\Help\Cancel"
'                  
'  CALL Requester (Message$, InOut$, ButtonLabel$, Button%)
'  PRINT Button%: PRINT InOut$: END

'   By Bill Strack, CA-AUG, Cleveland, OH  (public domain).
 
SUB requester (message$, inout$, ButtonLabel$, button%) STATIC
  real$="R": integer$="I": stringarray$(1)="": type$="string"
  sep$="\"
  
  ' Separate strings into parts
  FOR i=1 TO 10: text$(i)="": button$(i)="": NEXT
  FOR i=1 TO 3:  stringarray$(i)="": NEXT
  CALL StringSep (message$, sep$, text$(), n.texts)
  CALL StringSep (inout$, sep$, stringarray$(), n.strings)
  CALL StringSep (ButtonLabel$, sep$, button$(), n.buttons)
  StringGadget = inout$ <> ""
  IF StringGadget THEN
    defaultstring$ = stringarray$(1): len.string = LEN(defaultstring$)
    IF stringwidth < 0 OR stringwidth > 40 THEN stringwidth = 40
    IF stringwidth < len.string THEN stringwidth = len.string
  END IF
  IF stringarray$(2) = "" THEN stringwidth = 40 ELSE stringwidth = VAL(stringarray$(2))
  IF UCASE$(LEFT$(stringarray$(3),1)) = real$ THEN type$ = real$
  IF UCASE$(LEFT$(stringarray$(3),1)) = integer$ THEN type$ = integer$
  IF n.texts + n.buttons = 0 THEN DisplayString

  ' Determine size of requester window 
  wide = 0: buttonlength = 0
  FOR i = 1 TO n.texts
    lt = LEN(text$(i))+2: IF lt > wide THEN wide = lt: NEXT
  ltext = wide
  FOR i=1 TO n.buttons
    buttonlength = LEN(button$(i))+buttonlength: NEXT
  lb = buttonlength + 6*n.buttons
  IF lb > wide THEN wide = lb
  high = n.texts + 3: IF n.buttons > 0 THEN high = high + 2
  IF StringGadget THEN 
    high = high + 3
    IF stringwidth > wide THEN wide = stringwidth + 4
  END IF
  
  ' Open requester window after checking required dimensions
  delta.w = WINDOW(2)/8-wide: delta.h = WINDOW(3)/8-high
  IF delta.w < 0 THEN PRINT "Requester width" ABS(delta.w) "characters too long."
  IF delta.h < 0 THEN PRINT "Requester height" ABS(delta.h) "lines too long."
  IF delta.w < 0 OR delta.h < 0 THEN PRINT "Stopped due to sizing error.": STOP
  x1 = delta.w\2: y1 = delta.h\2: x2 = x1+wide: y2 = y1+high
  WINDOW 100,,(x1*8,y1*8)-(x2*8,y2*8),0: COLOR 2,1
  LINE (0,0)-(WINDOW(2),WINDOW(3)),1,bf 
  
  ' Display requester text
  IF n.texts <> 0 THEN
    j = 0: FOR i = 1 TO n.texts: j = j+1
    LOCATE j+1,(wide-ltext)\2+2: PRINT text$(i): NEXT
  END IF  
    
  ' Display requester buttons
  IF n.buttons <> 0 THEN
    buttonspace = (wide-buttonlength)\n.buttons
    LOCATE high-1,(wide-buttonlength-(n.buttons-1)*buttonspace)\2+1
    yb1 = (CSRLIN-2)*8: yb2 = yb1+24
    FOR b = 1 TO n.buttons          
    xb1(b) = (POS(o)-2)*8: xb2(b) = xb1(b) + (LEN(button$(b))+2)*8
    LINE (xb1(b),yb1)-(xb2(b),yb2),2,b
    LINE (xb1(b)-1,yb1-1)-(xb2(b)+1,yb2+1),3,b
    PRINT button$(b);: LOCATE ,POS(o)+buttonspace: NEXT
  END IF  
  
  'Branch to user response routines
  IF StringGadget THEN
    GOTO DisplayString
  ELSEIF n.buttons <> 0 THEN
    WHILE 1: GOSUB check.buttons: WEND
  ELSE
    LOCATE n.texts+3,1: PRINT " Press RETURN to continue."
    WHILE 1
      k$ = INKEY$: IF k$ <> "" THEN IF ASC(k$) = 13 THEN exit.requester
    WEND
  END IF
         

  DisplayString:   ' Display input string gadget
  asc.low = 32: asc.high = 125  ' set ASCII limits
  IF n.texts + n.buttons <> 0 THEN
    LOCATE j+3,(wide-stringwidth)\2 + 1: fg=1: bg=0
  ELSE
    fg= 0: bg=1
  END IF
  y = CSRLIN: x = POS(o): maxline = 22: COLOR fg,bg
  IF y > maxline THEN
    SCROLL (0,0)-(WINDOW(2),WINDOW(3)),0,-8*(y-maxline)
    LINE (0,maxline*8)-(WINDOW(2),WINDOW(3)),fg,bf
    y=maxline: LOCATE y
  END IF
  a$ = defaultstring$: strlength = LEN(a$)
  cursor = LEN(a$): IF cursor = stringwidth THEN cursor = cursor - 1 
  LINE (x*8-12,y*8-9)-(8*(x+stringwidth)+3,8*y),bg,bf

  display.line:
    LOCATE y,x: PRINT a$+SPACE$(stringwidth-LEN(a$))
  
  GetNewString:
    IF MOUSE(0) <> 0 AND n.buttons > 0 THEN GOSUB IdentifyButton
    k$ = INKEY$
    count = count-1  ' delete for non-flashing cursor
    IF count <= 0 AND cursor < stringwidth THEN
      x1=8*(x+cursor)-8: y1=y*8-8: x2=x1+8: y2=y1+7
      AREA (x1,y1): AREA (x2,y1): AREA (x2,y2): AREA (x1,y2)
      AREAFILL 1
      count = 100  ' set cursor flash rate
      END IF
    IF k$ = "" THEN GetNewString
    k = ASC(k$): count = 0
    IF k=27 THEN button% = 0: GOTO exit.requester 'escape
    IF k=13 THEN done.getnewstring  ' return key pressed
    IF k >= asc.low AND k <= asc.high AND strlength < stringwidth THEN
      IF type$=real$ OR type$=integer$ THEN  
        IF k<43 OR k>57 OR k=44 OR k=47 THEN GetNewString
        IF (k=43 OR k=45) AND cursor>0 THEN GetNewString
        IF type$=integer$ AND k=46 THEN GetNewString
      END IF
      LOCATE y,x+cursor: strlength = strlength+1
      a$ = LEFT$(a$,cursor)+k$+MID$(a$,cursor+1): PRINT MID$(a$,cursor+1)
      IF strlength < stringwidth THEN cursor = cursor + 1
      GOTO GetNewString
    END IF
    IF k=31 AND cursor > 0 THEN  ' cursor left
      cursor = cursor-1
     ELSEIF k=30 AND cursor < strlength THEN  ' cursor right
       cursor = cursor+1
     ELSEIF k = 127 AND cursor < strlength THEN  ' delete character 
       strlength = strlength-1
       a$ = LEFT$(a$,cursor) + MID$(a$,cursor+2)
     ELSEIF k=8 AND cursor> 0 THEN  ' backspace delete-left
       cursor = cursor-1: strlength = strlength-1
     a$ = LEFT$(a$,cursor) + MID$(a$,cursor+2)
     END IF
    GOTO display.line
  
  done.getnewstring:
    LOCATE y,x: inout$ = a$
    PRINT inout$ + SPACE$(stringwidth-LEN(inout$))
    IF n.buttons = 0 THEN exit.requester
    WHILE 1: GOSUB check.buttons: WEND ' Must exit using buttons  
        
  check.buttons:
    WHILE MOUSE(0) = 0  ' Mouse not pressed, check keyboard for first letters
      k$ = UCASE$(INKEY$)
      FOR b = 1 TO n.buttons
      IF k$ = UCASE$(LEFT$(button$(b),1)) THEN
        button% = b
        GOTO exit.requester
      END IF: NEXT
    WEND
    
  IdentifyButton:  
    xm = MOUSE(1): ym = MOUSE(2) ' Mouse was pressed, find which button 
    IF ym > yb1 AND ym < yb2 THEN
      FOR b = 1 TO n.buttons
      IF xm > xb1(b) AND xm < xb2(b) THEN
        AREA (xb1(b),yb1): AREA (xb1(b),yb2): AREA (xb2(b),yb2): AREA (xb2(b),yb1)
        AREAFILL 1
        WHILE MOUSE(0)<>0            ' Wait for button release
        xm = MOUSE(1): ym = MOUSE(2) ' Check for cancel motion
        IF ym < yb1 OR ym > yb2 OR xm < xb1(b) OR xm > xb2(b) THEN
          AREA (xb1(b),yb1): AREA (xb1(b),yb2): AREA (xb2(b),yb2): AREA (xb2(b),yb1)
          AREAFILL 1: RETURN
        END IF: WEND
      button% = b
      GOTO exit.requester
      END IF: NEXT b
    END IF
    RETURN
    
  exit.requester:
    WINDOW CLOSE 100: COLOR 1,0
END SUB '_______________________________________________________

SUB StringSep (InString$, Separate$, outstring$(1), i)  STATIC
  temp$=InString$: i=0
  WHILE temp$ <> ""
    i=i+1: pointer = INSTR(temp$,Separate$)
    IF pointer <> 0 THEN 
      outstring$(i) = LEFT$(temp$,pointer-1)
      temp$ = RIGHT$(temp$,LEN(temp$)-pointer)
    ELSE
      outstring$(i) = temp$: temp$="" 
    END IF
  WEND     
END SUB  
    
                                                                              
  
