+3 how to detect if a file exist ?

edited June 2010 in Sinclair Basic
Need help.

I am making a generic menu to my compilations over the spectrum +3.
Exist some way programatically to detect if some file exists on the disk ?
we can do a 'cat' but, how to detect if exist programatically sounds hard, if is possible !

thx in advance
Post edited by arfgh on
«1

Comments

  • edited May 2010
    Don't know about BASIC, but in C or assembler you can just read the directory and see what files are there (presumably, if writing a menu system you want to find out what files exist, since there's a near infinite combination of what won't exist :-))

    The +3 manual has details of how to read the directory.
  • edited May 2010
    i examined the +3 manual and i dont found this info that you say. At least no in basic.
  • fogfog
    edited May 2010
    you want something like "boot trilogic" on the c64.. where the filenames + number of files are unknown.

    there are some clued up folks who know about ASM and the +3..

    so it's a case of parsing the filenames and putting em onscreen.

    I did look thru the +3 disk images on here.. and one is MIA , a menu maker..

    but in basic prolly too much of an ask..
  • edited May 2010
    well if exist some little ASM code that i can implement in my generic menu, will be fine.
  • edited May 2010
    You could, if all else fails, use CAT to look for the file...
    CLS 
    CAT "filename"
    IF SCREEN$(0,1) <> "o" THEN PRINT "Found."
    
  • edited May 2010
    wow John Elliott !

    i never thought in this way. The trick works fine, but.. exist some way to hide the cat text result ?

    thx in advance
  • edited May 2010
    If you hide that text, the detection (made with SCREEN$) won't work.
  • edited May 2010
    this is true. Well the idea is good, but, exist some other way to do it ?
  • edited May 2010
    I know (almost) nothing of the +3,
    but if you have the ROM-call to CAT you can see if the value of BC is different on returning to BASIC. If so you can check on that value.
    Your code should make a call to a seperate piece of code that scans the name on stack and then make the call to CAT and returning with the right BC value.

    Something like this

    LET A=USR yourcodeaddress+VAL A$+0 : REM A$ holds namevalue, also string allowed, +0 needed to end return to BASIC OK

    ORG yourcodeaddress
    RST 20; skip ;
    RST 20 ; skip VAL
    CALL scanning
    JP cat-routine

    After running A holds the value of BC if this value is fixed when false then you know when a file is false


    BTW : ANY value can be transferred to BC before returning, so ALL registers are possible as check (even a FLAG)
  • edited May 2010
    Just a guess,

    open a channel for writing, write the CAT to the channel check content of the file, delete file???
    Nothing on screen
  • edited May 2010
    na_th_an wrote: »
    If you hide that text, the detection (made with SCREEN$) won't work.

    How were you thinking of hiding it? With white ink on white paper it should still work, since the screen bytes will still be there for SCREEN$ to read.
  • edited May 2010
    gasman wrote: »
    How were you thinking of hiding it? With white ink on white paper it should still work, since the screen bytes will still be there for SCREEN$ to read.

    True,
    but I think they mean use the screen for other purposes (i.e. a menu that doesn't alter due to reading files)
  • edited May 2010
    Just a guess,

    open a channel for writing, write the CAT to the channel check content of the file, delete file???
    Nothing on screen

    and how is the sintaxis to do this ?


    The reasson to hide the cat result is to not have to repaint the whole menu.
  • edited May 2010
    arfgh wrote: »
    and how is the sintaxis to do this ?


    The reasson to hide the cat result is to not have to repaint the whole menu.

    Talking IF 1 here, don't know if +3 can do thge same.

    By default you write to screen (channel 0 or 2).
    Writing to a printer is done by setting channel 3.

    Other channels can be used to handle filetransfer.

    Something like this (I don't have the manual at hand here):

    OPEN #4;"t";"output"
    CAT #4;"Name"
    CLOSE #4
    OPEN #4;"t";"output"
    INPUT #4;A$
    CLOSE #4
  • edited May 2010
    I thought that it might be possible to open a stream to a disk file, and then CAT #s to it, as can be done with the Microdrive, then the file could be read to get the result of the CAT - but it's not allowed.

    Then I tried using CAT #1 to put the output in the lower screen area (to use SCREEN$ as suggested earlier), but four lines have to be reserved otherwise the screen will scroll, and the output still has to be visible; eg.:
       5 POKE 23659,4: CLS 
       6 PRINT #1;AT 0,0;"-----";AT 
    3,0;"-----"
      10 PRINT AT 0,0;"x": PRINT AT 
    19,0;"y"
      15 PRINT #1;AT 0,0;
      20 CAT #1,"city"
      30 PAUSE 0
      40 GO TO 6
    
    (Line 6 is to open up the bottom four lines, and line 10 is just to show that the screen is not scrolling.)

    Really, the only neat way is to use a bit of machine code. I would use DOS OPEN at 0106h, described on pages 224-6 of the manual.
  • edited May 2010
    yes but, Battle Bunny...
    The way to implement a machine code is obscure to me. Can you show a little example ?

    thx in advance
  • edited May 2010
    Dr BEEP wrote: »
    True,
    but I think they mean use the screen for other purposes (i.e. a menu that doesn't alter due to reading files)

    That's what I meant. I understood "hiding" as "not printing". Like redirecting a linux command to /dev/nul.
  • edited May 2010
    arfgh wrote: »
    The way to implement a machine code is obscure to me. Can you show a little example ?

    I could write something, but it won't be today - maybe this weekend - if I don't fall off the roof while I'm doing some repairs.
  • edited May 2010
    I could write something, but it won't be today - maybe this weekend - if I don't fall off the roof while I'm doing some repairs.

    lol !!!! ok
  • edited May 2010
    This works for me. There should be 203 X characters after the REM, and the REM should be the first line of the program. Lines 10-160 set up the machine code. Lines 1000-1030 give an example of use. The result of the USR call is 1 if the file exists, 0 if it doesn't.
    10 REM XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    20 LET prog = PEEK 23635 + 256 * PEEK 23636
    30 RESTORE
    40 POKE prog + 5, 24: POKE PROG + 6, 118
    50 LET a = prog + 123
    60 READ d: POKE a, d: LET a = a + 1
    70 IF d <> 201 THEN GOTO 60
    80 DATA 255,255,33,0,0,57,197,221,225,80
    90 DATA 89,235,1,120,0,9,249,213,1,253
    100 DATA 127,243,58,92,91,246,7,203,167,50
    110 DATA 92,91,237,121,251,221,229,225,35,35
    120 DATA 1,5,0,17,2,0,205,6,1,1
    130 DATA 0,0,48,8,6,0,205,9,1,1
    140 DATA 1,0,80,89,1,253,127,243,58,92
    150 DATA 91,230,248,203,231,50,92,91,237,121
    160 DATA 225,249,66,75,201
    1000 LET f$="m:example"
    1010 FOR n=1 TO LEN f$: POKE (prog + 6 + n), CODE f$(n): NEXT n
    1020 POKE (prog+6+n), 255
    1030 PRINT USR(prog + 5)
    
    And here's the source of the code. Someone with more understanding than me of ZX BASIC and DEF FN may want to move argument parsing into the machine-code bit, so that the 'exists' check could just be DEF FN e(a$) = USR (prog+5)
    BANKM	equ	5B5Ch
    PORT	equ	7FFDh
    
    base:
    	jr	chk
    	defs	118		;Space for filename parameter and stack
    
    chk:	ld	hl, 0
    	add	hl, sp		;HL = current stack pointer
    	push	bc
    	pop	ix		;IX = entry address
    	ld	d, b
    	ld	e, c		;DE = entry address
    	ex	de, hl		;DE = stack pointer, HL = entry address
    	ld	bc, chk-base
    	add	hl, bc		;HL = address of chk
    	ld	sp, hl		;SP now equals chk
    	push	de		;First word on stack = old SP
    	
    	ld	bc, PORT	;Switch to +3DOS environment
    	di
    	ld	a, (BANKM)
    	or	7
    	res	4, a
    	ld	(BANKM), a
    	out	(c), a
    	ei	
    
    	push	ix
    	pop	hl		;HL = entry address	
    	inc	hl
    	inc	hl		;HL = filename parameter
    
    	ld	bc, 5		;Open file 0, shared-read mode
    	ld	de, 2		;Open file if it exists, error if it does not
    	call	0106h		;DOS OPEN
    	ld	bc, 0
    	jr	nc, exit	;File not found
    
    	ld	b, 0		;Close file 0
    	call	0109h		;DOS CLOSE
    	ld	bc, 1		;File exists
    
    exit:	ld	d, b
    	ld	e, c		;DE = result
    	
    	ld	bc, PORT
    	di
    	ld	a, (BANKM)	;Switch back to 48 BASIC environment
    	and	0F8h
    	set	4, a
    	ld	(BANKM), a
    	out	(c),a
    	pop	hl		;HL = old stack pointer
    	ld	sp, hl
    	ld	b, d
    	ld	c, e		;BC = result
    	ret
    
  • edited May 2010
    OK, once I started to have a look at it I couldn't tear myself away until I got it working. Here's a couple of short m/code routines in a BASIC demo which test for the existence of a +3 disk file. The code is relocatable, but be careful that you don't put it somewhere that conflicts with the addresses it uses. (The example in #21 above is a more concise way of doing it - but this is the first time I've written anything for +3 DOS!)

    The m/code intro & outro segments (lines 30/32 & 35/37) are from the manual; I wrote lines 31 & 36 (plus the BASIC, of course). It uses file number 3 for its test; if that number is already in use then it will return an error; it can be changed to use a different file number (4-15) if it is known that will not be used by anything else (otherwise it would need additional error handling to check if a file number is already in use and then use a different one). The two relevant lines are the LD B,3 before each ROM call.
      10 CLEAR 28658
      20 FOR a=28672 TO 28788: READ p: POKE a,p: NEXT a
      30 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      31 DATA 6,3,14,5,22,0,30,1,33,243,111,205,6,1,1,0,0,48,3,1,1,0
      32 DATA 197,1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,
    193,237,123,0,144,201
      35 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      36 DATA 6,3,205,9,1
      37 DATA 1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,237,
    123,0,144,201
      40 DIM n$(8): DIM s$(3): POKE 23658,8
      50 INPUT "Name=";n$;".";s$: LET f$=n$+"."+s$+CHR$ 255
      60 FOR a=28659 TO 28671: POKE a,CODE f$(a-28658): NEXT a
      70 LET open=USR 28672
      75 LET f$=f$( TO LEN f$-1)
      80 IF NOT open THEN PRINT f$;" does not exist"
      85 IF open THEN PRINT f$;" exists": LET close=USR 28740
     100 GO TO 50
    
  • edited May 2010
    wow.

    as i see you know a lot about the CM !
    what tools to program like this ?
  • edited May 2010
    A text editor and an assembler (for example, pasmo). And patience. Lots.
  • edited May 2010
      10 CLEAR 28658
      20 FOR a=28672 TO 28788: READ p: POKE a,p: NEXT a
      30 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      31 DATA 6,3,14,5,22,0,30,1,33,243,111,205,6,1,1,0,0,48,3,1,1,0
      32 DATA 197,1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,
    193,237,123,0,144,201
      35 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      36 DATA 6,3,205,9,1
      37 DATA 1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,237,
    123,0,144,201
      40 DIM n$(8): DIM s$(3): POKE 23658,8
      50 INPUT "Name=";n$;".";s$: LET f$=n$+"."+s$+CHR$ 255
      60 FOR a=28659 TO 28671: POKE a,CODE f$(a-28658): NEXT a
      70 LET open=USR 28672
      75 LET f$=f$( TO LEN f$-1)
      80 IF NOT open THEN PRINT f$;" does not exist"
      85 IF open THEN PRINT f$;" exists": LET close=USR 28740
     100 GO TO 50
    


    Correct me if I'm wrong, but wouldn't such a low CLEAR leave virtually no space for anything else than the BASIC MC loader? Why not put such code just below the UDG area, and leave the whole RAM for the BASIC program?
  • edited May 2010
    na_th_an wrote: »
    Correct me if I'm wrong, but wouldn't such a low CLEAR leave virtually no space for anything else than the BASIC MC loader? Why not put such code just below the UDG area, and leave the whole RAM for the BASIC program?

    As I mentioned, I'd taken some of the code from an example in the manual, which used ORG $7000 (=28672). As I'd never done any +3 DOS coding before I decided to play safe and keep the same start point - which is why I pointed out that it was relocatable.
  • edited May 2010
    Nice.

    Where to put this code would be tricky as I believe the +3DOS routines do some page ins and outs... Maybe just below $C000 would be a good place.
  • edited May 2010
    na_th_an wrote: »
    Nice.

    Where to put this code would be tricky as I believe the +3DOS routines do some page ins and outs... Maybe just below $C000 would be a good place.

    What about the printerbuffer?
  • edited May 2010
    Dr BEEP wrote: »
    What about the printerbuffer?

    Wouldn't it be one of the worst parts to put it? AFAIK the 128k BASIC uses that area during interrupts, and any game loading code there after the screen needs to be loaded in 48k mode because of this, or it will crash.
  • edited May 2010
    na_th_an wrote: »
    Correct me if I'm wrong, but wouldn't such a low CLEAR leave virtually no space for anything else than the BASIC MC loader? Why not put such code just below the UDG area, and leave the whole RAM for the BASIC program?

    I think i can answer this. the CLEAR Its a bit low, but you still have to reduce the ramtop, cos the second thing the program does is to select page 7 (The dos scratchpad) into $C000-$FFFF, so you need to keep the machine code portion of the program and stack below 49152 or immedately after that the program dissappears from memory :smile:

    This is battle bunny's code modified slightly for the new ramtop:
    (Note, this isnt tested)
      10 CLEAR 48882
      20 FOR a=48896 TO 49012: READ p: POKE a,p: NEXT a
      30 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      31 DATA 6,3,14,5,22,0,30,1,33,243,111,205,6,1,1,0,0,48,3,1,1,0
      32 DATA 197,1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,
    193,237,123,0,144,201
      35 DATA 243,237,115,0,144,1,253,127,58,92,91,203,167,246,7,50,92
    ,91,237,121,49,255,159,251
      36 DATA 6,3,205,9,1
      37 DATA 1,253,127,58,92,91,203,231,230,248,50,92,91,237,121,237,
    123,0,144,201
      40 DIM n$(8): DIM s$(3): POKE 23658,8
      50 INPUT "Name=";n$;".";s$: LET f$=n$+"."+s$+CHR$ 255
      60 FOR a=48883 TO 48895: POKE a,CODE f$(a-48882): NEXT a
      70 LET open=USR 48896
      75 LET f$=f$( TO LEN f$-1)
      80 IF NOT open THEN PRINT f$;" does not exist"
      85 IF open THEN PRINT f$;" exists": LET close=USR 48964
     100 GO TO 50
    

    This could probably be moved up a hundred bytes or so, I just simply moved the numbers from $7000 to $BF00
  • edited May 2010
    guys, what tools you use to program this cm code ?
Sign In or Register to comment.