kategorie: ANSI C, C++
[#1] Rozszerzenie "PATH" dla programu uruchomionego z Workbencha
Chciałem z poziomu programu uruchomionego z Workbencha powiększyć zakres ścieżek dla uruchamianych programów. Tak aby w programie korzystając z takich funkcji jak dos.library/SystemTags(), dos.library/Execute() wywoływać również komendy z zadanego katalogu.

AI zaproponowało mi podmianę listy cli_CommandDir w struct CommandLineInterface którą można dostać dzięki dos.library/Cli() dla aktualnego procesu.
Niestety podmiana na powiększoną listę o nowy Lock w sumie nie pomogła. Dlatego pytanie czy ktoś z Was robił już coś takiego?? I może podzielić się kodem.

Poniżej to co zaproponował ChatGPT4o, co ze zmianami u siebie zaimplementowałem (m.in. ja użyłem od razu funkcji Cli() bez FindTask()):

#include <exec/types.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <proto/dos.h>
#include <proto/exec.h>

void addPath(BPTR newPath) {
    struct Process *proc = (struct Process *)FindTask(NULL);
    struct CommandLineInterface *cli = (struct CommandLineInterface *)BADDR(proc->pr_CLI);
    BPTR *oldPathList, *newPathList;
    LONG oldPathCount = 0;
    LONG i;

    // Get the current path list
    oldPathList = (BPTR *)BADDR(cli->cli_CommandDir);

    // Count the current paths
    while (oldPathList[oldPathCount] != (BPTR)NULL) {
        oldPathCount++;
    }

    // Allocate new path list (old paths + new path + null terminator)
    newPathList = AllocVec(sizeof(BPTR) * (oldPathCount + 2), MEMF_CLEAR);
    if (!newPathList) {
        return; // Memory allocation failed
    }

    // Copy old paths to new path list
    for (i = 0; i < oldPathCount; i++) {
        newPathList[i] = oldPathList[i];
    }

    // Add new path
    newPathList[oldPathCount] = newPath;

    // Update the CLI structure with the new path list
    cli->cli_CommandDir = MKBADDR(newPathList);

    // Free the old path list
    FreeVec(oldPathList);
}

int main() {
    BPTR newPath;

    // Convert the directory string to a lock (e.g., "SYS:C/")
    newPath = Lock("SYS:C/", ACCESS_READ);
    if (newPath) {
        addPath(newPath);

        // Clean up
        UnLock(newPath);
    }

    return 0;
}


Na ten moment użyłem tymczasowego rozwiązania z dos.library/AssignAdd() i zwiększyłem to co widzi Assign C, ale to znowu zmienia globalnie dla systemu co zostaje nawet po wyjściu z programu, a ja chcę tylko w obrębie swojej apki. Dodatkowo AssignAdd() nie zważa na duble i można dodawać w kółko tą samą ścieżkę.

Ostatnia aktualizacja: 29.06.2024 19:20:39 przez Rafael/ARMO
[#2] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #1

Z tym problemem walczyłem w GoShell, program odpalony z CLI przeszukiwał poprawnie wszystkie katalogi z PATH, GoShell odpalony z WB tylko komendy z C: . Kto zna GoShell wie, że odpalanie komend tam to podstawa, więc brak uwzględnienia PATH w konsoli GoShell było dużym problemem.

Co się okazało, był problem właśnie ze strukturą cli w procesie.
Po prostu jest NULLem w procesach odpalanych z ikony.

Ja rozwiązałem to tak, że po wykryciu uruchomienia z WB kopiuję cli WB do procesu, poniżej procedurka z GoShell w AmigaE:

(...)
	IF wbmessage<>NIL	
    
        	->Start z WB, próba przekształcenia w CLI
		wb_into_CLI()
	
	ENDIF
(...)


PROC wb_into_CLI()

	DEF 	
        wbCLI=NIL:PTR TO commandlineinterface,
        wbPort=NIL:PTR TO mp,
        wbProc=NIL:PTR TO process,
        wbMsg=NIL:PTR TO wbstartup
			
	process := FindTask(NIL);
	cli     := BADDR (process.cli)
	
	-> jesli masz cli, to nie mieszaj
	IF cli THEN RETURN;
	
	/* kopiowanie cli Workbencha do procesu */
	wbMsg:=wbmessage
	
	Forbid()
	
		IF (wbPort := wbMsg.message.replyport)
			
			IF ((wbPort.flags AND PF_ACTION) = PA_SIGNAL)
				
				IF (wbProc := wbPort.sigtask)
					
					IF (wbProc.task.ln.type = NT_PROCESS)
						
						IF (wbCLI := BADDR(wbProc.cli))

							process.cli:=wbProc.cli

						ENDIF
					ENDIF
				ENDIF
			ENDIF
		ENDIF
	Permit()
ENDPROC


Nie gwarantuję że to jest dobre rozwiązanie, możliwe że jest bardzo niedobre, ale ma tą zaletę że działa i GoShell uruchomiony z ikonki uwzględnia PATH :)
A skutków ubocznych nie zauważyłem.
[#3] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@vojo, post #2

Możesz też spróbować zastosować swoją procedure addPath bezpośrednio do listy commandDir z wbProc.cli, ale nie wiem czy to zadziała.

Ostatnia aktualizacja: 29.06.2024 23:09:21 przez vojo
[#4] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@vojo, post #2

Dzięki za kod. Przeanalizowałem go i mam takie dwa spostrzeżenia, pytania.
Pierwsze, wydaje mi się że zamiast przechodzić po kolejnych zagłębieniach w strukturach aby dostać proces Workbench, można to samo uzyskać czytelniej za pomocą:
(struct Process *)FindTask("Workbench")

co owszem będzie wolniejsze ... ale chyba bezpieczniejsze i bardziej przenośne.

Druga sprawa dotyczy listy z wbProc.cli (wpProc->pr_CLI) i zwykłego skopiowanie wskaźnika do własnego procesu (co jest w Twoim kodzie: process.cli:=wbProc.cli). Czy czasem jak nasz proces zostanie zamknięty, to nie nastąpi zwolnienie pamięci tej listy (za pomocą jakiegoś FreeVec())? A tym samym zwolnienie pamięci listy w procesie Workbench ... chyba tego byśmy nie chcieli. Bo może spowodować, z czasem niestabilność systemu. A może jest gdzieś opisane, że tak się nie dzieje?


Ostatnia aktualizacja: 01.07.2024 11:59:54 przez Rafael/ARMO
[#5] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #4

Widzę np. w kodzie szukając githubie, w wynikach jest coś takiego:
https://github.com/noname22/NeoDICE/blob/a42cf39734dea9d2336dc0e1b4ee8a60a12be40d/lib/extra/system13.c#L555
I tam lista jest kopiowana przez użycie m.in. DupLock(). I raczej nie natknąłem się na zwykłe "skopiowanie" wskaźnika. Hmmm.

Ostatnia aktualizacja: 01.07.2024 12:07:23 przez Rafael/ARMO
[#6] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #1

Opisywany problem w https://aminet.net/package/dev/src/wbpath
Szczegółowa implementacja jest w wbpath.o bez źródeł, krótkie, więc można zdeassemblować.
Facet napisał książkę amiga guru book jak coś.
[#7] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@cholok, post #6

Z tego co się orientuję, to ścieżkę dla plików wykonywalnych PATH można podać za pomocą parametru NP_Path. Tylko, że trzeba odpalić oddzielny proces. Ale myślę, że uruchomienie oddzielnego procesu to nie problem, zważywszy że i tak chcemy by to był proces z CLI.

Możnaby napisać "stuba", który odpali nasz program z dodanymi ścieżkami.
[#8] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Hexmage960, post #7

Można owszem przekazać NP_Path w przypadku SystemTags() ale dla Execute() już tak nie jest.
Dlatego zależy mi aby Path był ustawiony w obrębie naszego procesu.
[#9] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@cholok, post #6

[#10] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #4

wydaje mi się że zamiast przechodzić po kolejnych zagłębieniach w strukturach aby dostać proces Workbench, można to samo uzyskać czytelniej za pomocą:

(struct Process *)FindTask("Workbench")


Możliwe że tak, trzeba sprawdzić. Jeśli zadziała to faktycznie dużo prostsze.

Druga sprawa dotyczy listy z wbProc.cli (wpProc->pr_CLI) i zwykłego skopiowanie wskaźnika do własnego procesu (co jest w Twoim kodzie: process.cli:=wbProc.cli). Czy czasem jak nasz proces zostanie zamknięty, to nie nastąpi zwolnienie pamięci tej listy


No jeśli program zwalniałby zasoby których nie alokował, to wg mnie byłby to błąd.
E takich rzeczy nie robi, automatycznie zwalnia tylko zasoby jawnie zaalokowane (np. przez funkcje New() czy String()).

Po zastanowieniu - jeśli chcesz modyfikować listę, to faktycznie skopiowałbym całą listę wraz z jej wartościami.
Jeśli potrzebujesz tylko do odczytu - to chyba bezpieczne jest skopiowanie wskaźnika.
CLI procesu Workbencha nie zniknie, póki działa Workbench, a tego nie zamkniesz dopóki działa jakiś program uruchomiony z poziomu Workbencha.

PS. Ciekawe jak to by zadziałało przy "zamiennikach" Workbencha typu Scalos czy Magellan...
edit: chodzi mi o to czy Scalos zwróci coś dla FindTask("Workbench")


Ostatnia aktualizacja: 01.07.2024 14:11:42 przez vojo
[#11] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@vojo, post #10


No jeśli program zwalniałby zasoby których nie alokował, to wg mnie byłby to błąd.
E takich rzeczy nie robi, automatycznie zwalnia tylko zasoby jawnie zaalokowane (np. przez funkcje New() czy String()).


Rozumiem. Tylko kto tworzy proces programu napisanego w E? Wydaje mi się, że tworzy go system/workbench, ładując go .. i on potem jest odpowiada za posprzątanie struct Process, m.in. za to co jest podpięte w pr_CLI, czyli jak !=null to zwolnij listę...Hmmm?? Jestem ciekawy jak to właściwe jest.


PS. Ciekawe jak to by zadziałało przy "zamiennikach" Workbencha typu Scalos czy Magellan...
edit: chodzi mi o to czy Scalos zwróci coś dla FindTask("Workbench")


Myślę, że zgłaszają się jako "Workbench", tak na pewno robi Ambient na MorphOS.
[#12] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #8

Można owszem przekazać NP_Path w przypadku SystemTags() ale dla Execute() już tak nie jest.
Dlatego zależy mi aby Path był ustawiony w obrębie naszego procesu.

Hej, jeśli chodzi o Execute(), to podobnie jak polecenie EXECUTE wykonuje ono skrypt AmigaDOSa. Więc prawdopodobnie możesz użyć polecenia PATH do uzupełnienia ścieżki.

Execute() i tak wymaga polecenia RUN w C:. Przy czym z tego co wiem, to polecenie jest rezydentne w nowszych wersjach Amiga OS.

Zaznaczam, że nie sprawdzałem powyższej metody w praktyce, ale może warto spróbować.
[#13] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Hexmage960, post #12

Hej, jeśli chodzi o Execute(), to podobnie jak polecenie EXECUTE wykonuje ono skrypt AmigaDOSa. Więc prawdopodobnie możesz użyć polecenia PATH do uzupełnienia ścieżki. [...]


Proszę Cię najpierw zweryfikuj co piszesz z tym co jest w dokumentacji: dos.library/Execute
[#14] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #13

Jako pierwszy parametr dla Execute() możesz podać więcej niż jedno polecenie, rozdzielając je znakiem entera, np:

Execute('dir\nassign\nlist',... ) i Execute wykona je po kolei 'dir', 'assign' i 'list', jak skrypt.

Tak że w tym co napisał Hex o Execute() i skryptach jest dużo prawdy.

Ostatnia aktualizacja: 01.07.2024 17:59:26 przez vojo
[#15] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@vojo, post #14

Tak, wywnioskowałem to też z opisu funkcji SystemTagList() (cytat):

Similar to Execute(), but does not read commands from the input
filehandle.
[#16] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@vojo, post #14

To takie naciągnie ... można też dać "Execute("execute skrypt")". Pewnie do SystemTags też można podać kolejne oddzielone \n ... Niemniej dos.libraray/Execute ma zdecydowanie dużo większe możliwości niż komenda DOS Execute. Takie wywoływanie z znacznikami nowej linii to raczej próba obejścia problemu niż jego rozwiązanie. Bo jak już mamy skrypt to lepiej go po prostu wywołać raz w całości niż klejenie linii do Execute(...).

Btw. Przy pracy nad kopiowaniem listy na szybko zrobiłem taką funkcję która wyświetla "path locklist" z procesu Wokbencha. Zamieszczam bo może komuś się przydać:
void PrintPathLockList()
{
    Forbid();
    const struct Task *pWorkbenchTask = (struct Task *)FindTask("Workbench");
    Permit();

    if (!pWorkbenchTask || pWorkbenchTask->tc_Node.ln_Type != NT_PROCESS)
        return;

    const struct Process *pWorkbenchProcess = (struct Process *)pWorkbenchTask;
    const struct CommandLineInterface *pCli = (struct CommandLineInterface *)BADDR(pWorkbenchProcess->pr_CLI);
    if (!pCli)
        return;

    char buffer[256];
    const struct FileLock *pFileLock = (struct FileLock *)BADDR(pCli->cli_CommandDir);
    while (pFileLock)
    {
        printf("lock: 0x%08x", pFileLock->fl_Key);
        if (NameFromLock(pFileLock->fl_Key, buffer, sizeof(buffer)))
            printf(" name: %s\n", buffer);
        else
            printf("\n");
        pFileLock = (struct FileLock *)BADDR(pFileLock->fl_Link);
    }
}


Ostatnia aktualizacja: 01.07.2024 18:33:44 przez Rafael/ARMO
1
[#17] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #16

Jeżeli funkcji Execute() w input podamy plik to po wykonaniu commandString są wykonywane kolejne polecenia z tego pliku. Dlatego też Execute() może być wywołany do wykonania skryptu:

BPTR script = Open("SkryptDOS", MODE_OLDFILE);
Execute("", script, Output());

Być może jest to pewne "obejście" problemu ale w przypadku funkcji Execute() która nie pobiera NP_Path.

Podałem po prostu sposób, który ma swoje wady i zalety.

Jeśli chcemy ręcznie poruszać się po listach DOSowych, to czy jest możliwe robienie tego w bezpieczny sposób za pomocą LockDosList()? Warto sprawdzić i rozważyć.

Można też sprawdzić implementację PATHa.

Ostatnia aktualizacja: 01.07.2024 18:50:52 przez Hexmage960
[#18] Re: Rozszerzenie "PATH" dla programu uruchomionego z Workbencha

@Rafael/ARMO, post #11

Na razie finalnie pozostałem przy rozwiązaniu które zaproponował @vojo, czyli kopiuje wskaźnik pr_CLI z procesu Workbencha.
Z tą różnicą, że przed wyjściem z programu czyszczę ten wskaźnik w swojej strukturze procesu.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem