25 June 2023, 23:02 | #1 |
Moderator
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. |
25 June 2023, 23:08 | #2 |
Registered User
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. |
26 June 2023, 09:12 | #3 |
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); } } |
26 June 2023, 19:31 | #4 |
Moderator
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. |
26 June 2023, 20:13 | #5 |
Registered User
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. |
26 June 2023, 20:42 | #6 |
Ex nihilo nihil
Join Date: Oct 2017
Location: CH
Posts: 4,936
|
|
26 June 2023, 21:37 | #7 |
Moderator
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. |
26 June 2023, 21:55 | #8 |
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; } |
26 June 2023, 22:10 | #9 | |
Registered User
Join Date: Jan 2002
Location: Germany
Posts: 7,006
|
Quote:
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. |
|
27 June 2023, 23:00 | #10 |
Moderator
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 |
28 June 2023, 03:45 | #11 |
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; } |
28 June 2023, 09:31 | #12 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,247
|
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.
|
28 June 2023, 23:07 | #13 | |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,629
|
Right now I can cd and list, appreciate this however.
Quote:
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. |
|
29 June 2023, 09:10 | #14 |
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.
|
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 |
|
|