Hobby Basic, ένας μικρός διερμηνευτής για την κονσόλα των Windows

xqtr

RetroNoob
Joined
3 Ιαν 2021
Μηνύματα
7
Αντιδράσεις
5
Προβολή συνημμένου 245146


Ο διερμηνευτής ξεπέρασε τα 1000 downloads στο φόρουμ του flat assembler. Συγκίνηση on.

Προβολή συνημμένου 245148


To coffee project της ημέρας.
Ένας ANSI viewer γραμμένος στην Hobby BASIC 1.4.3.

Εισαγωγή.

To 16color.rs φιλοξενεί χιλιάδες εικόνες ANSI σε φακέλους χρονολογικά, παράδειγμα ο φάκελος 1990.
Σκοπός μου να γράψω έναν viewer που θα μπορεί να φορτώσει απευθείας τις ANSI εικόνες που βρίσκονται ανεβασμένες στην εν λόγω ιστοσελίδα. Θα μπορεί όμως να λειτουργήσει και offline, φορτώνοντας εικόνες από τον φάκελο ART της Hobby BASIC.

Δοκιμές.

To screenshot είναι από τον κώδικα της σελίδας 1990. Βλέπω πως η σελίδα για την εικόνα AKO.ANS είναι η /PACK/1990/AKO.ANS

Προβολή συνημμένου 245124


Επισκέφτηκα την σελίδα και είδα πως ο απευθείας σύνδεσμος (direct link) της εικόνας είναι ελαφρά διαφορετικός pack/1990/raw/AKO.ANS
Δοκιμάζω τον σύνδεσμο, φορτώνω την εικόνα στην κονσόλα.

Κώδικας:
    screen 80,30,300
    color 0,7
    cls
    ansi "https://16colo.rs/pack/1990/raw/AKO.ANS"
    inkey
    end

Προβολή συνημμένου 245128


Δοκιμάζω τώρα να "κλέψω" όλους τους συνδέσμους τύπου .ANS από την σελίδα 1990 και να τους σώσω σε ένα αρχείο κειμένου. Η σελίδα περιέχει περίπου 440 διπλούς συνδέσμους, άρα κοντά 220 αρχεία .ANS.

Κώδικας:
    src$ = GETSRC("https://16colo.rs/pack/1990/")
    links$ = EXTRACT(src$,".ans")
    if LEN(TRIM(0,links$) > 0)
        save "links.txt",links$
    endif

Προβολή συνημμένου 245130


Το πρόγραμμα.

O Viewer φορτώνει εικόνες από 6 διαφορετικούς φακέλους του 16color.rs. Μπορούν φυσικά να προστεθούν και άλλοι. Μπορεί να τις αναπαράγει τυχαία ή σε σειρά. Περιλαμβάνει μερικό έλεγχο λαθών και κάνει skip στα διπλά ονόματα. Παίζει αυτόματα σαν slideshow ή manual κάνοντας skip στην επόμενη πατώντας κάποιο πλήκτρο (ή το Esc και στις 2 περιτπώσεις). Αποθηκεύει αντίγραφο κάθε εικόνας που φορτώνει στον φάκελο ART της Hobby BASIC. Πριν φορτώσει κάθε εικόνα, πρώτα ελέγχει αν υπάρχει ήδη κατεβασμένη και την φορτώνει από τον σκληρό δίσκο κάνοντας την εναλλαγή αυτόματα από online σε offline. Μπορεί ακόμα να δουλέψει μόνο offline φορτώνοντας τις εικόνες που θα βρει μέσα στον φάκελο ART.

Άφησα το πρόγραμμα να τρέξει κάμποση ώρα σε Windows 10 αλλάζοντας που και που τις παραμέτρους του. Δεν είδα κάποιο πρόβλημα, χωρίς όμως αυτό να αποκλείεται. Θα το ενσωματώσω στα παραδείγματα σε μια επόμενη έκδοση του διερμηνευτή.

Κώδικας:
    rem  AVIEW.BAS
    rem  Hobby Basic Interpreter
    rem  ANSI Text File Viewer (requires an internet connection)

    AUTO_PLAY = 1
    RANDOM_ORDER = 1
    TEXT_SPEED = 2
    OFFLINE = 0

    url$ = "https://16colo.rs/pack/"

    numOfFolders = 6
    dim folder$[numOfFolders] = "1990", "ansipics", "eansis", "1991", "aaa-8991", "ensiart"

    if RANDOM_ORDER then folder$[].SHUFFLE

    view 11
    screen 80,50
    cursor 0,0
    color 0,7
    cls

    ? "ANSI Text File Viewer for Hobby Basic"

    art_path$ = PATH("ART\")

    if CHDIR(art_path$,0) = -1
        ? "Can''t find ART folder"
        pause
        end
    endif

    if OFFLINE
        ? "AVIEW is running offline"
        exec "dir /b *.ans",tmp$
        tmp$ = TRIM(0,tmp$)
        goto split_links
    endif

    index = -1

    next_folder#

    index = (index+1) % numOfFolders
    folder_path$ = url$ + folder$[index] + "/"
    raw_path$ = folder_path$ + "raw/"

    ? "Loading source from ",folder_path$

    src$ = GETSRC(folder_path$)
    if V0 <> 1
        ? "Can''t open URL"
        wait 2000
        goto next_folder
    endif

    tmp$ = TRIM(0,EXTRACT(src$,".ans"))
    if LEN(tmp$) = 0
        ? "Can''t find any .ANS links in folder ",folder$[index]
        wait 2000
        goto next_folder
    endif

    split_links#

    numOfLinks = SPLIT(tmp$,CHR(13),-1)
    if numOfLinks = 0
        ? "Splitting links to array failed"
        wait 2000
        if ~OFFLINE then goto next_folder else pause : end
    endif

    ? numOfLinks," links found with extension .ANS" : wait 500

    dim list$[numOfLinks+1]
    SPLIT(tmp$,CHR(13),list$[])
    if RANDOM_ORDER then list$[].SHUFFLE

    x = 0

    ansi_viewer#

    filename$ = RIGHT(TRIM(0,list$[x]),-1)
    path$ = art_path$ + filename$
    if SIZE(path$) = -1
        if OFFLINE then goto @f
        path$ = raw_path$ + filename$
    endif

    if prev_path$ = path$ then goto @f
    prev_path$ = path$

    color 0,7
    cls
    title path$
    ansi path$,TEXT_SPEED
    if KEY(27) then wait 100 : goto @f
    if AUTO_PLAY then wait 3000 else inkey
    @@# x = x + 1 : if x < numOfLinks then goto ansi_viewer
    if ~OFFLINE then goto next_folder else goto ansi_viewer

Προβολή συνημμένου 245151


Κλείνοντας.

Η Hobby BASIC είναι εξ'ολοκλήρου γραμμένη σε 32-bit assembly και Win32 API. Η εντολή ANSI έχει backend έναν handmade loader γραμμένο σε assembly για να μπορεί να φορτώνει γραφικά ANSI στην κονσόλα, η εντολή EXTRACT που ανακτά τους συνδέσμους από μια ιστοσελίδα το ίδιο.

Αν τρέξετε το πρόγραμμα θα σας προσφέρει πολύ όμορφες και νοσταλγικές στιγμές, οι εικόνες ANSI είναι κομμάτι της ιστορίας και εξέλιξης των υπολογιστών.
Το 16colo.rs, εχει προσβαση και μεσω ftp, οπου έχει τα αρχεια και συμπιεσμενα σε packs, αλλα και ασυμπιεστα (raw). Το λεω πληροφοριακα, για πιθανό επόμενο project :)

Εχω φτιάξει κατι αντίστοιχο σε python για την Mystic BBS. :)

Φοβερη η hobby basic. Μήπως υπάρχει ενδεχόμενο να υπάρξει και σε εκδοση για Linux ;
 

Blue Max

RetroJunkie
Joined
13 Οκτ 2020
Μηνύματα
2.180
Αντιδράσεις
7.010
Γεια σου xqtr,

Μου έδωσες ωραία ιδέα (και ενδιαφέρον task), θα δοκιμάσω μέσω wininet api που το έχω δουλέψει παλιότερα.

Φοβάμαι πως δεν μπορεί να γίνει recompile για Linux, ο κώδικας της είναι γραμμένος από την αρχή σε 32-bit assembly και win32 api χωρίς cross platform βιβλιοθήκες όπως SDL. Ίσως τρέχει στο WINE, δεν το έχω δοκιμάσει
 

Blue Max

RetroJunkie
Joined
13 Οκτ 2020
Μηνύματα
2.180
Αντιδράσεις
7.010
Εχω φτιάξει κατι αντίστοιχο σε python για την Mystic BBS.
Είχα εγκαταστήσει κάποτε δοκιμαστικά την Synchronet BBS από το σπίτι. Ήμουν Administrator και ταυτόχρονα το μοναδικό μέλος. Φανταστικό υπέροχο software. Με έμαθε πολλά πράγματα.

Το 16colo.rs, εχει προσβαση και μεσω ftp, οπου έχει τα αρχεια και συμπιεσμενα σε packs, αλλα και ασυμπιεστα (raw). Το λεω πληροφοριακα, για πιθανό επόμενο project.
Με έβαλες σε σκέψεις φίλε xqtr, έψαξα και βρήκα ένα παλιό παράδειγμα που έχω γράψει σε win32 assembly. Είναι ένα πρόγραμμα που συνδέεται μέσω ftp στον server και κατεβάζει ένα αρχείο. Οπότε σε πρώτη φάση θα δω πως μπορώ να διαβάσω το ftp directory του server με συναρτήσεις WinINet και βλέπω μετά. Έχω μια βάση.

Κώδικας:
        ; WinInet functions example.
        ; The following sample code establish a connection to an FTP server.
        ; It controls how long to wait while connecting to the FTP server in WinInet.
        ; It downloads a file from FTP server to local disk and displays the download progress on Console title.
        ; FTP account username and password required.
    
        ; Written by Picnic
        ; Fasm v1.69.02
        ; Tested on Windows XP

        format PE CONSOLE 4.0
        entry main

        include 'include\win32ax.inc'

        INFINITE = -1
        INTERNET_SERVICE_FTP = 1
        INTERNET_DEFAULT_FTP_PORT = 21
        INTERNET_OPEN_TYPE_DIRECT = 1
        FTP_TRANSFER_TYPE_BINARY = 2
        INTERNET_FLAG_TRANSFER_BINARY = 2
        INTERNET_FLAG_RELOAD = 0x80000000
        INTERNET_FLAG_DONT_CACHE = 0x4000000
        CONTENT_LENGTH = 4096

.data
        szHost TCHAR '',0                   ; xxx.xxx.xxx.xxx
        szUser TCHAR '',0                   ; username
        szPass TCHAR '',0                   ; password
        szRemoteFile TCHAR '',0             ; /music/test.mp3
        szLocalFile TCHAR '',0              ; c:\test.mp3

        lpExitCode dd 0
        lpBytesRead dd 0
        lpCharsWritten dd 0

        dwTimeout dd 0
        dwThreadID dd 0
        dwTotalBytes dd 0

        hStdOut dd 0
        hConnect dd 0
        hOpen dd 0
        hThread dd 0
        hFile dd 0
        hHeap dd 0
        hMem dd 0
        hRequest dd 0

        Buffer db 256 dup ?

.code
main:
        ; ///Returns a handle for the standard output
        invoke GetStdHandle, STD_OUTPUT_HANDLE
        .if eax = -1
            stdcall LastError, <'GetStdHandle() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hStdOut], eax
    

        ;  ///Obtains a handle to the heap of the calling process
        invoke GetProcessHeap
        .if ~eax
            stdcall LastError, <'GetProcessHeap() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hHeap], eax
    

        ; ///Allocates a block of memory from a heap
        invoke HeapAlloc, [hHeap], HEAP_ZERO_MEMORY, CONTENT_LENGTH+1
        .if ~eax
            stdcall LastError, <'HeapAlloc() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hMem], eax
    

        ; ///Initializes use of the WinINet functions
        invoke InternetOpen, NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, 0, 0
        .if ~eax
            stdcall LastError, <'InternetOpen() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hOpen], eax
    

        ; ///Create a connection thread
        invoke CreateThread, NULL, 0, Thread, 0, 0, 0
        mov [hThread], eax

        ; ///Wait for the call to InternetConnect in thread function to complete
        mov [dwTimeout], 10000
        invoke WaitForSingleObject, [hThread], [dwTimeout]
        .if eax = WAIT_TIMEOUT
            stdcall Print, <'Can not connect to FTP server.',13,10>
            .if [hOpen]
                invoke InternetCloseHandle, [hOpen]
                mov [hOpen], 0
            .endif
            ; Wait until the thread exits
            invoke WaitForSingleObject, [hThread], INFINITE
            stdcall Print, <'Thread has exited.',13,10>
            jmp Exit
        .endif

        ; ///The state of the specified thread is signaled
        invoke GetExitCodeThread, [hThread], lpExitCode
        .if ~eax
            stdcall LastError, <'GetExitCodeThread() failed. Error code %d'>
            jmp Exit
        .endif

        invoke CloseHandle, [hThread]

        .if [lpExitCode]
            ; ///Thread function failed
            jmp Exit
        .endif

    
        ; ///Initiates access to a remote file on an FTP server for reading or writing
         invoke FtpOpenFile, [hConnect], szRemoteFile, GENERIC_READ,\
                   INTERNET_FLAG_TRANSFER_BINARY+INTERNET_FLAG_DONT_CACHE+INTERNET_FLAG_RELOAD, 0
        .if ~eax
            stdcall LastError, <'FtpOpenFile() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hRequest], eax
    

        ; ///Creates a new file on disk. The function overwrites the file if it exists
        invoke CreateFile, szLocalFile, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
        .if eax = -1
            stdcall LastError, <'CreateFile() failed. Error code %d'>
            jmp Exit
        .endif

        mov [hFile], eax
    

        stdcall Print, <'Downloading file from FTP server...',13,10>

        ; ///Read from file on the server in a loop chunks of 4Kb each
        .repeat
            invoke InternetReadFile, [hRequest], [hMem], CONTENT_LENGTH, lpBytesRead
            .if eax
                ; ///Write the memory buffer to file on disk
                invoke WriteFile, [hFile], [hMem], [lpBytesRead], lpCharsWritten, 0
                mov ecx, [lpCharsWritten]
                add [dwTotalBytes], ecx
                ; /// Sets the title bar string for the current Console
                invoke wsprintf, Buffer, <'Downloaded %d bytes so far..'>, [dwTotalBytes]
                invoke SetConsoleTitle, Buffer
            .endif
        .until ~[lpBytesRead]

    
        ; /// File download completed
        cinvoke wsprintf, Buffer, <'Download completed. Total %d bytes.',13,10>, [dwTotalBytes]
        stdcall Print, Buffer


    
; ///Release allocated memory, close open handles and exit program
Exit:
        .if [hFile]
            invoke CloseHandle, [hFile]
        .endif
        .if [hMem]
            invoke HeapFree, [hHeap], 0, [hMem]
        .endif
        .if [hRequest]
             invoke InternetCloseHandle, [hRequest]
        .endif
        .if [hOpen]
            invoke InternetCloseHandle, [hOpen]
        .endif
        .if [hConnect]
            invoke InternetCloseHandle, [hConnect]
        .endif

        invoke ExitProcess, 0



proc  Thread
        stdcall Print, <'Trying to establish connection...',13,10>

        ; ///Call InternetConnect to establish a FTP session
        invoke InternetConnect, [hOpen], szHost, INTERNET_DEFAULT_FTP_PORT,\
                  szUser, szPass, INTERNET_SERVICE_FTP, 0, 0
        .if ~eax
            stdcall LastError, <'InternetConnect() failed. Error code %d'>
            mov eax, 1
        .else
            mov [hConnect], eax
            stdcall Print, <'Connection established to FTP server.',13,10>
            xor eax, eax
        .endif
        ret
endp



; ///Prints a character string to Console
proc  Print lpBuffer
        cinvoke wsprintf, Buffer, [lpBuffer]
        invoke WriteConsole, [hStdOut], Buffer, eax, lpCharsWritten, 0
        .if ~eax
            stdcall LastError, <'WriteConsole() failed. Error code %d'>
            jmp Exit
        .endif
        ret
endp



; ///Displays last-error info & code value
proc  LastError lpBuffer
        invoke GetLastError
        cinvoke wsprintf, Buffer, [lpBuffer], eax
        invoke MessageBox, HWND_DESKTOP, Buffer, 0, MB_OK+MB_ICONERROR
        ret
endp



data import

        library kernel32,'KERNEL32.DLL',\
                 user32,'USER32.DLL',\
                 wininet,'WININET.DLL'

        include 'include\api\kernel32.inc'
        include 'include\api\user32.inc'
        include 'include\api\wininet.inc'

end data
1658920065153.png



1658921903768.png

Hobby Basic 1.4.5

Ο διερμηνευτής αναπτύσσεται σε περιβάλλον Windows 7 και 10. Είχα καιρό να τρέξω την Hobby Basic σε Windows XP και δεν πρόσεξα πως ορισμένες αλλαγές που έκανα έχουν σπάσει την συμβατότητα προς τα πίσω.

Συγκεκριμένα, χρησιμοποίησα κάποιες κλήσεις του λειτουργικού που υποστηρίζονται από τα Vista και έπειτα. Δεν το είχα πάρει χαμπάρι και όταν δοκίμασα να τρέξω την Hobby Basic σε Windows XP πήρα μήνυμα λάθους. Το πρόβλημα αφορούσε την εντολή VIEW που στα Windows 7/10 δίνει (μεταξύ άλλων) την δυνατότητα αλλαγής μεγέθους της γραμματοσειράς σε μέγεθος 5x5 pixel στην κονσόλα. Το πρόβλημα διορθώθηκε και πλέον ο διερμηνευτής τρέχει σε Windows 7/10 αλλά και στα XP, που απλά παραβλέπουν αυτό το mode.

Δείτε τι εννοώ τρέχοντας το παράδειγμα CELL που χρησιμοποιεί το mode 5x5. (Ακόμα δύο παραδείγματα χρησιμοποιούν αυτό το mode, το Snake και το 15).

Στα Windows 10 εμφανίζεται σωστά με μέγεθος κελιών 5x5. Τα σχήματα είναι τετράγωνα.
1658923106299.png

Στα Windows XP μένει το default 8x12 και τα σχήματα είναι παραλληλόγραμμα. Οπότε θα χρειαστούν αλλαγές στον κώδικα του παραδείγματος ώστε να υποστηρίζονται και τα 2 λειτουργικά και να φαίνεται σωστά.
1658924482763.png
 

xqtr

RetroNoob
Joined
3 Ιαν 2021
Μηνύματα
7
Αντιδράσεις
5
Είχα εγκαταστήσει κάποτε δοκιμαστικά την Synchronet BBS από το σπίτι. Ήμουν Administrator και ταυτόχρονα το μοναδικό μέλος. Φανταστικό υπέροχο software. Με έμαθε πολλά πράγματα.
Εγω εχω ακομα μια, με mystic bbs. Εννοειτε οτι η κινηση είναι χαλαρή εως ανύπαρκτη, αλλά τουλάχιστον κανω το κεφι μου. Το χω ρίξει και στο modding, οπότε, οποιαδηποτε κινηση προέρχεται απο εκεί ,μιας και έρχονται να δουν, να παρουν ιδεες και να κατεβασουν τα mods.

Αν θες ριξε μάτι ,θα δεις και το mod για το 16colo.rs. Η διευθυνση είναι :

telnet://andr01d.zapto.org:9999


Με έβαλες σε σκέψεις φίλε xqtr, έψαξα και βρήκα ένα παλιό παράδειγμα που έχω γράψει σε win32 assembly. Είναι ένα πρόγραμμα που συνδέεται μέσω ftp στον server και κατεβάζει ένα αρχείο. Οπότε σε πρώτη φάση θα δω πως μπορώ να διαβάσω το ftp directory του server με συναρτήσεις WinINet και βλέπω μετά. Έχω μια βάση.

Δεν το ειχα ποτέ με assembly και windows :)
 

Blue Max

RetroJunkie
Joined
13 Οκτ 2020
Μηνύματα
2.180
Αντιδράσεις
7.010
Εγω εχω ακομα μια, με mystic bbs. Εννοειτε οτι η κινηση είναι χαλαρή εως ανύπαρκτη, αλλά τουλάχιστον κανω το κεφι μου. Το χω ρίξει και στο modding, οπότε, οποιαδηποτε κινηση προέρχεται απο εκεί ,μιας και έρχονται να δουν, να παρουν ιδεες και να κατεβασουν τα mods. Αν θες ριξε μάτι ,θα δεις και το mod για το 16colo.rs. Η διευθυνση είναι : telnet://andr01d.zapto.org:9999 Δεν το ειχα ποτέ με assembly και windows :)

Είμαι μέσα, τέλειο που διατηρείς BBS !

Θα μπω αργά το βραδάκι με την ησυχία μου να την εξερευνήσω. Και βέβαια να κάνω εγγραφή. Είναι 24/7 open?
 
Τελευταία επεξεργασία:

xqtr

RetroNoob
Joined
3 Ιαν 2021
Μηνύματα
7
Αντιδράσεις
5
Είμαι μέσα, τέλειο που διατηρείς BBS !

Θα μπω αργά το βραδάκι με την ησυχία μου να την εξερευνήσω. Και βέβαια να κάνω εγγραφή. Είναι 24/7 open?
Παντα, εκτος και αν εχει φαει κανα κολλημα το rpi, γιατι τα κάνει κατι τετοια. Αλλα γενικά, ειναι 24/7.
 
Μπλουζα