English Amiga Board


Go Back   English Amiga Board > Coders > Coders. System

 
 
Thread Tools
Old 25 June 2023, 23:02   #1
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
How would you write a CD command replacement?

Current code is as you would expect:

1. Lock
2. Examine to find type (file or dir).
3. CurrentDir().
4. No unlock(), exit back to CLI.

If I unlock it, it will not have the desired effect. If I don't, 24 bytes remain allocated upon program exit.

Is there an OS structure that the AmigaDOS CD command uses, that I could also use, or how does the original CD command do it? Cheers.
Photon is offline  
Old 25 June 2023, 23:08   #2
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,006
new_lock = Lock (new_dir);
old_lock = CurrentDir (new_lock);
UnLock (old_lock);

If you unlock "it" (the new dir's lock), it will crash because you free the memory you told DOS to be the new current dir.

The original CD command also sets the current dir name in the CLI structure. It is used for %s in the prompt.
thomas is offline  
Old 26 June 2023, 09:12   #3
Sani11
Registered User
 
Join Date: Apr 2023
Location: Washington/USA
Posts: 35
As Thomas mentioned, the key is to remember that 'CurrentDir()' returns the old lock, not the new one. So it's crucial to unlock the right lock to avoid any issues.

To add, if you're trying to replicate the original CD command, you might want to update the current directory name in the CLI structure as well, something like this:

Code:
BPTR old_lock, new_lock;
struct CommandLineInterface *cli = Cli();

new_lock = Lock(new_dir, ACCESS_READ);
if (new_lock) {
    old_lock = CurrentDir(new_lock);
    UnLock(old_lock);

    if (cli) {
        if (cli->cli_SetName)
            FreeVec(cli->cli_SetName);
        cli->cli_SetName = BADDR(new_lock);
    }
}
This will also update the '%s' in the prompt like the original CD command. Hope this helps, and happy coding!
Sani11 is offline  
Old 26 June 2023, 19:31   #4
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
Now, no bytes are leaked. Thank you Thomas and Sani11 for answers.

I'd like to implement Sani's follow-up, but:
1. Passing the longword at Cli() result+4 to FreeVec, Exec causes a Recoverable Alert $0100000f on 3.1.
2. Replacing that longword with the new_lock value has no effect (as in, "prompt %s>" is typed before executing the CD command, and the prompt doesn't change as for AmigaDOS cd command).

I'm unsure of the 3 mixed-up types here (at least that's my first thought from documentation).

I've not worked extensively with BCPL types before. I'm assuming BSTR is a byte pointer to a zero-terminated string, a dos.library lock is not but a custom structure, and that a vector is a structure containing at least an address and a length, not just an address.

Last edited by Photon; 26 June 2023 at 20:03.
Photon is offline  
Old 26 June 2023, 20:13   #5
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,006
That part of Sani11's code is completely wrong.

BCPL works on longwords everywhere. A BCPL pointer (BPTR) is the number of longwords from 0 to the actual address. In order to work with such a pointer in C you have to multiply it by 4. That's what the BADDR() macro does.

In the same way, to make a BPTR from a C pointer, you have to divide it by 4. That's what the MKBADDR() macro does.

A BSTR is a BCPL pointer to a BCPL string. A BCPL string is an array of bytes with the first byte being the length of the string. (That's why DOS cannot handle strings longer than 255 characters). It is not 0-terminated. Do not expect it to be terminated, it is not!

The idea is:
- free the memory of the old string
- allocate memory for a new string
- use NameFromLock() to get the directory name to be put into the new string

I am not sure if AllocVec/FreeVec can be used in this case. As everything in DOS is backwards-compatible, I would assume that you have to use AllocMem/FreeMem.
thomas is offline  
Old 26 June 2023, 20:42   #6
malko
Ex nihilo nihil
 
malko's Avatar
 
Join Date: Oct 2017
Location: CH
Posts: 4,936
Quote:
Originally Posted by thomas View Post
That part of Sani11's code is completely wrong. [...]
ChatGPT code ?
malko is offline  
Old 26 June 2023, 21:37   #7
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
Thanks Thomas, this explains a few things (like return values being seemingly in the wrong memory area).

So possibly, a lock is a BPTR to a lock structure, and BSTR is a BPTR to a string that you describe (which is actually quite familiar)?

With this information I'll try to make it work and report back if it does.
Photon is offline  
Old 26 June 2023, 21:55   #8
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
Hmm, it doesn't seem to work though. And every reference I've found on the internet is overwriting the cli->SetName in place!!!

for example
https://groups.google.com/g/comp.sys...m/MbU48xOVJFEJ

http://www.columbia.edu/kermit/ftp/o...mit4f/ckiutl.c function update_dirname


Here is my attempt (which does not work), with a newly allocated BSTR

Code:
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>

#include <stdio.h>

#define BUFLEN 256

int main(int argc, char **argv)
{
    BPTR old_lock, new_lock;

    struct Process *pr = (struct Process *)FindTask(NULL);
    struct CommandLineInterface *cli =
        (struct CommandLineInterface *)(BADDR(pr->pr_CLI));
    char buffer[BUFLEN];

    new_lock = Lock(argv[1], ACCESS_READ);
    if (new_lock)
    {
        old_lock = CurrentDir(new_lock);
        UnLock(old_lock);

        if (cli)
        {
            if (cli->cli_SetName)
            {
                int len = *((char *)BADDR(cli->cli_SetName));
                FreeMem(BADDR(cli->cli_SetName), len + 1);
            }
            if (NameFromLock(new_lock, buffer + 1, BUFLEN))
            {
                buffer[0] = (BYTE)strlen(buffer + 1);
                printf("Buffer: %s\nLen: %d\n", buffer + 1, buffer[0]);
                char *realbuf = AllocMem(buffer[0] + 1, MEMF_ANY);
                memcpy(realbuf, buffer, buffer[0] + 1);
                cli->cli_SetName = (BSTR)MKBADDR(realbuf);
                Printf("Printf %b\n", cli->cli_SetName);
            }
        }
    }
    return 0;
}
alkis is offline  
Old 26 June 2023, 22:10   #9
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,006
Quote:
Originally Posted by alkis View Post
every reference I've found on the internet is overwriting the cli->SetName in place!!!
Maybe I should be more precise: it was Sani11's idea to free and re-allocate the memory buffer

The idea looked ok at first sight. But given the fact that a BCPL string can never exceed 255 characters, it might be safe to assume that the area pointed to by cli_SetName is 256 bytes and can just be used without re-allocation.

It could also be that cli_SetName is just a copy of another pointer and must not be changed. Thus it's probably a good idea to just overwrite the contents, not the pointer itself.
thomas is offline  
Old 27 June 2023, 23:00   #10
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
Well, I apparently don't check. It seems Cli() was not added to dos.library until KS2.0, and I want to support 1.3-3.1.

As feedback, I tried to replace the current dir name (and the prompt, which defaults to "%N> "), either by replacing the BSTR pointer or the text. This has no effect (tested on KS3.1). Probably SetPrompt() and SetCurrentDirName() should be used - on KS2.0+.

Probably on KS1.3, the CD command uses previously allocated internal memory areas which are not (easily) exposed. Perhaps 1.3 uses the same Cli structure, the pointer to which can be obtained from the DosBase structure, but 1.3 would then have to obey changes within it to set directory name and prompt (unlike 2.0+).

https://wiki.amigaos.net/wiki/AmigaD...rary_Structure
Photon is offline  
Old 28 June 2023, 03:45   #11
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
This is lightly tested but seems to work in 1.3 and 3.1

Code:
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>

#include <stdio.h>

#define BUFLEN 64
int NameFromLock13(BPTR baselock, char *buffer, int bufmax);

int main(int argc, char **argv)
{
    struct FileInfoBlock __aligned fib;
    BPTR old_lock, new_lock;

    struct Process *pr = (struct Process *)FindTask(NULL);
    struct CommandLineInterface *cli =
        (struct CommandLineInterface *)(BADDR(pr->pr_CLI));
    char *buffer;

    if (argc != 2)
        return 5;

    new_lock = Lock(argv[1], ACCESS_READ);
    if (cli && new_lock && Examine(new_lock, &fib) && fib.fib_DirEntryType > 0)
    {
        old_lock = CurrentDir(new_lock);
        UnLock(old_lock);

        buffer = BADDR(cli->cli_SetName);
        // if (NameFromLock(new_lock, buffer + 1, BUFLEN))
        //  replaced for 1.3
        if (NameFromLock13(new_lock, buffer + 1, BUFLEN))
        {
            buffer[0] = (BYTE)strlen(buffer + 1);
        }
    }
    return 0;
}

int NameFromLock13(BPTR baselock, char *buffer, int bufmax)
{
    char *loc = buffer + bufmax - 1; /* Last usable location */
    BPTR lock, newlock;
    struct FileInfoBlock __aligned fib;
    int len;

    *loc = '\0'; /* trailing NUL */
    lock = baselock;
    while (lock)
    {
        Examine(lock, &fib);
        newlock = ParentDir(lock);
        if (lock != baselock)
            UnLock(lock);
        lock = newlock;
        len = strlen(fib.fib_FileName);
        if (bufmax <= len)
        {
            strcpy(buffer, loc);
            return FALSE;
        }
        if (fib.fib_DirEntryType > 0) /* Is it a dir ? */
        {
            --loc;
            *loc = (lock) ? '/' : ':';
        }
        loc -= len;
        strncpy(loc, fib.fib_FileName, (size_t)len);
        bufmax -= len + 1;
    }
    strcpy(buffer, loc);
    return TRUE;
}
alkis is offline  
Old 28 June 2023, 09:31   #12
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,247
Quote:
Originally Posted by Photon View Post
As feedback, I tried to replace the current dir name (and the prompt, which defaults to "%N> "), either by replacing the BSTR pointer or the text. This has no effect (tested on KS3.1). Probably SetPrompt() and SetCurrentDirName() should be used - on KS2.0+.
Actually, the built-in "CD" should be used. (-; Anyhow, the directory name buffer is just statically allocated, and its BPTR is placed in the CLI structure. Do not re-allocate this buffer, this is part of the dos.library (or shell) to maintain. There is otherwise no magic going on, the handling of the prompt and CD did not change.
Thomas Richter is offline  
Old 28 June 2023, 23:07   #13
Photon
Moderator
 
Photon's Avatar
 
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
Quote:
Originally Posted by alkis View Post
This is lightly tested but seems to work in 1.3 and 3.1
Right now I can cd and list, appreciate this however.

Quote:
Originally Posted by Thomas Richter View Post
Actually, the built-in "CD" should be used. (-; Anyhow, the directory name buffer is just statically allocated, and its BPTR is placed in the CLI structure. Do not re-allocate this buffer, this is part of the dos.library (or shell) to maintain. There is otherwise no magic going on, the handling of the prompt and CD did not change.
IDK what you mean. I already tested that modifying the struct returned by Cli() affects nothing on 3.1.

Since you brought up "built-in", I have to bring up DOS commands are not in Amiga OS. Hey ho, all is good, topic remains as stated.

From a design perspective, the goal is to be able to explore files on a booted disk without spending 20-30K of it (and every booted disk) to do it. It's an attractive goal.
Photon is offline  
Old 29 June 2023, 09:10   #14
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,247
As said, *do not* modify the pointer in the CLI structure. Just the array it points to. It is a BPTR to the BSTR, so the first element is the length.
Thomas Richter is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Write HardFile To SD/CD/HD AMIGASYSTEM support.OtherUAE 7 07 March 2018 22:42
CD-Write Octopus66 request.Apps 12 07 May 2017 23:02
Replacement CD-ROM for CDTV? StevenJGore support.Hardware 11 21 February 2017 10:50
read/write Cd error help amigang support.WinUAE 1 30 July 2010 22:57
CD Read Write Errors Stom support.WinUAE 2 07 June 2002 18:46

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 16:27.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.10294 seconds with 13 queries