QB64.org Forum

Active Forums => Programs => Topic started by: Sanmayce on January 20, 2021, 05:18:19 am

Title: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 20, 2021, 05:18:19 am
 

Hi,
an oldboy being a big fan of QB 2.0, QB 4.0, QB 4.5 and QBX 7.1 here.

So glad that few days ago found QB64, a dream relived, as I see it.
Many thanks to QB64 team, really you gladdened my eyes, the IDE feels as it should, the stand alone executable is seconds away, so convenient, bravo!

25 years ago I wrote some original tools in QB45 + MASM functions, loved that pair, thought that experience was past long gone, now I see I haven't killed the quickening within.

Last night wrote my first QB64 program, gladly sharing it here , my wish is to continue to enrich its functionality...
To community, feel free to point out the stupid parts you see in it.

My idea is to invoke my [searching] console tools (written in C) via this "GUI SHELL" and showing their output in this QB64 window...

Code: QB64: [Select]
  1. ' DragDropWheel.bas
  2. ' written in QB64 v1.4 by Kaze, 2021-Jan-20
  3.  
  4. _TITLE "DragDropWheel"
  5. CONST RSHIFT& = 100303
  6. CONST LSHIFT& = 100304
  7.  
  8. XdimCOL = 160
  9. YdimROW = 44 ' ensure old laptops with 768pixels vertical will hold the whole window
  10. IF high& > 1000 THEN YdimROW = 60
  11. handle& = _NEWIMAGE(XdimCOL, YdimROW, 0)
  12. SCREEN handle&
  13.  
  14. ' Either one must be uncommented:
  15. '_AUTODISPLAY 'no need of refreshing
  16.  
  17. _ACCEPTFILEDROP 'enables drag/drop functionality
  18.  
  19. IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  20.     COLOR 9, 0
  21.     COLOR 3, 0
  22.  
  23. PRINT "Current working directory path: "; CHR$(34); _CWD$; CHR$(34)
  24. PRINT "User's program calling path: "; CHR$(34); _STARTDIR$; CHR$(34)
  25. PRINT "Command line parameters sent when a program is started: "; CHR$(34); COMMAND$; CHR$(34)
  26. PRINT "_OS$="; _OS$
  27.  
  28. 'Y = CSRLIN 'save the row
  29. 'X = POS(0) 'save the column
  30.  
  31. filecount% = 0
  32. REDIM FileArray$(1000000) 'create dynamic array: 3880000 alocates 532MB - bigger values need 570+MB and give "Out Of Memory"
  33.  
  34. FOR i = 1 TO YdimROW
  35.     FileArray$(i) = ""
  36.  
  37. PRINT "Drag files from a folder and drop them in this window..."
  38. 'REDIM FileArray$(filecount%)
  39.  
  40. 'pressakey$ = INPUT$(1)
  41.  
  42. a$ = ""
  43.         'FOR i = 1 TO _TOTALDROPPEDFILES
  44.         'a$ = _DROPPEDFILE(i)
  45.         a$ = _DROPPEDFILE(1)
  46.         'NEXT'
  47.         _FINISHDROP 'If _FINISHDROP isn't called here then _TOTALDROPPEDFILES never gets reset.
  48.         '    ELSE
  49.         '        a$ = "Scroller.$$$"
  50.         '       SHELL _HIDE "DIR /B *.* > Scroller.$$$"
  51.     END IF
  52.  
  53.     IF _FILEEXISTS(a$) THEN
  54.         OPEN a$ FOR INPUT AS #1
  55.         DO UNTIL EOF(1)
  56.             LINE INPUT #1, filename$ 'read entire text file line
  57.             filecount% = filecount% + 1
  58.             FileArray$(filecount%) = filename$
  59.         LOOP
  60.         CLOSE #1
  61.     END IF
  62.     _LIMIT 30
  63. LOOP WHILE a$ = ""
  64.  
  65. 'PRINT "Printing filenames in current directory... ";: PRINT LTRIM$(STR$(filecount%))
  66.  
  67. FOR i = 1 TO YdimROW 'filecount%
  68.     IF LEN(FileArray$(i)) >= XdimCOL THEN
  69.         FileArray$(i) = MID$(FileArray$(i), 1, XdimCOL)
  70.     ELSE
  71.         FileArray$(i) = FileArray$(i) + SPACE$(XdimCOL - LEN(FileArray$(i)))
  72.     END IF
  73.     LOCATE i, 1: PRINT FileArray$(i);
  74.  
  75. LOCATE 1, 1
  76. crx = POS(0)
  77. cry = CSRLIN
  78. crxOLD = crx
  79. cryOLD = cry
  80. LOCATE cry, crx, 1, 30, 31
  81.  
  82. IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  83.     COLOR 8, 0
  84.     COLOR 0, 3
  85. PRINT FileArray$(cry);
  86.     IF _KEYDOWN(LSHIFT&) THEN PLAY "L8V2ff-"
  87.     IF _KEYDOWN(RSHIFT&) THEN PLAY "L8V2a-c-"
  88.     'LOCATE cry, crx, 1, 30, 31
  89.     key$ = INKEY$
  90.     'DO: a$ = INKEY$: LOOP UNTIL a$ <> "" ' prevent ASC empty string read error
  91.     IF key$ <> "" THEN
  92.         code% = ASC(key$):
  93.         IF code% THEN ' ASC returns any value greater than 0
  94.             SELECT CASE ASC(key$)
  95.                 CASE 65 TO 97: 'PRINT key$;
  96.                 CASE ASC("a") TO ASC("z"): 'PRINT key$;
  97.                 CASE 27: COLOR 7, 0: SYSTEM 'END
  98.             END SELECT
  99.         ELSE
  100.             SELECT CASE ASC(key$, 2)
  101.                 CASE 72: IF cry > 1 THEN cry = cry - 1 'up
  102.                 CASE 80: IF cry < YdimROW THEN cry = cry + 1 'down
  103.                 CASE 75: IF crx > 1 THEN crx = crx - 1 'left
  104.                 CASE 77: IF crx < XdimCOL THEN crx = crx + 1 'right
  105.             END SELECT
  106.         END IF
  107.     END IF
  108.     IF cryOLD <> cry THEN
  109.         'LOCATE cryOLD, crx, 1, 30, 31: COLOR 3, 0: PRINT FileArray$(cryOLD);
  110.         LOCATE cryOLD, 1, 1, 30, 31
  111.         IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  112.             COLOR 9, 0
  113.         ELSE
  114.             COLOR 3, 0
  115.         END IF
  116.         PRINT FileArray$(cryOLD);
  117.         cryOLD = cry
  118.     ELSE 'it 'cry' could be changed by Mouse Wheel too, check it
  119.         AsIfItIsINKEY% = _MOUSEINPUT '      Check the mouse status
  120.         IF _MOUSEWHEEL = 1 THEN ' as if Down
  121.             IF cry < YdimROW THEN cry = cry + 1 'down
  122.         END IF
  123.         IF _MOUSEWHEEL = -1 THEN ' as if Up
  124.             IF cry > 1 THEN cry = cry - 1 'up
  125.         END IF
  126.     END IF
  127.     'LOCATE cry, crx, 1, 30, 31: COLOR 0, 3: PRINT FileArray$(cry);
  128.     LOCATE cry, 1, 1, 30, 31
  129.     IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  130.         COLOR 8, 0
  131.     ELSE
  132.         COLOR 0, 3
  133.     END IF
  134.  
  135.     PRINT FileArray$(cry);
  136.     _DISPLAY
  137.     'DO WHILE INKEY$ <> "": LOOP ' have to clear the keyboard buffer
  138.     '_LIMIT 30 'commented because the wheel up/down was not working?!
  139.  
  140.  

 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on January 20, 2021, 06:15:46 am
A better solution for mouse handling:

Code: QB64: [Select]
  1.   DO
  2.        CLS
  3.        WHILE _MOUSEINPUT
  4.              scroll = scroll + _MOUSEWHEEL
  5.        WEND
  6.        IF scroll < 0 THEN scroll = 100
  7.        IF scroll > 100 THEN scroll = 0
  8.        PRINT scroll
  9.        _DISPLAY
  10.        _LIMIT 30
  11.    LOOP UNTIL _KEYHIT = 27
  12.  

In the above, my mousewheel will scroll from 0 to 100, and wrap from high to low, without any lag or drag on performance.  For your needs, just substitute your (max line count - number of lines on screen) instead of 100, and scroll should be the line you’d start printing to the screen.  (Assuming no word wrap occurs, of course.)
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: FellippeHeitor on January 20, 2021, 11:11:03 am
Welcome aboard, @Sanmayce! Cool to see you're already getting it going with several modern keywords as well! Looking forward to your future contributions.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 20, 2021, 11:28:27 am
@Steve,

Don't forget to tell him about NOT adding other mouse commands, like _MOUSEBUTTON(1), etc. inside that loop, but rather to add them outside and after it terminates.

Pete
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 20, 2021, 11:42:22 am
@FellippeHeitor

Hey Fell, looks like you've got another old-TIMER in the fold. We're getting to be a pretty big group around here. If this keeps up, you'll have to offer us a senior discount. Since this is an open source project, that means you'll owe us money! :D

@Sanmayce

Welcome. I like GUI the stuff, too. I've got a project I'm working on currently, posted over at the QBasic forum. Since you're an old-timer, do you remember that forum? Network54 used to host it. Now it's on Tapatalk. Mallord was the first admin, followed by Mac, and Mac turned it over to me, when he passed away in 2008. Anyway, I'm just curious if you recall it, or Pete's QBasic forum, or any of the others back in the day.

Pete
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on January 20, 2021, 12:04:18 pm
@Sanmayce  welcome! I did not know or see demo of _ACCEPTFILEDROP, thanks! Hopefully we can drop in more than one file eventually.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: FellippeHeitor on January 20, 2021, 12:06:45 pm
Yeah, the whole drag/drop suite of commands is getting old already at this point (they were introduced in v1.3) - and yes, you can handle multiple files. Click the keywords below to read more about them:

Code: QB64: [Select]
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 20, 2021, 12:09:58 pm
@bplus

This is a neat addition to the language. I have it in V. 1.3. Back in the day, I had to make my own routine. I dragged a copy of FreeBASIC in it once, by mistake, which created a memory incident. It returned an "Are you out of your mind," error.

Pete
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on January 20, 2021, 12:14:18 pm
@bplus

This is a neat addition to the language. I have it in V. 1.3. Back in the day, I had to make my own routine. I dragged a copy of FreeBASIC in it once, by mistake, which created a memory incident. It returned an "Are you out of your mind," error.

Pete

LOL

Yeah I am seeing this as nice substitute for expensive File Dialog! Would like to see demo of handling multiple files, something to play around with for sure!
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: FellippeHeitor on January 20, 2021, 12:14:56 pm
All in the wiki 😉
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: NOVARSEG on January 20, 2021, 10:50:02 pm
Hi Sanmayce

I tried uncommenting the _LIMIT 30 in your code and it does work but it takes forever (just over 2 minutes) for the wheel to update. That is because there is usually tons of mouse x, y position data in the mouse buffer and LIMIT 30 is too slow to process that data. The wheel data is usually at the end of the x, y position data.

Actually the wheel and position data can be intermixed but when the wheel data is at the end of a large amount of position data,  there is this apparent delay in wheel update.

Even with no mouse position data in the buffer, the wheel response is pretty slow with _LIMIT 30

So try _LIMIT 500
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 20, 2021, 11:38:27 pm
Thank you very much guys, having found QB64 and this community/forum gladdened me, bigtime, for two days I feel as if being in happy old times.

My passion is text processing of huge English text, searching, decompressing, indexing them in order to ease quick n-gram requests i.e. to have spell-checkers, and ... phrase-checkers of English texts under the fingers.
C and QB64 are so instrumental in that regard, eager to pursue this dream of mine...

@SMcNeill

Thank you Steve, not only for you suggestion (which prompted me to revise my first pseudo-buggy attempt) but for useful sharings of yours. Showing different scenarios being handled is the best way to help others, such snippets/etudes are instrumental for sure.
The idea is to write a simplistic viewer working with the "heap" by using the QB64's memaloc()-like new functions instead of array of NON-FIXED length strings. Wanna try how the scroller behaves with 1GB file text loaded in RAM.
Your MEMUSAGE tool is cool, MUCH NEEDED, accessing Windows APIs has to be explored as you did (I have no experience in using APIs), some functionality has to be "stolen" from DLLs, wanna write first that exact viewer...

Welcome aboard, @Sanmayce! Cool to see you're already getting it going with several modern keywords as well! Looking forward to your future contributions.

Thank you man! Surely in future will share all my code along with my feedback.

Fellippe, I bend a knee before you. resurrecting QB is just awesome! Many beers I owe you.
As far as I recall, only said this once back, to another developer - a true master of coding compression in C.

Really enliked your presentation about 'InForm', please consider doing such reviews more often, at least not stopping them:

https://www.youtube.com/watch?v=S3D4zEUQ0sQ&list=PLD7-OthpyuXNbrB12Cl5_3vBpRtvN7CA8&index=5 (https://www.youtube.com/watch?v=S3D4zEUQ0sQ&list=PLD7-OthpyuXNbrB12Cl5_3vBpRtvN7CA8&index=5)

Nice work with this Form Designer, wanna try it after some weeks, my tempo is slow but ongoing, a real fan here, that is.

My expertise is amateurish, I have been playing with search algorithms, and Windows (as far as Form Designer goes) not wanting to go into C++ and APIs, just played for a month or so with VisualStudio (ATL project) in order to make my GUI shell for invoking my console executables written in C. Just assigned some SHELL _HIDE like instance behind each button. The result: www.sanmayce.com/Downloads/_GW_(Bare-Minimum_2018-Mar-16).zip (http://www.sanmayce.com/Downloads/_GW_(Bare-Minimum_2018-Mar-16).zip)
It looks very nice on Windows XP, and so ugly with the new Windows 7+ schemes, therefore for more than 3 years I abandoned it, shame.

  [ Invalid Attachment ]  
  [ Invalid Attachment ]  
  [ Invalid Attachment ]  

Similar thing is what I want to write with QB64 - a simplistic text editor sensitive to all my textual processing tools - my textual madness is deep and constant, my wish is in the near future to have phrase sensitive functionality (giving statistics about English language n-grams generated by external tools) while hovering over this text window, both with cursor and mouse.
Simply, I am hell bent on making and sharing one 100% FREE lightweight (and thanks to QB64 portability) text assistant/sidekick/application in the near future.

Want to ask for possible way to load our own bitmap (from DOS times) fonts, saw that '_FONT 16' is default for SCREEN 0, if there is a way to load those fonts will bring additional retro flavor as they were very nice, sharing them, to take a look if interested:
 
 

@Sanmayce

Welcome. I like GUI the stuff, too. I've got a project I'm working on currently, posted over at the QBasic forum. Since you're an old-timer, do you remember that forum? Network54 used to host it. Now it's on Tapatalk. Mallord was the first admin, followed by Mac, and Mac turned it over to me, when he passed away in 2008. Anyway, I'm just curious if you recall it, or Pete's QBasic forum, or any of the others back in the day.

Pete

Thanks, will share some GUI of mine in the future, my Gallowwalker GUI, in the meantime you are welcome to see some of its functionality at:
https://github.com/Sanmayce/1gram/issues/1 (https://github.com/Sanmayce/1gram/issues/1)

As for the old forum, no, was not active in Internet for a long time, haven't seen it. Otherwise, I am a chatterbox :P

The idea is to have the first English Phrase-Checker - checking all n-grams (phrases of n words) of your text (the loaded into this QB64 assistant) against mega corpora of English n-grams, hundreds of millions strong!
 


@Sanmayce  welcome! I did not know or see demo of _ACCEPTFILEDROP, thanks! Hopefully we can drop in more than one file eventually.

Thank you, @bplus, I myself am uncovering new things on a daily basis, so many gaps ate there in my know-how.

Did a minor tweak (pseudo-bug fixage), rather add-on, now one can use the left button and "jump" on the desired line, along with scrolling with keys and the wheel:

Code: QB64: [Select]
  1. ' DragDropWheelScroller.bas
  2. ' written in QB64 v1.4 by Kaze, 2021-Jan-21
  3. ' Thanks go to the www.qb64.org/forum members for sharing useful excerpts/etudes
  4.  
  5. _TITLE "DragDropWheel"
  6. CONST RSHIFT& = 100303
  7. CONST LSHIFT& = 100304
  8.  
  9. XdimCOL = 100
  10. YdimROW = 44 ' ensure old laptops with 768pixels vertical will hold the whole window
  11. IF high& > 1000 THEN YdimROW = 60
  12. handle& = _NEWIMAGE(XdimCOL, YdimROW, 0)
  13. SCREEN handle&
  14.  
  15. '_FONT 16 'wish we could use the old 8x16 bitmap/raster fonts from DOS times...
  16.  
  17. ' Either one must be uncommented:
  18. '_AUTODISPLAY 'no need of refreshing
  19.  
  20. _ACCEPTFILEDROP 'enables drag/drop functionality
  21.  
  22. IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  23.     COLOR 9, 0
  24.     COLOR 3, 0
  25.  
  26. PRINT "Current working directory path: "; CHR$(34); _CWD$; CHR$(34)
  27. PRINT "User's program calling path: "; CHR$(34); _STARTDIR$; CHR$(34)
  28. PRINT "Command line parameters sent when a program is started: "; CHR$(34); COMMAND$; CHR$(34)
  29. PRINT "_OS$="; _OS$
  30.  
  31. 'Y = CSRLIN 'save the row
  32. 'X = POS(0) 'save the column
  33.  
  34. filecount% = 0
  35. REDIM FileArray$(1000000) 'create dynamic array: 3880000 alocates 532MB - bigger values need 570+MB and give "Out Of Memory"
  36.  
  37. FOR i = 1 TO YdimROW
  38.     FileArray$(i) = ""
  39.  
  40. PRINT "Drag files from a folder and drop them in this window..."
  41. 'REDIM FileArray$(filecount%)
  42.  
  43. 'pressakey$ = INPUT$(1)
  44.  
  45. a$ = ""
  46.         'FOR i = 1 TO _TOTALDROPPEDFILES
  47.         'a$ = _DROPPEDFILE(i)
  48.         a$ = _DROPPEDFILE(1)
  49.         'NEXT'
  50.         _FINISHDROP 'If _FINISHDROP isn't called here then _TOTALDROPPEDFILES never gets reset.
  51.         'ELSE
  52.         'a$ = "Scroller.$$$"
  53.         'SHELL _HIDE "DIR /B *.* > Scroller.$$$"
  54.     END IF
  55.  
  56.     IF _FILEEXISTS(a$) THEN
  57.         OPEN a$ FOR INPUT AS #1
  58.         DO UNTIL EOF(1)
  59.             LINE INPUT #1, filename$ 'read entire text file line
  60.             filecount% = filecount% + 1
  61.             FileArray$(filecount%) = filename$
  62.         LOOP
  63.         CLOSE #1
  64.     END IF
  65.     _LIMIT 30
  66. LOOP WHILE a$ = ""
  67.  
  68. 'PRINT "Printing filenames in current directory... ";: PRINT LTRIM$(STR$(filecount%))
  69.  
  70. FOR i = 1 TO YdimROW 'filecount%
  71.     IF LEN(FileArray$(i)) >= XdimCOL THEN
  72.         FileArray$(i) = MID$(FileArray$(i), 1, XdimCOL)
  73.     ELSE
  74.         FileArray$(i) = FileArray$(i) + SPACE$(XdimCOL - LEN(FileArray$(i)))
  75.     END IF
  76.     LOCATE i, 1: PRINT FileArray$(i);
  77.  
  78. LOCATE 1, 1
  79. crx = POS(0)
  80. cry = CSRLIN
  81. crxOLD = crx
  82. cryOLD = cry
  83. LOCATE cry, crx, 1, 30, 31
  84.  
  85. IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  86.     COLOR 8, 0
  87.     COLOR 0, 3
  88. PRINT FileArray$(cry);
  89.     IF _KEYDOWN(LSHIFT&) THEN PLAY "L8V2ff-"
  90.     IF _KEYDOWN(RSHIFT&) THEN PLAY "L8V2a-c-"
  91.     'LOCATE cry, crx, 1, 30, 31
  92.     key$ = INKEY$
  93.     'DO: a$ = INKEY$: LOOP UNTIL a$ <> "" ' prevent ASC empty string read error
  94.     IF key$ <> "" THEN
  95.         code% = ASC(key$):
  96.         IF code% THEN ' ASC returns any value greater than 0
  97.             SELECT CASE ASC(key$)
  98.                 CASE 65 TO 97: 'PRINT key$;
  99.                 CASE ASC("a") TO ASC("z"): 'PRINT key$;
  100.                 CASE 27: COLOR 7, 0: SYSTEM 'END
  101.             END SELECT
  102.         ELSE
  103.             SELECT CASE ASC(key$, 2)
  104.                 CASE 72: IF cry > 1 THEN cry = cry - 1 'up
  105.                 CASE 80: IF cry < YdimROW THEN cry = cry + 1 'down
  106.                 CASE 75: IF crx > 1 THEN crx = crx - 1 'left
  107.                 CASE 77: IF crx < XdimCOL THEN crx = crx + 1 'right
  108.             END SELECT
  109.         END IF
  110.     END IF
  111.     IF cryOLD <> cry THEN
  112.         'LOCATE cryOLD, crx, 1, 30, 31: COLOR 3, 0: PRINT FileArray$(cryOLD);
  113.         LOCATE cryOLD, 1, 1, 30, 31
  114.         IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  115.             COLOR 9, 0
  116.         ELSE
  117.             COLOR 3, 0
  118.         END IF
  119.         PRINT FileArray$(cryOLD);
  120.         cryOLD = cry
  121.     ELSE 'it 'cry' could be changed by Mouse Wheel too, check it
  122.         AsIfItIsINKEY% = _MOUSEINPUT '      Check the mouse status
  123.         IF _MOUSEWHEEL = 1 THEN ' as if Down
  124.             IF cry < YdimROW THEN cry = cry + 1 'down
  125.         END IF
  126.         IF _MOUSEWHEEL = -1 THEN ' as if Up
  127.             IF cry > 1 THEN cry = cry - 1 'up
  128.         END IF
  129.         'Kinda trump the arrows and wheel with MOUSEmovement i.e. us having both the inverse(selected) line plus darklighting the current(under the mouse pointer) one
  130.         IF _MOUSEBUTTON(1) THEN
  131.             cry = _MOUSEY
  132.         END IF
  133.     END IF
  134.     'dummy me, the 2021-Jan-20 was not smoot friendly, should have updated here (not in the loop afterwards) i.e. _DISPLY shows two inversed lines, ugh [
  135.     IF cryOLD <> cry THEN
  136.         'LOCATE cryOLD, crx, 1, 30, 31: COLOR 3, 0: PRINT FileArray$(cryOLD);
  137.         LOCATE cryOLD, 1, 1, 30, 31
  138.         IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  139.             COLOR 9, 0
  140.         ELSE
  141.             COLOR 3, 0
  142.         END IF
  143.         PRINT FileArray$(cryOLD);
  144.         cryOLD = cry
  145.     END IF
  146.     'dummy me, the 2021-Jan-20 was not smoot friendly, should have updated here (not in the loop afterwards) i.e. _DISPLY shows two inversed lines, ugh ]
  147.     'LOCATE cry, crx, 1, 30, 31: COLOR 0, 3: PRINT FileArray$(cry);
  148.     LOCATE cry, 1, 1, 30, 31
  149.     IF INSTR(LCASE$(COMMAND$), "/purple") THEN
  150.         COLOR 8, 0
  151.     ELSE
  152.         COLOR 0, 3
  153.     END IF
  154.     PRINT FileArray$(cry);
  155.     _DISPLAY
  156.     'DO WHILE INKEY$ <> "": LOOP ' have to clear the keyboard buffer
  157.     '_LIMIT 30 'commented because the wheel up/down was not working?!
  158.  
  159.  

 


Kinda want to revive the DOS functionality of my old QB project:

 

 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: FellippeHeitor on January 20, 2021, 11:43:42 pm
Quote
Fellippe, I bend a knee before you. resurrecting QB is just awesome! Many beers I owe you.
As far as I recall, only said this once back, to another developer - a true master of coding compression in C.

Really enliked your presentation about 'InForm', please consider doing such reviews more often, at least not stopping them:

https ://www.youtube.com/watch?v=S3D4zEUQ0sQ&list=PLD7-OthpyuXNbrB12Cl5_3vBpRtvN7CA8&index=5

Nice work with this Form Designer, wanna try it after some weeks, my tempo is slow but ongoing, a real fan here, that is.

We all bend our knees before @Galleon, the guy who created QB64 in the first place. I'm barely part of the team. He does come around from time to time.

I'm so glad you enjoyed InForm! That's truly my code baby. Let me know if I can be of any assistance with it.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 20, 2021, 11:53:39 pm
We all bend our knees before @Galleon, the guy who created QB64 in the first place. I'm barely part of the team. He does come around from time to time.

I'm so glad you enjoyed InForm! That's truly my code baby. Let me know if I can be of any assistance with it.

Oh, I bend a knee the third time, then. VIVA @Galleon.
I can tell from your video, you are bona-fide QB fellow, indeed!
Excuse me for the previous messy post of mine, couldn't fit all the illustrative screenshots at once, that is what happens when many fellow members address a new fellow at once, likey-likey :P
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: NOVARSEG on January 21, 2021, 12:17:33 am
Thanks Sanmayce


Quote
My passion is text processing of huge English text, searching, decompressing, indexing them in order to ease quick n-gram requests i.e. to have spell-checkers, and ... phrase-checkers of English texts under the fingers.
C and QB64 are so instrumental in that regard, eager to pursue this dream of mine...

You will like the fact that QB64 string size is over 2GB

Quote
25 years ago I wrote some original tools in QB45 + MASM functions

Did you ever use DOS interrupts . Ralf Brown interrupt list etc?
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 21, 2021, 01:00:35 am
@NOVARSEG

Thank you for the hint, will try it, currently I am using an old laptop with Windows XP 32bit paired with a buggy ATI videocard (causing text to be blurred if more than ~130 columns are used), next week I will get access to my main laptop with Windows 10 64bit with i5-7200u and 36GB, at the moment my brother is repairing it, it is 4 years old, almost.

Thanks Sanmayce


You will like the fact that QB64 string size is over 2GB

Did you ever use DOS interrupts . Ralf Brown interrupt list etc?

Oh, good to know, I love strings, the thing is, over the years just switched to C and changed the approach to pointers. Will share inhere how the scrolling of 1+GB texts is handled...

As for interrupts, yeah, I wrote some resident keyboard tools, switching fonts and languages, KAZUMA.COM it was called, it featured AFAIR 11 fonts and using the 28 lines. But mostly I used MASM to write all my functions and link them to QB, the main thing was to use XMS memory from QB, also writing 3D windows waiting for the refresh beam to scan again, the time between refreshing was pretty enough to achieve smooth scrolling and drawing. Also, wrote OTANE.BAS - the fastest VESA 1.2 graphical PCX viewer/scroller, it rotated images, AFAIR reaching 44 fps on some 486DX100MHz in 1024x768, forgot already, did attach them anyway:
 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 22, 2021, 02:53:26 am
The first INITIAL revision is done, from which I will add more and more features...

Just added few things:
- ICON;
- increased the LIMIT to 500 iterations, as suggested by @NOVARSEG (glad to see the scroll is smoothly going, now);
- sensitive to writing to CONSOLE;
- added the must-have system stats by @SMcNeill from his MEMUSAGE.BAS;

Wanted to have the very first revision attached as a starting point.

My brother finished repairing my main laptop 'Compressionette', sharing three screenshots:

 


 


 


And the source attached: 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 24, 2021, 01:13:33 pm
Last night wrote the first meaningful i.e. practical revision, revision 2, featuring:

 

- the loaded file now is viewable i.e. scrollable;
- loading the file alternatively via command prompt;
- TAB2SPC expander;
- Line Wrapper, commented out since currently is not needed;
- now there is a status line;
- should be compilable on Linux;
- Mouse Button 3 - works as if PgDn is pressed;
- LSHIFT+RSHIFT prints in the lowest/status line the time needed to load;
- LCtrl+Home, LCtrl+End  - going to the top/bottom left position;

In the future, I intend to write a streaming revision able to show only the window (dynamically loading only the needed for visualization content) thus saving RAM and TIME, for example current English Wikipedia XML dump is 81+ billion bytes having longest line around 1 million chars, it means that the RAM for browsing this Wikipedia will be less than 60x1MB i.e. 60 lines padded with spaces... For now, let us see how one paragon 500MB file stresses the current ALL-TO-RAM approach:

On my fastest laptop with i5-7200U did try to load the whole Oxford English Dictionary, the performance of LINE INPUT is awful, in next revisions will bypass it altogether by replacing it with my own pointer based function, similar to the 'LineWordreporter.c' (included in the attached package) - wrote it to serve as a quick file reporter.

 


 


 


The benchmark shows, OED took 23,187 seconds or 6+ hours to be loaded via LINE INPUT, unacceptable! Any idea why so?
Holding the Mouse Button 3 for:
19:19:00
19:22:38
or 22*60+38-19*60+00=218 seconds scrolled all the 4 million lines, or 4,071,706/60=67861 pages, which is 67861/218=311 Pages-Per-Second, nice.

There is a Keyboard SUB called 'ReturnCombo' returning in shared variables many to-be-used shortcuts as:

Code: QB64: [Select]
  1. ' Masakari.bas (DragDropWheelScroller.bas)
  2. ' written in QB64 v1.4 by Kaze, 2021-Jan-24
  3. ' Thanks go to the www.qb64.org/forum members for sharing useful excerpts/etudes
  4. ' Wow, this is nice indeed: http://www.qb64.org/wiki/Windows_Libraries
  5.  
  6. ' Currently are implemented only:
  7. ' Mouse:
  8. '       Button 1 - sets the cursor and the inverse line to the chosen position
  9. '       Button 3 - PgDn
  10. '       Wheel Up - Up
  11. '       Wheel Dn - Dn
  12. ' Keyboard:
  13. '        Up
  14. '        Down
  15. '        Left - still no sideways scroll
  16. '        Right - still no sideways scroll
  17. '        LCtrl+Home - going to the top left position
  18. '        LCtrl+End  - going to the bottom left position
  19. '        Alt+x or Alt+q - quit to the system, without demanding keypress.
  20.  
  21. _TITLE "MASAKARI 128x60, The 'Holy Axe' English Text Sidekick"
  22. $EXEICON:'ColumnChart.ico'
  23. CONST RSHIFTkey& = 100303
  24. CONST LSHIFTkey& = 100304
  25. CONST RCTRLkey& = 100305
  26. CONST LCTRLkey& = 100306
  27. CONST RALTkey& = 100307
  28. CONST LALTkey& = 100308
  29.  
  30. CONST BACKSPCkey& = 8
  31. CONST TABkey& = 9
  32. CONST SPACEkey& = 32
  33. CONST ESCkey& = 27
  34. CONST ENTERkey& = 13
  35.  
  36. CONST HOMEkey& = 18176
  37. CONST ENDkey& = 20224
  38.  
  39. CONST INSkey& = 20992
  40. CONST DELkey& = 21248
  41.  
  42. CONST PGUPkey& = 18688
  43. CONST PGDNkey& = 20736
  44.  
  45. CONST LEFTkey& = 19200
  46. CONST RIGHTkey& = 19712
  47. CONST UPkey& = 18432
  48. CONST DOWNkey& = 20480
  49.  
  50.     $CONSOLE
  51.     _CONSOLE ON
  52.     _CONSOLETITLE "Masakari console window"
  53.     PRINT "Masakari, revision 2, written in QB64 by Kaze"
  54.     PRINT "Usage: Masakari filename|/help"
  55.     SYSTEM
  56.     '_CONSOLE OFF
  57.     '_SCREENSHOW
  58.     $CONSOLE
  59.  
  60. 'DEFLNG A-Z
  61. '_DEFINE A-Z AS _UNSIGNED _INTEGER64
  62.  
  63. $IF WINDOWS THEN
  64.     DECLARE LIBRARY "mem"
  65.         FUNCTION MemInUsePercent~&&
  66.         FUNCTION TotalPhysicalMem~&&
  67.         FUNCTION FreePhysicalMem~&&
  68.         FUNCTION TotalPagingFile~&&
  69.         FUNCTION FreePagingFile~&&
  70.         FUNCTION TotalVirtualMem~&&
  71.         FUNCTION FreeVirtualMem~&&
  72.         FUNCTION FreeExtendedMem~&&
  73.         FUNCTION GetCPULoad#
  74.     END DECLARE
  75.  
  76. XdimCOL = 128
  77. YdimROW = 44 ' ensure old laptops with 768pixels vertical will hold the whole window
  78. IF high& > 1000 THEN YdimROW = 60
  79. handle& = _NEWIMAGE(XdimCOL, YdimROW + 1, 0)
  80. SCREEN handle&
  81. _DEST handle&
  82.  
  83. ' _DEST 0 refers to the present program SCREEN. You can use 0 to refer to the present program
  84. '  SCREEN.
  85.  
  86. '_FONT 16 'wish we could use the old 8x16 bitmap/raster fonts from DOS times...
  87.  
  88. ' Either one must be uncommented:
  89. '_AUTODISPLAY 'no need of refreshing
  90.  
  91. TimeA = TIMER
  92.  
  93. PurpleFlag = 0
  94. 'PurpleFlag = 1
  95.  
  96. NormalFRGr = 3
  97. IF PurpleFlag THEN NormalFRGr = 9
  98. NormalBCKGr = 0
  99. IF PurpleFlag THEN NormalBCKGr = 0
  100.  
  101. InverseFRGr = 0
  102. IF PurpleFlag THEN InverseFRGr = 8
  103. InverseBCKGr = 3
  104. IF PurpleFlag THEN InverseBCKGr = 0
  105.  
  106. COLOR NormalFRGr, NormalBCKGr
  107.  
  108. PRINT "Current working directory path: "; CHR$(34); _CWD$; CHR$(34)
  109. PRINT "User's program calling path: "; CHR$(34); _STARTDIR$; CHR$(34)
  110. PRINT "Command line parameters sent when a program is started: "; CHR$(34); COMMAND$; CHR$(34)
  111. PRINT "_OS$="; _OS$
  112.  
  113. 'Y = CSRLIN 'save the row
  114. 'X = POS(0) 'save the column
  115.  
  116. REDIM FileArray$(1) 'create dynamic array: 3880000 alocates 532MB - bigger values need 570+MB and give "Out Of Memory"
  117. DIM FileArrayWINDOW$(YdimROW)
  118.  
  119. $IF WINDOWS THEN
  120.     _ACCEPTFILEDROP 'enables drag/drop functionality
  121.     IF COMMAND$ = "" THEN PRINT: PRINT "Drag files from a folder and drop them in this window...": PRINT
  122.  
  123. 'pressakey$ = INPUT$(1)
  124.  
  125. a$ = ""
  126. PostfixedToHeader = CSRLIN
  127.  
  128.     LOCATE PostfixedToHeader, 1
  129.  
  130.     $IF WINDOWS THEN
  131.         ' MEMUSAGE by Steve [
  132.         ' GetCPULoad = 0 is idle, 1 is fully used.
  133.         '  Multiply by 100 for a percentage
  134.         PRINT "CPU used:              "; LTRIM$(STR$(INT((GetCPULoad * 10000) / 100))); "%"; SPACE$(18)
  135.         PRINT "Memory used:           "; LTRIM$(STR$(MemInUsePercent)); "%"; SPACE$(18)
  136.         PRINT "Total Physical Memory: ";
  137.         PRINT AddCommas$(TotalPhysicalMem); " bytes"; SPACE$(18)
  138.         PRINT "Free Physical Memory:  ";
  139.         PRINT AddCommas$(FreePhysicalMem); " bytes"; SPACE$(18)
  140.         PRINT "Total Paging File:     ";
  141.         PRINT AddCommas$(TotalPagingFile); " bytes"; SPACE$(18)
  142.         PRINT "Free Paging File:      ";
  143.         PRINT AddCommas$(FreePagingFile); " bytes"; SPACE$(18)
  144.         PRINT "Total Virtual Memory:  ";
  145.         PRINT AddCommas$(TotalVirtualMem); " bytes"; SPACE$(18)
  146.         PRINT "Free Virtual Memory:   ";
  147.         PRINT AddCommas$(FreeVirtualMem); " bytes"; SPACE$(18)
  148.         'PRINT "Free Extended Virtual Memory:"
  149.         'PRINT "  "; FreeExtendedMeml; " bytes"
  150.         ' MEMUSAGE by Steve ]
  151.     $END IF
  152.  
  153.     IF COMMAND$ = "" THEN PRINT: PRINT "May press Alt+X or Alt+Q to eXit/Quit..."
  154.     ReturnCOMBO
  155.     _DISPLAY
  156.  
  157.     $IF WINDOWS THEN
  158.             'FOR i = 1 TO _TOTALDROPPEDFILES
  159.             'a$ = _DROPPEDFILE(i)
  160.             a$ = _DROPPEDFILE(1)
  161.             'NEXT'
  162.             _FINISHDROP 'If _FINISHDROP isn't called here then _TOTALDROPPEDFILES never gets reset.
  163.             'ELSE
  164.             'a$ = "Scroller.$$$"
  165.             'SHELL _HIDE "DIR /B *.* > Scroller.$$$"
  166.         END IF
  167.     $END IF
  168.     IF COMMAND$ <> "" THEN a$ = COMMAND$
  169.  
  170.     'WrapFlag = 0
  171.     'Wwidth% = XdimCOL
  172.     'ul& = 0
  173.     'LongestLine = 0
  174.     'DO WHILE NOT EOF(1)
  175.     '    LINE INPUT #1, l$: ul& = ul& + 1
  176.     '    ExpandTabs l$
  177.     '    IF LEN(l$) > LongestLine THEN LongestLine = LEN(l$)
  178.     '    IF WrapFlag THEN
  179.     '        lX$ = l$
  180.     '        DO WHILE LEN(lX$) > Wwidth%
  181.     '            Glupak% = Wwidth%
  182.     '            DO UNTIL MID$(lX$, Glupak% + 1, 1) = " " AND MID$(lX$, Glupak%, 1) <> " "
  183.     '                Glupak% = Glupak% - 1
  184.     '                IF Glupak% = 0 THEN
  185.     '                    PRINT "Rejecting line(#"; LTRIM$(STR$(ul&)); ", "; LTRIM$(STR$(LEN(l$))); "chars) that cannot be wrapped!"
  186.     '                    _DISPLAY: SYSTEM
  187.     '                    GOTO B4Txpanar
  188.     '                END IF
  189.     '            LOOP
  190.     '            PRINT #3, LEFT$(lX$, Glupak%)
  191.     '            lX$ = STRING$(1, " ") + LTRIM$(MID$(lX$, Glupak% + 1, LEN(lX$) - (Glupak%)))
  192.     '        LOOP
  193.     '        PRINT #3, lX$
  194.     '        B4Txpanar:
  195.     '    END IF
  196.     'LOOP
  197.  
  198.     LongestLine = 0
  199.     IF _FILEEXISTS(a$) THEN
  200.         PRINT: PRINT "Loading..."
  201.         _DISPLAY
  202.         filecount = 0
  203.         OPEN a$ FOR INPUT AS #1
  204.         DO UNTIL EOF(1)
  205.             LINE INPUT #1, l$
  206.             filecount = filecount + 1
  207.         LOOP
  208.         CLOSE #1
  209.         REDIM FileArray$(1 TO filecount)
  210.         filecount = 0
  211.         OPEN a$ FOR INPUT AS #1
  212.         FileSize = LOF(1)
  213.         DO UNTIL EOF(1)
  214.             LINE INPUT #1, l$
  215.             ExpandTabs l$
  216.             FOR j = 1 TO LEN(l$)
  217.                 IF MID$(l$, j, 1) < CHR$(32) THEN MID$(l$, j, 1) = CHR$(32)
  218.             NEXT j
  219.             IF LEN(l$) > LongestLine THEN LongestLine = LEN(l$)
  220.             filecount = filecount + 1
  221.             FileArray$(filecount) = l$
  222.         LOOP
  223.         CLOSE #1
  224.     END IF
  225.     _LIMIT 5
  226.     'IF INKEY$ = CHR$(27) THEN SYSTEM
  227.     'IF keycode& = 27 THEN SYSTEM
  228.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(81) OR _KEYDOWN(113)) THEN SYSTEM
  229.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(88) OR _KEYDOWN(120)) THEN SYSTEM
  230.  
  231.     '                            QB64 _KEYHIT and _KEYDOWN Values
  232.     '
  233.     'Esc  F1    F2    F3    F4    F5    F6    F7    F8    F9    F10   F11   F12   Sys  ScL Pause
  234.     ' 27 15104 15360 15616 15872 16128 16384 16640 16896 17152 17408 34048 34304 +316 +302 +019
  235.     '`~  1!  2@  3#  4$  5%  6^  7&  8*  9(  0) -_ =+ BkSp   Ins   Hme   PUp   NumL   /     *    -
  236.     '126 33  64  35  36  37  94  38  42  40  41 95 43   8   20992 18176 18688 +300   47    42   45
  237.     ' 96 49  50  51  52  53  54  55  56  57  48 45 61
  238.     'Tab Q   W   E   R   T   Y   U   I   O   P  [{  ]}  \|   Del   End   PDn   7Hme  8/?   9PU   +
  239.     ' 9  81  87  69  82  84  89  85  73  79  80 123 125 124 21248 20224 20736 18176 18432 18688 43
  240.     '   113 119 101 114 116 121 117 105 111 112  91  93  92                    55    56    57
  241.     'CapL   A   S   D   F   G   H   J   K   L   ;:  '" Enter                   4/?-   5    6/-?
  242.     '+301   65  83  68  70  71  72  74  75  76  58  34  13                    19200 19456 19712  E
  243.     '       97 115 100 102 103 104 106 107 108  59  39                         52    53    54    n
  244.     'Shift   Z   X   C   V   B   N   M   ,<  .>  /?    Shift       ?           1End  2/?   3PD   t
  245.     '+304   90  88  67  86  66  78  77  60  62  63    +303       18432        20224 20480 20736  e
  246.     '      122 120  99 118  98 110 109  44  46  47                             49    50    51    r
  247.     'Ctrl   Win  Alt     Spacebar      Alt  Win  Menu  Ctrl   ?-   ?   -?      0Ins        .Del
  248.     '+306  +311 +308       32         +307 +312 +319  +305 19200 20480 19712  20992       21248 13
  249.     '                                                                          48          46
  250.     '         Lower value = LCase/NumLock On __________________ + = add 100000
  251.  
  252. LOOP WHILE a$ = ""
  253.  
  254. TimeB = TIMER
  255. PLAY "L8V2a-c-"
  256. CurrentLine = 1
  257. FOR i = 1 TO YdimROW
  258.     LOCATE i, 1: PRINT SPACE$(XdimCOL);
  259. FOR i = 1 TO MIN&(YdimROW, filecount)
  260.     IF LEN(FileArray$(i)) >= XdimCOL THEN
  261.         FileArrayWINDOW$(i) = MID$(FileArray$(i), 1, XdimCOL)
  262.     ELSE
  263.         FileArrayWINDOW$(i) = FileArray$(i) + SPACE$(XdimCOL - LEN(FileArray$(i)))
  264.     END IF
  265.     LOCATE i, 1: PRINT FileArrayWINDOW$(i);
  266.  
  267. ' Here is the layout:
  268. ' The window-frame is 1..crx or 1..128 |  The file-frame is 1..LongestLine
  269. '                     .         .      |                    .
  270. '                     .         .      |                    .
  271. '                     cry       60     |                    filecount
  272. '              FileArrayWINDOW$(60)    |          FileArray(filecount)
  273. ' if File_Frame_x < 128 then PADDING to 128 else File_Frame_x = 1..LongestLine-(128-1)
  274. ' if File_Frame_y < 60 then PADDING to 60 else File_Frame_y = 1..filecount-(60-1)
  275.  
  276. UpdateCLine 1, 1, InverseFRGr, InverseBCKGr, 1
  277. StatuLine$ = SPACE$(XdimCOL)
  278. MID$(StatuLine$, 1, 1) = "["
  279. MID$(StatuLine$, XdimCOL, 1) = "]"
  280.  
  281. Dumbo$ = "File Size: " + AddCommas$(FileSize) + "; Longest Line: " + AddCommas$(LongestLine) + "; Total Lines: " + AddCommas$(filecount)
  282. MID$(StatuLine$, 2, LEN(Dumbo$)) = Dumbo$
  283. LOCATE YdimROW + 1, 1: COLOR 9, 0: PRINT StatuLine$;
  284. UpdateCLL CurrentLine, LEN(Dumbo$) + 1 + 1
  285. CLL_Field = LEN(AddCommas$(LongestLine))
  286. MostRightField = LEN(Dumbo$) + 1 + 1 + (LEN("; Current Line Length: ") + CLL_Field)
  287. UpdateNextToCCL_DONE MostRightField
  288.  
  289. LOCATE 1, 1, 1, 30, 31
  290. crx = POS(0)
  291. cry = CSRLIN
  292. crxOLD = crx
  293. cryOLD = cry
  294. File_Frame_x = 1
  295. File_Frame_y = 1
  296.  
  297.     ReturnCOMBO
  298.     IF LSHIFT_RSHIFT THEN
  299.         PLAY "L4V2f": _KEYCLEAR
  300.         ReportTimeToLoad MostRightField
  301.         _DISPLAY
  302.     END IF
  303.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(81) OR _KEYDOWN(113)) THEN SYSTEM
  304.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(88) OR _KEYDOWN(120)) THEN SYSTEM
  305.     key$ = INKEY$
  306.     'DO: a$ = INKEY$: LOOP UNTIL a$ <> "" ' prevent ASC empty string read error
  307.     IF key$ <> "" THEN
  308.         code% = ASC(key$):
  309.         IF code% THEN ' ASC returns any value greater than 0
  310.             SELECT CASE ASC(key$)
  311.                 CASE 65 TO 97: 'PRINT key$;
  312.                 CASE ASC("a") TO ASC("z"): 'PRINT key$;
  313.                     'CASE 27: COLOR 7, 0: SYSTEM 'END
  314.             END SELECT
  315.         ELSE
  316.             SELECT CASE ASC(key$, 2)
  317.                 CASE 72:
  318.                     IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  319.                     IF cry > 1 THEN
  320.                         cry = cry - 1 'up
  321.                     ELSE 'scrolling is needed
  322.                         IF File_Frame_y > 1 THEN File_Frame_y = File_Frame_y - 1
  323.                         UpdateWindowFrame NormalFRGr, NormalBCKGr
  324.                     END IF
  325.                 CASE 80:
  326.                     IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  327.                     IF cry < YdimROW THEN
  328.                         IF cry < filecount THEN cry = cry + 1 'down
  329.                     ELSE 'scrolling is needed
  330.                         IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  331.                         UpdateWindowFrame NormalFRGr, NormalBCKGr
  332.                     END IF
  333.                 CASE 75: IF crx > 1 THEN crx = crx - 1 'left
  334.                 CASE 77: IF crx < XdimCOL THEN crx = crx + 1 'right
  335.             END SELECT
  336.         END IF
  337.     END IF
  338.     IF cryOLD <> cry THEN
  339.         UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  340.         cryOLD = cry
  341.     ELSE 'it 'cry' could be changed by Mouse Wheel too, check it
  342.         AsIfItIsINKEY% = _MOUSEINPUT '      Check the mouse status
  343.         IF _MOUSEWHEEL = 1 THEN ' as if Down
  344.             IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  345.             IF cry < YdimROW THEN
  346.                 IF cry < filecount THEN cry = cry + 1 'down
  347.             ELSE 'scrolling is needed
  348.                 IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  349.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  350.             END IF
  351.         END IF
  352.         IF _MOUSEWHEEL = -1 THEN ' as if Up
  353.             IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  354.             IF cry > 1 THEN
  355.                 cry = cry - 1 'up
  356.             ELSE 'scrolling is needed
  357.                 IF File_Frame_y > 1 THEN File_Frame_y = File_Frame_y - 1
  358.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  359.             END IF
  360.         END IF
  361.         IF _MOUSEBUTTON(1) THEN
  362.             crxOLD = crx
  363.             cryOLD = cry
  364.             cry = _MOUSEY
  365.             crx = _MOUSEX
  366.             UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  367.             DO WHILE cryOLD > cry
  368.                 cryOLD = cryOLD - 1
  369.                 IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  370.             LOOP
  371.             DO WHILE cryOLD < cry
  372.                 cryOLD = cryOLD + 1
  373.                 IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  374.             LOOP
  375.         END IF
  376.         IF _MOUSEBUTTON(3) THEN 'PgDn - just add the page height i.e. 'YdimROW' to 'File_Frame_y'
  377.             ' Don't execute PgDn (advancing the 'CurrentLine') if 'File_Frame_y' is not "eligible":
  378.             'IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  379.             'IF File_Frame_y + 1 <= filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  380.             'CAUTION [
  381.             ' Next three line beep NOT
  382.             'DEFLNG A-Z
  383.             'aaa = 61
  384.             'bbb = -48
  385.             'IF aaa <= bbb THEN BEEP: END
  386.             'Next three line beep
  387.             'aaa~& = 61
  388.             'bbb~& = -48
  389.             'IF aaa~& <= bbb~& THEN BEEP: END
  390.             'Next three line beep NOT
  391.             'aaa& = 61
  392.             'bbb& = -48
  393.             'IF aaa& <= bbb& THEN BEEP: END
  394.             'Next line works even when unsigned!
  395.             'IF File_Frame_y + YdimROW - (filecount - (YdimROW - 1)) <= 0 THEN
  396.             'CAUTION ]
  397.             'Next line doesn't work when unsigned!
  398.             IF File_Frame_y + YdimROW <= filecount - (YdimROW - 1) THEN
  399.                 File_Frame_y = File_Frame_y + YdimROW
  400.                 'IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  401.                 'IF CurrentLine + 1 <= filecount THEN CurrentLine = CurrentLine + 1
  402.                 IF CurrentLine + YdimROW <= filecount THEN CurrentLine = CurrentLine + YdimROW
  403.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  404.             END IF
  405.         END IF
  406.     END IF
  407.     IF cryOLD <> cry THEN
  408.         UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  409.         cryOLD = cry
  410.     END IF
  411.     IF LCTRL_HOME THEN
  412.         LOCATE 1, 1, 1, 30, 31
  413.         crx = POS(0)
  414.         cry = CSRLIN
  415.         crxOLD = crx
  416.         cryOLD = cry
  417.         File_Frame_x = 1
  418.         File_Frame_y = 1
  419.         CurrentLine = 1
  420.         UpdateWindowFrame NormalFRGr, NormalBCKGr
  421.     END IF
  422.     IF LCTRL_END THEN
  423.         IF filecount >= YdimROW THEN
  424.             IF filecount - (YdimROW - 1) THEN
  425.                 LOCATE YdimROW, 1, 1, 30, 31
  426.                 crx = POS(0)
  427.                 cry = CSRLIN
  428.                 crxOLD = crx
  429.                 cryOLD = cry
  430.                 File_Frame_x = 1
  431.                 File_Frame_y = filecount - (YdimROW - 1)
  432.                 CurrentLine = filecount
  433.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  434.             END IF
  435.         ELSE
  436.             LOCATE filecount, 1, 1, 30, 31
  437.             crx = POS(0)
  438.             cry = CSRLIN
  439.             crxOLD = crx
  440.             cryOLD = cry
  441.             File_Frame_x = 1
  442.             File_Frame_y = 1
  443.             CurrentLine = filecount
  444.             UpdateWindowFrame NormalFRGr, NormalBCKGr
  445.         END IF
  446.     END IF
  447.  
  448.     LOCATE cry, crx, 1, 30, 31
  449.     UpdateCLine cry, 1, InverseFRGr, InverseBCKGr, cry
  450.     UpdateCLL CurrentLine, LEN(Dumbo$) + 1 + 1
  451.     _DISPLAY
  452.     'DO WHILE INKEY$ <> "": LOOP ' have to clear the keyboard buffer
  453.     _LIMIT 500 '_LIMIT 30 'commented because the wheel up/down was not working?!
  454.  
  455.  
  456. SUB ReturnCOMBO
  457.     SHARED LSHIFT_RSHIFT
  458.     SHARED LCTRL_RCTRL
  459.     SHARED LALT_RALT
  460.  
  461.     SHARED LALT_HOME
  462.     SHARED LALT_END
  463.  
  464.     SHARED LALT_INS
  465.     SHARED LALT_DEL
  466.  
  467.     SHARED LALT_PGUP
  468.     SHARED LALT_PGDN
  469.  
  470.     SHARED LALT_Left
  471.     SHARED LALT_Right
  472.     SHARED LALT_Up
  473.     SHARED LALT_Down
  474.  
  475.     SHARED RALT_HOME
  476.     SHARED RALT_END
  477.  
  478.     SHARED RALT_INS
  479.     SHARED RALT_DEL
  480.  
  481.     SHARED RALT_PGUP
  482.     SHARED RALT_PGDN
  483.  
  484.     SHARED RALT_Left
  485.     SHARED RALT_Right
  486.     SHARED RALT_Up
  487.     SHARED RALT_Down
  488.  
  489.     SHARED LSHIFT_HOME
  490.     SHARED LSHIFT_END
  491.  
  492.     SHARED LSHIFT_INS
  493.     SHARED LSHIFT_DEL
  494.  
  495.     SHARED LSHIFT_PGUP
  496.     SHARED LSHIFT_PGDN
  497.  
  498.     SHARED LSHIFT_Left
  499.     SHARED LSHIFT_Right
  500.     SHARED LSHIFT_Up
  501.     SHARED LSHIFT_Down
  502.  
  503.     SHARED RSHIFT_HOME
  504.     SHARED RSHIFT_END
  505.  
  506.     SHARED RSHIFT_INS
  507.     SHARED RSHIFT_DEL
  508.  
  509.     SHARED RSHIFT_PGUP
  510.     SHARED RSHIFT_PGDN
  511.  
  512.     SHARED RSHIFT_Left
  513.     SHARED RSHIFT_Right
  514.     SHARED RSHIFT_Up
  515.     SHARED RSHIFT_Down
  516.  
  517.     SHARED LCTRL_HOME
  518.     SHARED LCTRL_END
  519.  
  520.     SHARED LCTRL_INS
  521.     SHARED LCTRL_DEL
  522.  
  523.     SHARED LCTRL_PGUP
  524.     SHARED LCTRL_PGDN
  525.  
  526.     SHARED LCTRL_Left
  527.     SHARED LCTRL_Right
  528.     SHARED LCTRL_Up
  529.     SHARED LCTRL_Down
  530.  
  531.     SHARED RCTRL_HOME
  532.     SHARED RCTRL_END
  533.  
  534.     SHARED RCTRL_INS
  535.     SHARED RCTRL_DEL
  536.  
  537.     SHARED RCTRL_PGUP
  538.     SHARED RCTRL_PGDN
  539.  
  540.     SHARED RCTRL_Left
  541.     SHARED RCTRL_Right
  542.     SHARED RCTRL_Up
  543.     SHARED RCTRL_Down
  544.  
  545.     SHARED LSHIFT_LCTRL_HOME
  546.     SHARED LSHIFT_LCTRL_END
  547.  
  548.     SHARED LSHIFT_LCTRL_INS
  549.     SHARED LSHIFT_LCTRL_DEL
  550.  
  551.     SHARED LSHIFT_LCTRL_PGUP
  552.     SHARED LSHIFT_LCTRL_PGDN
  553.  
  554.     SHARED LSHIFT_LCTRL_Left
  555.     SHARED LSHIFT_LCTRL_Right
  556.     SHARED LSHIFT_LCTRL_Up
  557.     SHARED LSHIFT_LCTRL_Down
  558.  
  559.     SHARED LSHIFT_BackSpace
  560.     SHARED LSHIFT_TAB
  561.     SHARED LSHIFT_SPACE
  562.     SHARED LSHIFT_ESC
  563.     SHARED LSHIFT_ENTER
  564.  
  565.     SHARED RSHIFT_BackSpace
  566.     SHARED RSHIFT_TAB
  567.     SHARED RSHIFT_SPACE
  568.     SHARED RSHIFT_ESC
  569.     SHARED RSHIFT_ENTER
  570.  
  571.     SHARED LCTRL_SPACE
  572.     SHARED LCTRL_ENTER
  573.  
  574.     SHARED RCTRL_SPACE
  575.     SHARED RCTRL_ENTER
  576.  
  577.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(RSHIFTkey&) THEN LSHIFT_RSHIFT = 1 ELSE LSHIFT_RSHIFT = 0
  578.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RCTRLkey&) THEN LCTRL_RCTRL = 1 ELSE LCTRL_RCTRL = 0
  579.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(RALTkey&) THEN LALT_RALT = 1 ELSE LALT_RALT = 0
  580.  
  581.     'LALT:
  582.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(HOMEkey&) THEN LALT_HOME = 1 ELSE LALT_HOME = 0
  583.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(ENDkey&) THEN LALT_END = 1 ELSE LALT_END = 0
  584.  
  585.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(INSkey&) THEN LALT_INS = 1 ELSE LALT_INS = 0
  586.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(DELkey&) THEN LALT_DEL = 1 ELSE LALT_DEL = 0
  587.  
  588.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(PGUPkey&) THEN LALT_PGUP = 1 ELSE LALT_PGUP = 0
  589.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(PGDNkey&) THEN LALT_PGDN = 1 ELSE LALT_PGDN = 0
  590.  
  591.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(LEFTkey&) THEN LALT_Left = 1 ELSE LALT_Left = 0
  592.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(RIGHTkey&) THEN LALT_Right = 1 ELSE LALT_Right = 0
  593.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(UPkey&) THEN LALT_Up = 1 ELSE LALT_Up = 0
  594.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(DOWNkey&) THEN LALT_Down = 1 ELSE LALT_Down = 0
  595.  
  596.     'RALT:
  597.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(HOMEkey&) THEN RALT_HOME = 1 ELSE RALT_HOME = 0
  598.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(ENDkey&) THEN RALT_END = 1 ELSE RALT_END = 0
  599.  
  600.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(INSkey&) THEN RALT_INS = 1 ELSE RALT_INS = 0
  601.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(DELkey&) THEN RALT_DEL = 1 ELSE RALT_DEL = 0
  602.  
  603.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(PGUPkey&) THEN RALT_PGUP = 1 ELSE RALT_PGUP = 0
  604.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(PGDNkey&) THEN RALT_PGDN = 1 ELSE RALT_PGDN = 0
  605.  
  606.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(LEFTkey&) THEN PRINT RALT_Left = 1 ELSE RALT_Left = 0
  607.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(RIGHTkey&) THEN RALT_Right = 1 ELSE RALT_Right = 0
  608.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(UPkey&) THEN RALT_Up = 1 ELSE RALT_Up = 0
  609.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(DOWNkey&) THEN RALT_Down = 1 ELSE RALT_Down = 0
  610.  
  611.     'LSHIFT:
  612.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(HOMEkey&) THEN LSHIFT_HOME = 1 ELSE LSHIFT_HOME = 0
  613.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ENDkey&) THEN LSHIFT_END = 1 ELSE LSHIFT_END = 0
  614.  
  615.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(INSkey&) THEN LSHIFT_INS = 1 ELSE LSHIFT_INS = 0
  616.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(DELkey&) THEN LSHIFT_DEL = 1 ELSE LSHIFT_DEL = 0
  617.  
  618.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(PGUPkey&) THEN LSHIFT_PGUP = 1 ELSE LSHIFT_PGUP = 0
  619.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(PGDNkey&) THEN LSHIFT_PGDN = 1 ELSE LSHIFT_PGDN = 0
  620.  
  621.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LEFTkey&) THEN LSHIFT_Left = 1 ELSE LSHIFT_Left = 0
  622.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(RIGHTkey&) THEN LSHIFT_Right = 1 ELSE LSHIFT_Right = 0
  623.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(UPkey&) THEN LSHIFT_Up = 1 ELSE LSHIFT_Up = 0
  624.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(DOWNkey&) THEN LSHIFT_Down = 1 ELSE LSHIFT_Down = 0
  625.  
  626.     'RSHIFT:
  627.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(HOMEkey&) THEN RSHIFT_HOME = 1 ELSE RSHIFT_HOME = 0
  628.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ENDkey&) THEN RSHIFT_END = 1 ELSE RSHIFT_END = 0
  629.  
  630.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(INSkey&) THEN RSHIFT_INS = 1 ELSE RSHIFT_INS = 0
  631.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(DELkey&) THEN RSHIFT_DEL = 1 ELSE RSHIFT_DEL = 0
  632.  
  633.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(PGUPkey&) THEN RSHIFT_PGUP = 1 ELSE RSHIFT_PGUP = 0
  634.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(PGDNkey&) THEN RSHIFT_PGDN = 1 ELSE RSHIFT_PGDN = 0
  635.  
  636.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(LEFTkey&) THEN RSHIFT_Left = 1 ELSE RSHIFT_Left = 0
  637.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(RIGHTkey&) THEN RSHIFT_Right = 1 ELSE RSHIFT_Right = 0
  638.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(UPkey&) THEN RSHIFT_Up = 1 ELSE RSHIFT_Up = 0
  639.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(DOWNkey&) THEN RSHIFT_Down = 1 ELSE RSHIFT_Down = 0
  640.  
  641.     'LCTRL:
  642.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN LCTRL_HOME = 1 ELSE LCTRL_HOME = 0
  643.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENDkey&) THEN LCTRL_END = 1 ELSE LCTRL_END = 0
  644.  
  645.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(INSkey&) THEN LCTRL_INS = 1 ELSE LCTRL_INS = 0
  646.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DELkey&) THEN LCTRL_DEL = 1 ELSE LCTRL_DEL = 0
  647.  
  648.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN LCTRL_PGUP = 1 ELSE LCTRL_PGUP = 0
  649.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN LCTRL_PGDN = 1 ELSE LCTRL_PGDN = 0
  650.  
  651.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN LCTRL_Left = 1 ELSE LCTRL_Left = 0
  652.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN LCTRL_Right = 1 ELSE LCTRL_Right = 0
  653.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(UPkey&) THEN LCTRL_Up = 1 ELSE LCTRL_Up = 0
  654.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN LCTRL_Down = 1 ELSE LCTRL_Down = 0
  655.  
  656.     'RCTRL:
  657.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN RCTRL_HOME = 1 ELSE RCTRL_HOME = 0
  658.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(ENDkey&) THEN RCTRL_END = 1 ELSE RCTRL_END = 0
  659.  
  660.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(INSkey&) THEN RCTRL_INS = 1 ELSE RCTRL_INS = 0
  661.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(DELkey&) THEN RCTRL_DEL = 1 ELSE RCTRL_DEL = 0
  662.  
  663.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN RCTRL_PGUP = 1 ELSE RCTRL_PGUP = 0
  664.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN RCTRL_PGDN = 1 ELSE RCTRL_PGDN = 0
  665.  
  666.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN RCTRL_Left = 1 ELSE RCTRL_Left = 0
  667.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN RCTRL_Right = 1 ELSE RCTRL_Right = 0
  668.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(UPkey&) THEN RCTRL_Up = 1 ELSE RCTRL_Up = 0
  669.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN RCTRL_Down = 1 ELSE RCTRL_Down = 0
  670.  
  671.     'LSHIFT+LCTRL: NOTICE: LSHIFT+LCTRL+Left triggers 3 variables on - 1] LSHIFT_LCTRL_Left 2] LSHIFT_Left 3] LCTRL_Left
  672.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN LSHIFT_LCTRL_HOME = 1 ELSE LSHIFT_LCTRL_HOME = 0
  673.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENDkey&) THEN LSHIFT_LCTRL_END = 1 ELSE LSHIFT_LCTRL_END = 0
  674.  
  675.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(INSkey&) THEN LSHIFT_LCTRL_INS = 1 ELSE LSHIFT_LCTRL_INS = 0
  676.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DELkey&) THEN LSHIFT_LCTRL_DEL = 1 ELSE LSHIFT_LCTRL_DEL = 0
  677.  
  678.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN LSHIFT_LCTRL_PGUP = 1 ELSE LSHIFT_LCTRL_PGUP = 0
  679.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN LSHIFT_LCTRL_PGDN = 1 ELSE LSHIFT_LCTRL_PGDN = 0
  680.  
  681.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN LSHIFT_LCTRL_Left = 1 ELSE LSHIFT_LCTRL_Left = 0
  682.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN LSHIFT_LCTRL_Right = 1 ELSE LSHIFT_LCTRL_Right = 0
  683.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(UPkey&) THEN LSHIFT_LCTRL_Up = 1 ELSE LSHIFT_LCTRL_Up = 0
  684.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN LSHIFT_LCTRL_Down = 1 ELSE LSHIFT_LCTRL_Down = 0
  685.  
  686.     'LSHIFT:
  687.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(BACKSPCkey&) THEN LSHIFT_BackSpace = 1 ELSE LSHIFT_BackSpace = 0
  688.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(TABkey&) THEN LSHIFT_TAB = 1 ELSE LSHIFT_TAB = 0
  689.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(SPACEkey&) THEN LSHIFT_SPACE = 1 ELSE LSHIFT_SPACE = 0
  690.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ESCkey&) THEN LSHIFT_ESC = 1 ELSE LSHIFT_ESC = 0
  691.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ENTERkey&) THEN LSHIFT_ENTER = 1 ELSE LSHIFT_ENTER = 0
  692.     'RSHIFT:
  693.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(BACKSPCkey&) THEN RSHIFT_BackSpace = 1 ELSE RSHIFT_BackSpace = 0
  694.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(TABkey&) THEN RSHIFT_TAB = 1 ELSE RSHIFT_TAB = 0
  695.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(SPACEkey&) THEN RSHIFT_SPACE = 1 ELSE RSHIFT_SPACE = 0
  696.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ESCkey&) THEN RSHIFT_ESC = 1 ELSE RSHIFT_ESC = 0
  697.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ENTERkey&) THEN RSHIFT_ENTER = 1 ELSE RSHIFT_ENTER = 0
  698.  
  699.     'LCTRL:
  700.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(SPACEkey&) THEN LCTRL_SPACE = 1 ELSE LCTRL_SPACE = 0
  701.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENTERkey&) THEN LCTRL_ENTER = 1 ELSE LCTRL_ENTER = 0
  702.     'RCTRL:
  703.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(SPACEkey&) THEN RCTRL_SPACE = 1 ELSE RCTRL_SPACE = 0
  704.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(ENTERkey&) THEN RCTRL_ENTER = 1 ELSE RCTRL_ENTER = 0
  705.  
  706.     '_KEYCLEAR
  707.  
  708. SUB ExpandTabs (l$)
  709.     IF INSTR(l$, CHR$(9)) THEN
  710.         TabV% = 8
  711.         b$ = "": f& = 0
  712.         FOR i& = 1 TO LEN(l$)
  713.             IF MID$(l$, i&, 1) = CHR$(9) THEN
  714.                 b$ = b$ + STRING$((f& \ TabV%) * TabV% + TabV% - f&, " ")
  715.                 '  |
  716.                 '  |
  717.                 ' \|/
  718.                 'TabV% - (f% - (f% \ TabV%) * TabV%) =
  719.                 'TabV% - (f% MOD TabV%)
  720.                 f& = (f& \ TabV%) * TabV% + TabV%
  721.             ELSE
  722.                 b$ = b$ + MID$(l$, i&, 1)
  723.                 f& = f& + 1
  724.             END IF
  725.         NEXT
  726.         l$ = b$
  727.     END IF
  728.  
  729. FUNCTION MIN& (YdimROW, filecount)
  730.     IF YdimROW < filecount THEN MIN& = YdimROW ELSE MIN& = filecount
  731.  
  732. FUNCTION AddCommas$ (numeral)
  733.     s$ = LTRIM$(STR$(numeral))
  734.     IF LEN(s$) > 3 THEN
  735.         IF (LEN(s$) MOD 3) THEN x$ = STRING$(3 - (LEN(s$) MOD 3), " ") + s$ ELSE x$ = s$
  736.         s$ = ""
  737.         FOR i = 1 TO LEN(x$) STEP 3
  738.             s$ = s$ + MID$(x$, i, 3) + ","
  739.         NEXT
  740.         s$ = LEFT$(s$, LEN(s$) - 1)
  741.     END IF
  742.     AddCommas$ = LTRIM$(s$)
  743.  
  744. SUB UpdateCLL (l, posit)
  745.     SHARED CLL_Field
  746.     SHARED YdimROW, FileArray$()
  747.     crx = POS(0)
  748.     cry = CSRLIN
  749.     q$ = AddCommas$(LEN(FileArray$(l)))
  750.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Current Line Length: " + q$ + STRING$(CLL_Field - LEN(q$), " ");
  751.     LOCATE cry, crx, 1, 30, 31
  752.  
  753. SUB UpdateNextToCCL_BUSY (posit)
  754.     SHARED YdimROW
  755.     crx = POS(0)
  756.     cry = CSRLIN
  757.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Status: BUSY";
  758.     LOCATE cry, crx, 1, 30, 31
  759.  
  760. SUB UpdateNextToCCL_DONE (posit)
  761.     SHARED YdimROW
  762.     crx = POS(0)
  763.     cry = CSRLIN
  764.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Status: DONE";
  765.     LOCATE cry, crx, 1, 30, 31
  766.  
  767. SUB UpdateCLine (lineToWrite, columnToWrite, FRGR, BACKGR, ln)
  768.     SHARED FileArrayWINDOW$()
  769.     crx = POS(0)
  770.     cry = CSRLIN
  771.     COLOR FRGR, BACKGR
  772.     LOCATE lineToWrite, columnToWrite, 1, 30, 31
  773.     PRINT FileArrayWINDOW$(ln);
  774.     LOCATE cry, crx, 1, 30, 31
  775.  
  776. SUB UpdateWindowFrame (FRGR, BACKGR)
  777.     SHARED YdimROW, filecount, FileArray$(), File_Frame_y, XdimCOL, FileArrayWINDOW$()
  778.     COLOR FRGR, BACKGR
  779.     FOR i = 1 TO MIN&(YdimROW, filecount)
  780.         IF LEN(FileArray$(i + (File_Frame_y - 1))) >= XdimCOL THEN
  781.             FileArrayWINDOW$(i) = MID$(FileArray$(i + (File_Frame_y - 1)), 1, XdimCOL)
  782.         ELSE
  783.             FileArrayWINDOW$(i) = FileArray$(i + (File_Frame_y - 1)) + SPACE$(XdimCOL - LEN(FileArray$(i + (File_Frame_y - 1))))
  784.         END IF
  785.         LOCATE i, 1: PRINT FileArrayWINDOW$(i);
  786.     NEXT
  787.  
  788. SUB ReportTimeToLoad (posit)
  789.     SHARED YdimROW
  790.     SHARED TimeA, TimeB
  791.     crx = POS(0)
  792.     cry = CSRLIN
  793.     LOCATE YdimROW + 1, posit: COLOR 4, 0: PRINT "; Loaded in"; TimeB - TimeA; " seconds.";
  794.     LOCATE cry, crx, 1, 30, 31
  795.  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on January 24, 2021, 01:24:36 pm
Change LINE INPUT to work in BINARY mode — it’s tons faster.  Instead of:

OPEN file$ FOR INPUT AS #1

try:

OPEN file$ FOR BINARY AS #1
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 24, 2021, 01:35:51 pm
Steve is spot on when it comes to using BINARY for speed. Just be sure to keep using your IF _FILEEXISTS condition statement. Unlike OPEN for INPUT, which errors out if the file doesn't exist, Open for BINARY just creates the file. BINARY can also be used to write to the file, but you have to use PUT statements. QB64 added the ability to use LINE INPUT instead of the standard GET statements, so all you have to do is swap out the FOR INPUT to FOR BINARY. Y0u already have the _FILEEXISTS, so you should be good to go.

On a side note, I think I need to move to Bulgaria. Sure, I've only known five, well six people now from that country, but on an intelligence level they are all 10 for 10. Oh don't get me wrong, when it comes to brilliant people, the U.S. is a five-star country too, and one of those stars is half shaded in. Oh, and no comments from the peanut galley that if Pete moves to Bulgaria, then there goes the neighborhood!

Nice coding there Tex,

Pete
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 24, 2021, 04:36:38 pm
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Thank you @SMcNeill  and @Pete , didn't know that LINE INPUT works in BINARY mode.

Now we know that for OED, "tons faster" is roughly 4.1x or 23,187 seconds / 5,571 seconds, see the screenshot.

The attached revision 2+ now differs only in these two lines:

Code: QB64: [Select]
  1. '        OPEN a$ FOR INPUT AS #1
  2.         OPEN a$ FOR BINARY AS #1 ' As suggested by SMcNeill and Pete in https://www.qb64.org/forum/index.php?topic=3518.msg128631#msg128631
  3. ...
  4. '        OPEN a$ FOR INPUT AS #1
  5.         OPEN a$ FOR BINARY AS #1 ' As suggested by SMcNeill and Pete in https://www.qb64.org/forum/index.php?topic=3518.msg128631#msg128631
  6.  

Steve is spot on when it comes to using BINARY for speed. Just be sure to keep using your IF _FILEEXISTS condition statement. Unlike OPEN for INPUT, which errors out if the file doesn't exist, Open for BINARY just creates the file. BINARY can also be used to write to the file, but you have to use PUT statements. QB64 added the ability to use LINE INPUT instead of the standard GET statements, so all you have to do is swap out the FOR INPUT to FOR BINARY. Y0u already have the _FILEEXISTS, so you should be good to go.

Pete, your wording is as it should, much appreciated, the flow, the explanation, just, Mutsi!
Please both with Steve stick around as I intend in next weeks to add slowly more features helping the user with text stats/windows...
Dummy me, looking in my old archives I saved only files as 3D.ASM drawing the windows with shadows, but lost the .BAS files, have to rewrite from .ASM to .BAS, ugh.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Also, the idea is this tool to work on Linux, remotely my brother did run for me QB64 for Linux, the video shows r.2+ scrolling the 15MB long 'Arabian Nights' file on one old laptop with 1366x768 resolution, notice how the window fits in:



YouTube butchered the scroll after rendering it, so the original .MKV is on my Internet Drive:
https://drive.google.com/file/d/1RvMejR3cb_IWBSr3Jw94c4cIBd8oKa8Y/view?usp=sharing (https://drive.google.com/file/d/1RvMejR3cb_IWBSr3Jw94c4cIBd8oKa8Y/view?usp=sharing)

In the attached r.2+ package, there is MASAKARI_64bit.elf (468,660 bytes) - the *nix executable (static, stripped, compressed with upx).
Latest Fedora 33 was used, very glad that QB64 is *nix friendly.

My cameraman (my brother) did fine job filming it, I am impressed with the quality of capturing, no tearing, no frame dropping, so glad that my Text Sidekick will work on Linux as well.

As for Bulgarians, I beg to differ, most of my countrymen are disgrace to the Bulgarian spirit, and that is to put it mildly. To me, "intelligence" means little, many smartasses are out there, the kind-and-appreciative mindset is what I seek and love in humans.
To me, Bulgaria is a wonderful part of the Earth, however soullessness is rampant here, the soulful people are minority, as everywhere I guess... nah, except Nihon.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 24, 2021, 04:56:33 pm
I'm a bit of both. I have the kind part going, as in I'm kind of a smartass.

Glad you made use of BINARY, but ouch on having to go from ASM to BASIC. I coded a C/C++ WP routine I wrote back into BASIC once. It was just about like rewriting the whole thing, too.

We'll stay in touch,

Pete

Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on January 24, 2021, 05:55:12 pm
If you want the absolute fastest way to input a file (and it sounds like you would, with such a large file), read and then parse it.  I’m not at home with my PC until tomorrow, but your basic pseudocode is:

OPEN file$ FOR BINARY AS #1
text$ = SPACE$(LOF(1))
GET #1, 1, text$ ‘read the whole file at once
CLOSE

DO
    parse text$ for CRLF characters (usually CHR$(10) and CHR$(13), in some combination)*
LOOP until all of text$ is parsed

I’ve posted countless examples of this process on the forums before, so a search should find one with a little digging.

Overall time speeds will be quite a bit faster than reading over and over from the drive, but exact improvements depend on drive speed vs memory speed.  (For example, a SSD would see less improvement than a 5200RPM drive)

With extremely large files, I’d definitely suggest the read-and-parse method to load the whole file.



*Windows usually has CHR$(13) + CHR$(10) line endings.  Linux/Newer Mac (above version 9) use CHR$(10).  Legacy Mac (before version 9) use CHR$(13).

I’d check the file for which of those the file contains, and then parse for it as your line delimiter.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on January 24, 2021, 06:09:35 pm
Another trick:

Code: [Select]
REDIM FileArray$(1 TO 100000)


    LongestLine = 0
    IF _FILEEXISTS(a$) THEN
        PRINT: PRINT "Loading..."
        _DISPLAY
        filecount = 0
        OPEN a$ FOR BINARY AS #1
        DO UNTIL EOF(1)
            LINE INPUT #1, l$
            filecount = filecount + 1


            IF UBOUND(FileArray$) < filecount THEN REDIM _PRESERVE FileArray$(1 TO UBOUND(FileArray$) + 100000)
            LINE INPUT #1, FileArray$(filecount)
            IF LEN(FileArray$(filecount))) > LongestLine THEN LongestLine = LEN(FileArray$(filecount))

        LOOP
        CLOSE #1
        REDIM FileArray$(1 TO filecount)

You are now reading and assigning your file to your array in a single pass, rather than having to read it once (to count lines), and then read it a second time (to assign it to your array).

Half the disk reads, twice the speed.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 26, 2021, 12:46:36 am
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

In this revision 3+, some changes were made, as:

- removing the flashing window when command line option as "/help" or "-h" are used;
- removing the PLAY statement, it has some dependencies on Linux;
- fixing the path during loading the file, I guess _CWD$ and _STARTDIR$ have to be swapped;

@SMcNeill Thanks, your suggestions got me thinking how to solve the whole "load crisis" in one sweep, didn't have enough time to play with it, in next days I hope will end the crisis by removing usage of strings altogether, I intend to use you malloc-like approach
Code: QB64: [Select]
  1. text$ = SPACE$(LOF(1))

and manually find lines' endings. Also your MACOS comment about CR endings prompted for parsing in a way to handle all the CRLF, LF, CR texts, maybe will replace every LF with CR unless it is paired in CRLF, in that case just skipping it. Thus we would have a modified text file having only CR as a ending.

In order to have tons faster loading, loading in 5000+ seconds should be dropped to 5 seconds, a ton being a thousand, you know. Will deal with this in next days, for now another thing interests me, making the simplistic-and-universal "File Load Menu List", universal, thanks to a tool I wrote (forked from the awesome WATCOM C) many years ago which works exactly the same with Windows and Linux, it is called Yoshi.exe or Youshi.elf, the .C source is also included in the attached to this post package. Basically, it lists all the files in current folder recursively, that is, giving us (optionally with full paths) a list ready to be used in Masakari, thus in next revisions I will make the loading of a file (both on Windows and Linux) the same and a CAKEWALK - just running some script (here m.bat) and scrolling within the filelist, pressing Enter and then loading this file in the very same window. This is my conception for dealing with problems - writing a dedicated module in .C and running it from a GUI, or outside before entering the GUI. In the incoming revisions many problems were solved already in superfast fashion, so Masakari will only invoke them.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Code: QB64: [Select]
  1. ' Masakari.bas (DragDropWheelScroller.bas)
  2. ' written in QB64 v1.4 by Kaze, 2021-Jan-25
  3. ' Thanks go to the www.qb64.org/forum members for sharing useful excerpts/etudes
  4. ' Wow, this is nice indeed: http://www.qb64.org/wiki/Windows_Libraries
  5.  
  6. ' Currently are implemented only:
  7. ' Mouse:
  8. '       Button 1 - sets the cursor and the inverse line to the chosen position
  9. '       Button 3 - PgDn
  10. '       Wheel Up - Up
  11. '       Wheel Dn - Dn
  12. ' Keyboard:
  13. '        Up
  14. '        Down
  15. '        Left - still no sideways scroll
  16. '        Right - still no sideways scroll
  17. '        LCtrl+Home - going to the top left position
  18. '        LCtrl+End  - going to the bottom left position
  19. '        Alt+x or Alt+q - quit to the system, without demanding keypress.
  20.  
  21. _TITLE "MASAKARI 128x60, The 'Holy Axe' English Text Sidekick"
  22. $EXEICON:'ColumnChart.ico'
  23. CONST RSHIFTkey& = 100303
  24. CONST LSHIFTkey& = 100304
  25. CONST RCTRLkey& = 100305
  26. CONST LCTRLkey& = 100306
  27. CONST RALTkey& = 100307
  28. CONST LALTkey& = 100308
  29.  
  30. CONST BACKSPCkey& = 8
  31. CONST TABkey& = 9
  32. CONST SPACEkey& = 32
  33. CONST ESCkey& = 27
  34. CONST ENTERkey& = 13
  35.  
  36. CONST HOMEkey& = 18176
  37. CONST ENDkey& = 20224
  38.  
  39. CONST INSkey& = 20992
  40. CONST DELkey& = 21248
  41.  
  42. CONST PGUPkey& = 18688
  43. CONST PGDNkey& = 20736
  44.  
  45. CONST LEFTkey& = 19200
  46. CONST RIGHTkey& = 19712
  47. CONST UPkey& = 18432
  48. CONST DOWNkey& = 20480
  49.  
  50.     $CONSOLE
  51.     _CONSOLE ON
  52.     _CONSOLETITLE "Masakari console window"
  53.     PRINT "Masakari, revision 3+, written in QB64 by Kaze"
  54.     $IF WINDOWS THEN
  55.         PRINT "Usage: Masakari filename|/help"
  56.     $ELSE
  57.         PRINT "Usage: Masakari filename|-h"
  58.     $END IF
  59.     SYSTEM
  60.     '_CONSOLE OFF
  61.     '_SCREENSHOW
  62.     _SCREENSHOW ' Why so?!
  63.     $CONSOLE
  64.  
  65. 'DEFLNG A-Z
  66. '_DEFINE A-Z AS _UNSIGNED _INTEGER64
  67.  
  68. $IF WINDOWS THEN
  69.     DECLARE LIBRARY "mem"
  70.         FUNCTION MemInUsePercent~&&
  71.         FUNCTION TotalPhysicalMem~&&
  72.         FUNCTION FreePhysicalMem~&&
  73.         FUNCTION TotalPagingFile~&&
  74.         FUNCTION FreePagingFile~&&
  75.         FUNCTION TotalVirtualMem~&&
  76.         FUNCTION FreeVirtualMem~&&
  77.         FUNCTION FreeExtendedMem~&&
  78.         FUNCTION GetCPULoad#
  79.     END DECLARE
  80.  
  81. XdimCOL = 128
  82. YdimROW = 40 ' ensure old laptops with 768pixels vertical will hold the whole window
  83. IF high& > 1000 THEN YdimROW = 60
  84. handle& = _NEWIMAGE(XdimCOL, YdimROW + 1, 0)
  85. SCREEN handle&
  86. _DEST handle&
  87.  
  88. ' _DEST 0 refers to the present program SCREEN. You can use 0 to refer to the present program
  89. '  SCREEN.
  90.  
  91. '_FONT 16 'wish we could use the old 8x16 bitmap/raster fonts from DOS times...
  92.  
  93. ' Either one must be uncommented:
  94. '_AUTODISPLAY 'no need of refreshing
  95.  
  96. PurpleFlag = 0
  97. 'PurpleFlag = 1
  98.  
  99. NormalFRGr = 3
  100. IF PurpleFlag THEN NormalFRGr = 9
  101. NormalBCKGr = 0
  102. IF PurpleFlag THEN NormalBCKGr = 0
  103.  
  104. InverseFRGr = 0
  105. IF PurpleFlag THEN InverseFRGr = 8
  106. InverseBCKGr = 3
  107. IF PurpleFlag THEN InverseBCKGr = 0
  108.  
  109. COLOR NormalFRGr, NormalBCKGr
  110.  
  111. 'Ugh, they are reversed?!
  112. 'PRINT "Current working directory path: "; CHR$(34); _CWD$; CHR$(34)
  113. 'PRINT "User's program calling path: "; CHR$(34); _STARTDIR$; CHR$(34)
  114. PRINT "Current working directory path: "; CHR$(34); _STARTDIR$; CHR$(34)
  115. PRINT "User's program calling path: "; CHR$(34); _CWD$; CHR$(34)
  116. PRINT "Command line parameters sent when a program is started: "; CHR$(34); COMMAND$; CHR$(34)
  117. PRINT "_OS$="; _OS$
  118.  
  119. 'Y = CSRLIN 'save the row
  120. 'X = POS(0) 'save the column
  121.  
  122. REDIM FileArray$(1) 'create dynamic array: 3880000 alocates 532MB - bigger values need 570+MB and give "Out Of Memory"
  123. DIM FileArrayWINDOW$(YdimROW)
  124.  
  125. $IF WINDOWS THEN
  126.     _ACCEPTFILEDROP 'enables drag/drop functionality
  127.     IF COMMAND$ = "" THEN PRINT: PRINT "Drag files from a folder and drop them in this window...": PRINT
  128.  
  129. 'pressakey$ = INPUT$(1)
  130.  
  131. a$ = ""
  132. PostfixedToHeader = CSRLIN
  133.  
  134.     LOCATE PostfixedToHeader, 1
  135.  
  136.     $IF WINDOWS THEN
  137.         ' MEMUSAGE by Steve [
  138.         ' GetCPULoad = 0 is idle, 1 is fully used.
  139.         '  Multiply by 100 for a percentage
  140.         PRINT "CPU used:              "; LTRIM$(STR$(INT((GetCPULoad * 10000) / 100))); "%"; SPACE$(18)
  141.         PRINT "Memory used:           "; LTRIM$(STR$(MemInUsePercent)); "%"; SPACE$(18)
  142.         PRINT "Total Physical Memory: ";
  143.         PRINT AddCommas$(TotalPhysicalMem); " bytes"; SPACE$(18)
  144.         PRINT "Free Physical Memory:  ";
  145.         PRINT AddCommas$(FreePhysicalMem); " bytes"; SPACE$(18)
  146.         PRINT "Total Paging File:     ";
  147.         PRINT AddCommas$(TotalPagingFile); " bytes"; SPACE$(18)
  148.         PRINT "Free Paging File:      ";
  149.         PRINT AddCommas$(FreePagingFile); " bytes"; SPACE$(18)
  150.         PRINT "Total Virtual Memory:  ";
  151.         PRINT AddCommas$(TotalVirtualMem); " bytes"; SPACE$(18)
  152.         PRINT "Free Virtual Memory:   ";
  153.         PRINT AddCommas$(FreeVirtualMem); " bytes"; SPACE$(18)
  154.         'PRINT "Free Extended Virtual Memory:"
  155.         'PRINT "  "; FreeExtendedMeml; " bytes"
  156.         ' MEMUSAGE by Steve ]
  157.     $END IF
  158.  
  159.     IF COMMAND$ = "" THEN PRINT: PRINT "May press Alt+X or Alt+Q to eXit/Quit..."
  160.     ReturnCOMBO
  161.     _DISPLAY
  162.  
  163.     $IF WINDOWS THEN
  164.             'FOR i = 1 TO _TOTALDROPPEDFILES
  165.             'a$ = _DROPPEDFILE(i)
  166.             a$ = _DROPPEDFILE(1)
  167.             'NEXT'
  168.             _FINISHDROP 'If _FINISHDROP isn't called here then _TOTALDROPPEDFILES never gets reset.
  169.             'ELSE
  170.             'a$ = "Scroller.$$$"
  171.             'SHELL _HIDE "DIR /B *.* > Scroller.$$$"
  172.         END IF
  173.     $END IF
  174.     $IF WINDOWS THEN
  175.         IF COMMAND$ <> "" THEN a$ = _STARTDIR$ + "\" + COMMAND$
  176.     $ELSE
  177.         IF COMMAND$ <> "" THEN a$ = _STARTDIR$ + "/" + COMMAND$
  178.     $END IF
  179.  
  180.     'WrapFlag = 0
  181.     'Wwidth% = XdimCOL
  182.     'ul& = 0
  183.     'LongestLine = 0
  184.     'DO WHILE NOT EOF(1)
  185.     '    LINE INPUT #1, l$: ul& = ul& + 1
  186.     '    ExpandTabs l$
  187.     '    IF LEN(l$) > LongestLine THEN LongestLine = LEN(l$)
  188.     '    IF WrapFlag THEN
  189.     '        lX$ = l$
  190.     '        DO WHILE LEN(lX$) > Wwidth%
  191.     '            Glupak% = Wwidth%
  192.     '            DO UNTIL MID$(lX$, Glupak% + 1, 1) = " " AND MID$(lX$, Glupak%, 1) <> " "
  193.     '                Glupak% = Glupak% - 1
  194.     '                IF Glupak% = 0 THEN
  195.     '                    PRINT "Rejecting line(#"; LTRIM$(STR$(ul&)); ", "; LTRIM$(STR$(LEN(l$))); "chars) that cannot be wrapped!"
  196.     '                    _DISPLAY: SYSTEM
  197.     '                    GOTO B4Txpanar
  198.     '                END IF
  199.     '            LOOP
  200.     '            PRINT #3, LEFT$(lX$, Glupak%)
  201.     '            lX$ = STRING$(1, " ") + LTRIM$(MID$(lX$, Glupak% + 1, LEN(lX$) - (Glupak%)))
  202.     '        LOOP
  203.     '        PRINT #3, lX$
  204.     '        B4Txpanar:
  205.     '    END IF
  206.     'LOOP
  207.  
  208. TimeA = TIMER
  209.  
  210.     LongestLine = 0
  211.     IF _FILEEXISTS(a$) THEN
  212.         PRINT: PRINT "Loading..."
  213.         _DISPLAY
  214.         filecount = 0
  215.         '        OPEN a$ FOR INPUT AS #1
  216.         OPEN a$ FOR BINARY AS #1 ' As suggested by SMcNeill and Pete in https://www.qb64.org/forum/index.php?topic=3518.msg128631#msg128631
  217.         DO UNTIL EOF(1)
  218.             LINE INPUT #1, l$
  219.             filecount = filecount + 1
  220.         LOOP
  221.         CLOSE #1
  222.         REDIM FileArray$(1 TO filecount)
  223.         filecount = 0
  224.         '        OPEN a$ FOR INPUT AS #1
  225.         OPEN a$ FOR BINARY AS #1 ' As suggested by SMcNeill and Pete in https://www.qb64.org/forum/index.php?topic=3518.msg128631#msg128631
  226.         FileSize = LOF(1)
  227.         DO UNTIL EOF(1)
  228.             LINE INPUT #1, l$
  229.             ExpandTabs l$
  230.             FOR j = 1 TO LEN(l$)
  231.                 IF MID$(l$, j, 1) < CHR$(32) THEN MID$(l$, j, 1) = CHR$(32)
  232.             NEXT j
  233.             IF LEN(l$) > LongestLine THEN LongestLine = LEN(l$)
  234.             filecount = filecount + 1
  235.             FileArray$(filecount) = l$
  236.         LOOP
  237.         CLOSE #1
  238.     END IF
  239.     _LIMIT 5
  240.     'IF INKEY$ = CHR$(27) THEN SYSTEM
  241.     'IF keycode& = 27 THEN SYSTEM
  242.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(81) OR _KEYDOWN(113)) THEN SYSTEM
  243.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(88) OR _KEYDOWN(120)) THEN SYSTEM
  244.  
  245.     '                            QB64 _KEYHIT and _KEYDOWN Values
  246.     '
  247.     'Esc  F1    F2    F3    F4    F5    F6    F7    F8    F9    F10   F11   F12   Sys  ScL Pause
  248.     ' 27 15104 15360 15616 15872 16128 16384 16640 16896 17152 17408 34048 34304 +316 +302 +019
  249.     '`~  1!  2@  3#  4$  5%  6^  7&  8*  9(  0) -_ =+ BkSp   Ins   Hme   PUp   NumL   /     *    -
  250.     '126 33  64  35  36  37  94  38  42  40  41 95 43   8   20992 18176 18688 +300   47    42   45
  251.     ' 96 49  50  51  52  53  54  55  56  57  48 45 61
  252.     'Tab Q   W   E   R   T   Y   U   I   O   P  [{  ]}  \|   Del   End   PDn   7Hme  8/?   9PU   +
  253.     ' 9  81  87  69  82  84  89  85  73  79  80 123 125 124 21248 20224 20736 18176 18432 18688 43
  254.     '   113 119 101 114 116 121 117 105 111 112  91  93  92                    55    56    57
  255.     'CapL   A   S   D   F   G   H   J   K   L   ;:  '" Enter                   4/?-   5    6/-?
  256.     '+301   65  83  68  70  71  72  74  75  76  58  34  13                    19200 19456 19712  E
  257.     '       97 115 100 102 103 104 106 107 108  59  39                         52    53    54    n
  258.     'Shift   Z   X   C   V   B   N   M   ,<  .>  /?    Shift       ?           1End  2/?   3PD   t
  259.     '+304   90  88  67  86  66  78  77  60  62  63    +303       18432        20224 20480 20736  e
  260.     '      122 120  99 118  98 110 109  44  46  47                             49    50    51    r
  261.     'Ctrl   Win  Alt     Spacebar      Alt  Win  Menu  Ctrl   ?-   ?   -?      0Ins        .Del
  262.     '+306  +311 +308       32         +307 +312 +319  +305 19200 20480 19712  20992       21248 13
  263.     '                                                                          48          46
  264.     '         Lower value = LCase/NumLock On __________________ + = add 100000
  265.  
  266. LOOP WHILE a$ = ""
  267.  
  268. TimeB = TIMER
  269. 'PLAY "L8V2a-c-" 'removed in order to get rid of audio dependency
  270. CurrentLine = 1
  271. FOR i = 1 TO YdimROW
  272.     LOCATE i, 1: PRINT SPACE$(XdimCOL);
  273. FOR i = 1 TO MIN&(YdimROW, filecount)
  274.     IF LEN(FileArray$(i)) >= XdimCOL THEN
  275.         FileArrayWINDOW$(i) = MID$(FileArray$(i), 1, XdimCOL)
  276.     ELSE
  277.         FileArrayWINDOW$(i) = FileArray$(i) + SPACE$(XdimCOL - LEN(FileArray$(i)))
  278.     END IF
  279.     LOCATE i, 1: PRINT FileArrayWINDOW$(i);
  280.  
  281. ' Here is the layout:
  282. ' The window-frame is 1..crx or 1..128 |  The file-frame is 1..LongestLine
  283. '                     .         .      |                    .
  284. '                     .         .      |                    .
  285. '                     cry       60     |                    filecount
  286. '              FileArrayWINDOW$(60)    |          FileArray(filecount)
  287. ' if File_Frame_x < 128 then PADDING to 128 else File_Frame_x = 1..LongestLine-(128-1)
  288. ' if File_Frame_y < 60 then PADDING to 60 else File_Frame_y = 1..filecount-(60-1)
  289.  
  290. UpdateCLine 1, 1, InverseFRGr, InverseBCKGr, 1
  291. StatuLine$ = SPACE$(XdimCOL)
  292. MID$(StatuLine$, 1, 1) = "["
  293. MID$(StatuLine$, XdimCOL, 1) = "]"
  294.  
  295. Dumbo$ = "File Size: " + AddCommas$(FileSize) + "; Longest Line: " + AddCommas$(LongestLine) + "; Total Lines: " + AddCommas$(filecount)
  296. MID$(StatuLine$, 2, LEN(Dumbo$)) = Dumbo$
  297. LOCATE YdimROW + 1, 1: COLOR 9, 0: PRINT StatuLine$;
  298. UpdateCLL CurrentLine, LEN(Dumbo$) + 1 + 1
  299. CLL_Field = LEN(AddCommas$(LongestLine))
  300. MostRightField = LEN(Dumbo$) + 1 + 1 + (LEN("; Current Line Length: ") + CLL_Field)
  301. UpdateNextToCCL_DONE MostRightField
  302.  
  303. LOCATE 1, 1, 1, 30, 31
  304. crx = POS(0)
  305. cry = CSRLIN
  306. crxOLD = crx
  307. cryOLD = cry
  308. File_Frame_x = 1
  309. File_Frame_y = 1
  310.  
  311.     ReturnCOMBO
  312.     IF LSHIFT_RSHIFT THEN
  313.         'PLAY "L4V2f" 'removed in order to get rid of audio dependency
  314.         _KEYCLEAR
  315.         ReportTimeToLoad MostRightField
  316.         _DISPLAY
  317.     END IF
  318.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(81) OR _KEYDOWN(113)) THEN SYSTEM
  319.     IF (_KEYDOWN(LALTkey&) OR _KEYDOWN(RALTkey&)) AND (_KEYDOWN(88) OR _KEYDOWN(120)) THEN SYSTEM
  320.     key$ = INKEY$
  321.     'DO: a$ = INKEY$: LOOP UNTIL a$ <> "" ' prevent ASC empty string read error
  322.     IF key$ <> "" THEN
  323.         code% = ASC(key$):
  324.         IF code% THEN ' ASC returns any value greater than 0
  325.             SELECT CASE ASC(key$)
  326.                 CASE 65 TO 97: 'PRINT key$;
  327.                 CASE ASC("a") TO ASC("z"): 'PRINT key$;
  328.                     'CASE 27: COLOR 7, 0: SYSTEM 'END
  329.             END SELECT
  330.         ELSE
  331.             SELECT CASE ASC(key$, 2)
  332.                 CASE 72:
  333.                     IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  334.                     IF cry > 1 THEN
  335.                         cry = cry - 1 'up
  336.                     ELSE 'scrolling is needed
  337.                         IF File_Frame_y > 1 THEN File_Frame_y = File_Frame_y - 1
  338.                         UpdateWindowFrame NormalFRGr, NormalBCKGr
  339.                     END IF
  340.                 CASE 80:
  341.                     IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  342.                     IF cry < YdimROW THEN
  343.                         IF cry < filecount THEN cry = cry + 1 'down
  344.                     ELSE 'scrolling is needed
  345.                         IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  346.                         UpdateWindowFrame NormalFRGr, NormalBCKGr
  347.                     END IF
  348.                 CASE 75: IF crx > 1 THEN crx = crx - 1 'left
  349.                 CASE 77: IF crx < XdimCOL THEN crx = crx + 1 'right
  350.             END SELECT
  351.         END IF
  352.     END IF
  353.     IF cryOLD <> cry THEN
  354.         UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  355.         cryOLD = cry
  356.     ELSE 'it 'cry' could be changed by Mouse Wheel too, check it
  357.         AsIfItIsINKEY% = _MOUSEINPUT '      Check the mouse status
  358.         IF _MOUSEWHEEL = 1 THEN ' as if Down
  359.             IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  360.             IF cry < YdimROW THEN
  361.                 IF cry < filecount THEN cry = cry + 1 'down
  362.             ELSE 'scrolling is needed
  363.                 IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  364.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  365.             END IF
  366.         END IF
  367.         IF _MOUSEWHEEL = -1 THEN ' as if Up
  368.             IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  369.             IF cry > 1 THEN
  370.                 cry = cry - 1 'up
  371.             ELSE 'scrolling is needed
  372.                 IF File_Frame_y > 1 THEN File_Frame_y = File_Frame_y - 1
  373.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  374.             END IF
  375.         END IF
  376.         IF _MOUSEBUTTON(1) THEN
  377.             crxOLD = crx
  378.             cryOLD = cry
  379.             cry = _MOUSEY
  380.             crx = _MOUSEX
  381.             UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  382.             DO WHILE cryOLD > cry
  383.                 cryOLD = cryOLD - 1
  384.                 IF CurrentLine > 1 THEN CurrentLine = CurrentLine - 1
  385.             LOOP
  386.             DO WHILE cryOLD < cry
  387.                 cryOLD = cryOLD + 1
  388.                 IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  389.             LOOP
  390.         END IF
  391.         IF _MOUSEBUTTON(3) THEN 'PgDn - just add the page height i.e. 'YdimROW' to 'File_Frame_y'
  392.             ' Don't execute PgDn (advancing the 'CurrentLine') if 'File_Frame_y' is not "eligible":
  393.             'IF File_Frame_y < filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  394.             'IF File_Frame_y + 1 <= filecount - (YdimROW - 1) THEN File_Frame_y = File_Frame_y + 1
  395.             'CAUTION [
  396.             ' Next three line beep NOT
  397.             'DEFLNG A-Z
  398.             'aaa = 61
  399.             'bbb = -48
  400.             'IF aaa <= bbb THEN BEEP: END
  401.             'Next three line beep
  402.             'aaa~& = 61
  403.             'bbb~& = -48
  404.             'IF aaa~& <= bbb~& THEN BEEP: END
  405.             'Next three line beep NOT
  406.             'aaa& = 61
  407.             'bbb& = -48
  408.             'IF aaa& <= bbb& THEN BEEP: END
  409.             'Next line works even when unsigned!
  410.             'IF File_Frame_y + YdimROW - (filecount - (YdimROW - 1)) <= 0 THEN
  411.             'CAUTION ]
  412.             'Next line doesn't work when unsigned!
  413.             IF File_Frame_y + YdimROW <= filecount - (YdimROW - 1) THEN
  414.                 File_Frame_y = File_Frame_y + YdimROW
  415.                 'IF CurrentLine < filecount THEN CurrentLine = CurrentLine + 1
  416.                 'IF CurrentLine + 1 <= filecount THEN CurrentLine = CurrentLine + 1
  417.                 IF CurrentLine + YdimROW <= filecount THEN CurrentLine = CurrentLine + YdimROW
  418.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  419.             END IF
  420.         END IF
  421.     END IF
  422.     IF cryOLD <> cry THEN
  423.         UpdateCLine cryOLD, 1, NormalFRGr, NormalBCKGr, cryOLD
  424.         cryOLD = cry
  425.     END IF
  426.     IF LCTRL_HOME THEN
  427.         LOCATE 1, 1, 1, 30, 31
  428.         crx = POS(0)
  429.         cry = CSRLIN
  430.         crxOLD = crx
  431.         cryOLD = cry
  432.         File_Frame_x = 1
  433.         File_Frame_y = 1
  434.         CurrentLine = 1
  435.         UpdateWindowFrame NormalFRGr, NormalBCKGr
  436.     END IF
  437.     IF LCTRL_END THEN
  438.         IF filecount >= YdimROW THEN
  439.             IF filecount - (YdimROW - 1) THEN
  440.                 LOCATE YdimROW, 1, 1, 30, 31
  441.                 crx = POS(0)
  442.                 cry = CSRLIN
  443.                 crxOLD = crx
  444.                 cryOLD = cry
  445.                 File_Frame_x = 1
  446.                 File_Frame_y = filecount - (YdimROW - 1)
  447.                 CurrentLine = filecount
  448.                 UpdateWindowFrame NormalFRGr, NormalBCKGr
  449.             END IF
  450.         ELSE
  451.             LOCATE filecount, 1, 1, 30, 31
  452.             crx = POS(0)
  453.             cry = CSRLIN
  454.             crxOLD = crx
  455.             cryOLD = cry
  456.             File_Frame_x = 1
  457.             File_Frame_y = 1
  458.             CurrentLine = filecount
  459.             UpdateWindowFrame NormalFRGr, NormalBCKGr
  460.         END IF
  461.     END IF
  462.  
  463.     LOCATE cry, crx, 1, 30, 31
  464.     UpdateCLine cry, 1, InverseFRGr, InverseBCKGr, cry
  465.     UpdateCLL CurrentLine, LEN(Dumbo$) + 1 + 1
  466.     _DISPLAY
  467.     'DO WHILE INKEY$ <> "": LOOP ' have to clear the keyboard buffer
  468.     _LIMIT 500 '_LIMIT 30 'commented because the wheel up/down was not working?!
  469.  
  470.  
  471.  
  472. '_TITLE "Mouse Feedback"
  473. 'DO
  474. '    DO WHILE _MOUSEINPUT '      Check the mouse status
  475. '        PRINT _MOUSEX, _MOUSEY, _MOUSEBUTTON(1); _MOUSEBUTTON(2); _MOUSEBUTTON(3), _MOUSEWHEEL
  476. '    LOOP
  477. 'LOOP UNTIL INKEY$ <> ""
  478.  
  479. 'Syntax:
  480. 'infoExists%% = _MOUSEINPUT
  481.  
  482. 'Description:
  483. '- Returns -1 if new mouse information is available, otherwise it returns 0.
  484. '- Must be called before reading any of the other mouse functions. The function will not miss any
  485. '  mouse input even during an INPUT entry.
  486. '- Use in a loop to monitor the mouse buttons, scroll wheel and coordinate positions.
  487. '-  To clear all previous mouse data, use _MOUSEINPUT in a loop until it returns 0.
  488.  
  489.  
  490.  
  491. ' _FONT (function) creates a new alphablended font handle from a designated image handle
  492. ' _FONT (statement) sets the current _LOADFONT function font handle to be used by PRINT or
  493. '  _PRINTSTRING.
  494. ' _FONTHEIGHT (function) returns the font height of a font handle created by _LOADFONT.
  495. ' _FONTWIDTH (function) returns the font width of a MONOSPACE font handle created by _LOADFONT.
  496. ' _FREEFONT (statement) frees a font handle value from memory
  497. ' _LOADFONT (function) loads a TrueType font (.TTF) file of a specific size and style and returns
  498. '  a font handle value.
  499.  
  500. ' _DISPLAY (statement) turns off automatic display while only displaying the screen changes when
  501. '  called.
  502.  
  503. ' SHELL (QB64 function) executes a DOS command or calls another program. Returns codes sent by END
  504. '  or SYSTEM.
  505. ' _SHELLHIDE (function) hides a DOS command or call to another program. Returns codes sent by END
  506. '  or SYSTEM.
  507.  
  508.  
  509. ' _CWD$ (function) returns the current working directory path as a STRING.
  510. ' _DONTWAIT (SHELL action) allows the program to continue without waiting for the other program to
  511. '  close.
  512. ' _FILEEXISTS (function) returns -1 if the file name string parameter exists. Zero if it does not.
  513. ' _HIDE (SHELL action) hides the DOS screen output during a shell.
  514.  
  515. ' _SHELLHIDE (function) executes a DOS command or calls another program. Returns codes sent by END
  516. '  or SYSTEM.
  517. ' _STARTDIR$ (function) returns the user's program calling path as a STRING.
  518.  
  519.  
  520.  
  521. 'The _MEMNEW function allocates new memory and returns a _MEM memory block referring to it.
  522.  
  523. 'Syntax:
  524. '     memoryBlock = _MEMNEW(byteSize)
  525.  
  526. '- The byteSize parameter is the desired byte size of the memory block based on the variable type
  527. '  it will hold.
  528.  
  529. 'Description:
  530. '- The memoryBlock value created holds the elements .OFFSET, .SIZE, .TYPE and .ELEMENTSIZE.
  531. '- _MEMNEW does not clear the data previously in the memory block it allocates, for speed purposes.
  532. '- To clear previous data from a new memory block, use _MEMFILL with a byte value of 0.
  533. '- When a new memory block is created the memory .TYPE value will be 0.
  534. '- If the read only memory block .SIZE is 0, the memory block was not created.
  535. '- All values created by memory functions must be freed using _MEMFREE with a valid _MEM variable.
  536.  
  537. 'Code Examples:
  538. 'Example: Shows how SINGLE numerical values can be passed, but non-fixed STRING lengths cannot get
  539. 'the value.
  540.  
  541. 'DIM m AS _MEM
  542. 'DIM f AS STRING * 5
  543. 'm = _MEMNEW(5) 'create new memory block of 5 bytes
  544. 'a = 12345.6
  545. '_MEMPUT m, m.OFFSET, a 'put single value
  546. '_MEMGET m, m.OFFSET, b 'get single value
  547. 'PRINT "b = "; b
  548. 'c$ = "Doggy"
  549. '_MEMPUT m, m.OFFSET, c$ 'put 5 byte string value
  550. '_MEMGET m, m.OFFSET, d$ 'get unfixed length string value
  551. '_MEMGET m, m.OFFSET, f  'get 5 byte string value
  552. 'e$ = _MEMGET(m, m.OFFSET, STRING * 5) 'get 5 byte string value
  553. 'PRINT "d$ = "; d$; LEN(d$) 'prints empty string
  554. 'PRINT "e$ = "; e$; LEN(e$)
  555. 'PRINT "f = "; f; LEN(f)
  556.  
  557.  
  558.  
  559. ''OPENICON.BAS
  560. ''============
  561. ''Maximizes a minimized program using WinAPI.
  562. ''By Dav, DEC/2020
  563.  
  564. 'DECLARE DYNAMIC LIBRARY "user32"
  565. '    FUNCTION OpenIcon& (BYVAL hwnd AS LONG)
  566. 'END DECLARE
  567.  
  568. 'PRINT
  569. 'PRINT "Minimize this program at it will pop back up in 2 secs."
  570.  
  571. 'DO
  572. '    IF _SCREENICON THEN
  573. '        SLEEP 2: x& = OpenIcon&(_WINDOWHANDLE)
  574. '    END IF
  575. 'LOOP
  576.  
  577. ' http://www.qb64.org/wiki/CONSOLETITLE
  578. 'Example: Hiding the main program window while displaying the console window with a title.
  579.  
  580. SUB ReturnCOMBO
  581.     SHARED LSHIFT_RSHIFT
  582.     SHARED LCTRL_RCTRL
  583.     SHARED LALT_RALT
  584.  
  585.     SHARED LALT_HOME
  586.     SHARED LALT_END
  587.  
  588.     SHARED LALT_INS
  589.     SHARED LALT_DEL
  590.  
  591.     SHARED LALT_PGUP
  592.     SHARED LALT_PGDN
  593.  
  594.     SHARED LALT_Left
  595.     SHARED LALT_Right
  596.     SHARED LALT_Up
  597.     SHARED LALT_Down
  598.  
  599.     SHARED RALT_HOME
  600.     SHARED RALT_END
  601.  
  602.     SHARED RALT_INS
  603.     SHARED RALT_DEL
  604.  
  605.     SHARED RALT_PGUP
  606.     SHARED RALT_PGDN
  607.  
  608.     SHARED RALT_Left
  609.     SHARED RALT_Right
  610.     SHARED RALT_Up
  611.     SHARED RALT_Down
  612.  
  613.     SHARED LSHIFT_HOME
  614.     SHARED LSHIFT_END
  615.  
  616.     SHARED LSHIFT_INS
  617.     SHARED LSHIFT_DEL
  618.  
  619.     SHARED LSHIFT_PGUP
  620.     SHARED LSHIFT_PGDN
  621.  
  622.     SHARED LSHIFT_Left
  623.     SHARED LSHIFT_Right
  624.     SHARED LSHIFT_Up
  625.     SHARED LSHIFT_Down
  626.  
  627.     SHARED RSHIFT_HOME
  628.     SHARED RSHIFT_END
  629.  
  630.     SHARED RSHIFT_INS
  631.     SHARED RSHIFT_DEL
  632.  
  633.     SHARED RSHIFT_PGUP
  634.     SHARED RSHIFT_PGDN
  635.  
  636.     SHARED RSHIFT_Left
  637.     SHARED RSHIFT_Right
  638.     SHARED RSHIFT_Up
  639.     SHARED RSHIFT_Down
  640.  
  641.     SHARED LCTRL_HOME
  642.     SHARED LCTRL_END
  643.  
  644.     SHARED LCTRL_INS
  645.     SHARED LCTRL_DEL
  646.  
  647.     SHARED LCTRL_PGUP
  648.     SHARED LCTRL_PGDN
  649.  
  650.     SHARED LCTRL_Left
  651.     SHARED LCTRL_Right
  652.     SHARED LCTRL_Up
  653.     SHARED LCTRL_Down
  654.  
  655.     SHARED RCTRL_HOME
  656.     SHARED RCTRL_END
  657.  
  658.     SHARED RCTRL_INS
  659.     SHARED RCTRL_DEL
  660.  
  661.     SHARED RCTRL_PGUP
  662.     SHARED RCTRL_PGDN
  663.  
  664.     SHARED RCTRL_Left
  665.     SHARED RCTRL_Right
  666.     SHARED RCTRL_Up
  667.     SHARED RCTRL_Down
  668.  
  669.     SHARED LSHIFT_LCTRL_HOME
  670.     SHARED LSHIFT_LCTRL_END
  671.  
  672.     SHARED LSHIFT_LCTRL_INS
  673.     SHARED LSHIFT_LCTRL_DEL
  674.  
  675.     SHARED LSHIFT_LCTRL_PGUP
  676.     SHARED LSHIFT_LCTRL_PGDN
  677.  
  678.     SHARED LSHIFT_LCTRL_Left
  679.     SHARED LSHIFT_LCTRL_Right
  680.     SHARED LSHIFT_LCTRL_Up
  681.     SHARED LSHIFT_LCTRL_Down
  682.  
  683.     SHARED LSHIFT_BackSpace
  684.     SHARED LSHIFT_TAB
  685.     SHARED LSHIFT_SPACE
  686.     SHARED LSHIFT_ESC
  687.     SHARED LSHIFT_ENTER
  688.  
  689.     SHARED RSHIFT_BackSpace
  690.     SHARED RSHIFT_TAB
  691.     SHARED RSHIFT_SPACE
  692.     SHARED RSHIFT_ESC
  693.     SHARED RSHIFT_ENTER
  694.  
  695.     SHARED LCTRL_SPACE
  696.     SHARED LCTRL_ENTER
  697.  
  698.     SHARED RCTRL_SPACE
  699.     SHARED RCTRL_ENTER
  700.  
  701.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(RSHIFTkey&) THEN LSHIFT_RSHIFT = 1 ELSE LSHIFT_RSHIFT = 0
  702.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RCTRLkey&) THEN LCTRL_RCTRL = 1 ELSE LCTRL_RCTRL = 0
  703.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(RALTkey&) THEN LALT_RALT = 1 ELSE LALT_RALT = 0
  704.  
  705.     'LALT:
  706.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(HOMEkey&) THEN LALT_HOME = 1 ELSE LALT_HOME = 0
  707.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(ENDkey&) THEN LALT_END = 1 ELSE LALT_END = 0
  708.  
  709.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(INSkey&) THEN LALT_INS = 1 ELSE LALT_INS = 0
  710.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(DELkey&) THEN LALT_DEL = 1 ELSE LALT_DEL = 0
  711.  
  712.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(PGUPkey&) THEN LALT_PGUP = 1 ELSE LALT_PGUP = 0
  713.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(PGDNkey&) THEN LALT_PGDN = 1 ELSE LALT_PGDN = 0
  714.  
  715.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(LEFTkey&) THEN LALT_Left = 1 ELSE LALT_Left = 0
  716.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(RIGHTkey&) THEN LALT_Right = 1 ELSE LALT_Right = 0
  717.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(UPkey&) THEN LALT_Up = 1 ELSE LALT_Up = 0
  718.     IF _KEYDOWN(LALTkey&) AND _KEYDOWN(DOWNkey&) THEN LALT_Down = 1 ELSE LALT_Down = 0
  719.  
  720.     'RALT:
  721.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(HOMEkey&) THEN RALT_HOME = 1 ELSE RALT_HOME = 0
  722.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(ENDkey&) THEN RALT_END = 1 ELSE RALT_END = 0
  723.  
  724.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(INSkey&) THEN RALT_INS = 1 ELSE RALT_INS = 0
  725.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(DELkey&) THEN RALT_DEL = 1 ELSE RALT_DEL = 0
  726.  
  727.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(PGUPkey&) THEN RALT_PGUP = 1 ELSE RALT_PGUP = 0
  728.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(PGDNkey&) THEN RALT_PGDN = 1 ELSE RALT_PGDN = 0
  729.  
  730.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(LEFTkey&) THEN PRINT RALT_Left = 1 ELSE RALT_Left = 0
  731.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(RIGHTkey&) THEN RALT_Right = 1 ELSE RALT_Right = 0
  732.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(UPkey&) THEN RALT_Up = 1 ELSE RALT_Up = 0
  733.     IF _KEYDOWN(RALTkey&) AND _KEYDOWN(DOWNkey&) THEN RALT_Down = 1 ELSE RALT_Down = 0
  734.  
  735.     'LSHIFT:
  736.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(HOMEkey&) THEN LSHIFT_HOME = 1 ELSE LSHIFT_HOME = 0
  737.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ENDkey&) THEN LSHIFT_END = 1 ELSE LSHIFT_END = 0
  738.  
  739.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(INSkey&) THEN LSHIFT_INS = 1 ELSE LSHIFT_INS = 0
  740.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(DELkey&) THEN LSHIFT_DEL = 1 ELSE LSHIFT_DEL = 0
  741.  
  742.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(PGUPkey&) THEN LSHIFT_PGUP = 1 ELSE LSHIFT_PGUP = 0
  743.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(PGDNkey&) THEN LSHIFT_PGDN = 1 ELSE LSHIFT_PGDN = 0
  744.  
  745.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LEFTkey&) THEN LSHIFT_Left = 1 ELSE LSHIFT_Left = 0
  746.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(RIGHTkey&) THEN LSHIFT_Right = 1 ELSE LSHIFT_Right = 0
  747.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(UPkey&) THEN LSHIFT_Up = 1 ELSE LSHIFT_Up = 0
  748.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(DOWNkey&) THEN LSHIFT_Down = 1 ELSE LSHIFT_Down = 0
  749.  
  750.     'RSHIFT:
  751.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(HOMEkey&) THEN RSHIFT_HOME = 1 ELSE RSHIFT_HOME = 0
  752.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ENDkey&) THEN RSHIFT_END = 1 ELSE RSHIFT_END = 0
  753.  
  754.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(INSkey&) THEN RSHIFT_INS = 1 ELSE RSHIFT_INS = 0
  755.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(DELkey&) THEN RSHIFT_DEL = 1 ELSE RSHIFT_DEL = 0
  756.  
  757.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(PGUPkey&) THEN RSHIFT_PGUP = 1 ELSE RSHIFT_PGUP = 0
  758.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(PGDNkey&) THEN RSHIFT_PGDN = 1 ELSE RSHIFT_PGDN = 0
  759.  
  760.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(LEFTkey&) THEN RSHIFT_Left = 1 ELSE RSHIFT_Left = 0
  761.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(RIGHTkey&) THEN RSHIFT_Right = 1 ELSE RSHIFT_Right = 0
  762.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(UPkey&) THEN RSHIFT_Up = 1 ELSE RSHIFT_Up = 0
  763.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(DOWNkey&) THEN RSHIFT_Down = 1 ELSE RSHIFT_Down = 0
  764.  
  765.     'LCTRL:
  766.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN LCTRL_HOME = 1 ELSE LCTRL_HOME = 0
  767.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENDkey&) THEN LCTRL_END = 1 ELSE LCTRL_END = 0
  768.  
  769.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(INSkey&) THEN LCTRL_INS = 1 ELSE LCTRL_INS = 0
  770.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DELkey&) THEN LCTRL_DEL = 1 ELSE LCTRL_DEL = 0
  771.  
  772.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN LCTRL_PGUP = 1 ELSE LCTRL_PGUP = 0
  773.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN LCTRL_PGDN = 1 ELSE LCTRL_PGDN = 0
  774.  
  775.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN LCTRL_Left = 1 ELSE LCTRL_Left = 0
  776.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN LCTRL_Right = 1 ELSE LCTRL_Right = 0
  777.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(UPkey&) THEN LCTRL_Up = 1 ELSE LCTRL_Up = 0
  778.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN LCTRL_Down = 1 ELSE LCTRL_Down = 0
  779.  
  780.     'RCTRL:
  781.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN RCTRL_HOME = 1 ELSE RCTRL_HOME = 0
  782.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(ENDkey&) THEN RCTRL_END = 1 ELSE RCTRL_END = 0
  783.  
  784.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(INSkey&) THEN RCTRL_INS = 1 ELSE RCTRL_INS = 0
  785.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(DELkey&) THEN RCTRL_DEL = 1 ELSE RCTRL_DEL = 0
  786.  
  787.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN RCTRL_PGUP = 1 ELSE RCTRL_PGUP = 0
  788.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN RCTRL_PGDN = 1 ELSE RCTRL_PGDN = 0
  789.  
  790.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN RCTRL_Left = 1 ELSE RCTRL_Left = 0
  791.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN RCTRL_Right = 1 ELSE RCTRL_Right = 0
  792.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(UPkey&) THEN RCTRL_Up = 1 ELSE RCTRL_Up = 0
  793.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN RCTRL_Down = 1 ELSE RCTRL_Down = 0
  794.  
  795.     'LSHIFT+LCTRL: NOTICE: LSHIFT+LCTRL+Left triggers 3 variables on - 1] LSHIFT_LCTRL_Left 2] LSHIFT_Left 3] LCTRL_Left
  796.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(HOMEkey&) THEN LSHIFT_LCTRL_HOME = 1 ELSE LSHIFT_LCTRL_HOME = 0
  797.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENDkey&) THEN LSHIFT_LCTRL_END = 1 ELSE LSHIFT_LCTRL_END = 0
  798.  
  799.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(INSkey&) THEN LSHIFT_LCTRL_INS = 1 ELSE LSHIFT_LCTRL_INS = 0
  800.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DELkey&) THEN LSHIFT_LCTRL_DEL = 1 ELSE LSHIFT_LCTRL_DEL = 0
  801.  
  802.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGUPkey&) THEN LSHIFT_LCTRL_PGUP = 1 ELSE LSHIFT_LCTRL_PGUP = 0
  803.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(PGDNkey&) THEN LSHIFT_LCTRL_PGDN = 1 ELSE LSHIFT_LCTRL_PGDN = 0
  804.  
  805.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(LEFTkey&) THEN LSHIFT_LCTRL_Left = 1 ELSE LSHIFT_LCTRL_Left = 0
  806.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(RIGHTkey&) THEN LSHIFT_LCTRL_Right = 1 ELSE LSHIFT_LCTRL_Right = 0
  807.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(UPkey&) THEN LSHIFT_LCTRL_Up = 1 ELSE LSHIFT_LCTRL_Up = 0
  808.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(LCTRLkey&) AND _KEYDOWN(DOWNkey&) THEN LSHIFT_LCTRL_Down = 1 ELSE LSHIFT_LCTRL_Down = 0
  809.  
  810.     'LSHIFT:
  811.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(BACKSPCkey&) THEN LSHIFT_BackSpace = 1 ELSE LSHIFT_BackSpace = 0
  812.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(TABkey&) THEN LSHIFT_TAB = 1 ELSE LSHIFT_TAB = 0
  813.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(SPACEkey&) THEN LSHIFT_SPACE = 1 ELSE LSHIFT_SPACE = 0
  814.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ESCkey&) THEN LSHIFT_ESC = 1 ELSE LSHIFT_ESC = 0
  815.     IF _KEYDOWN(LSHIFTkey&) AND _KEYDOWN(ENTERkey&) THEN LSHIFT_ENTER = 1 ELSE LSHIFT_ENTER = 0
  816.     'RSHIFT:
  817.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(BACKSPCkey&) THEN RSHIFT_BackSpace = 1 ELSE RSHIFT_BackSpace = 0
  818.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(TABkey&) THEN RSHIFT_TAB = 1 ELSE RSHIFT_TAB = 0
  819.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(SPACEkey&) THEN RSHIFT_SPACE = 1 ELSE RSHIFT_SPACE = 0
  820.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ESCkey&) THEN RSHIFT_ESC = 1 ELSE RSHIFT_ESC = 0
  821.     IF _KEYDOWN(RSHIFTkey&) AND _KEYDOWN(ENTERkey&) THEN RSHIFT_ENTER = 1 ELSE RSHIFT_ENTER = 0
  822.  
  823.     'LCTRL:
  824.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(SPACEkey&) THEN LCTRL_SPACE = 1 ELSE LCTRL_SPACE = 0
  825.     IF _KEYDOWN(LCTRLkey&) AND _KEYDOWN(ENTERkey&) THEN LCTRL_ENTER = 1 ELSE LCTRL_ENTER = 0
  826.     'RCTRL:
  827.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(SPACEkey&) THEN RCTRL_SPACE = 1 ELSE RCTRL_SPACE = 0
  828.     IF _KEYDOWN(RCTRLkey&) AND _KEYDOWN(ENTERkey&) THEN RCTRL_ENTER = 1 ELSE RCTRL_ENTER = 0
  829.  
  830.     '_KEYCLEAR
  831.  
  832. SUB ExpandTabs (l$)
  833.     IF INSTR(l$, CHR$(9)) THEN
  834.         TabV% = 8
  835.         b$ = "": f& = 0
  836.         FOR i& = 1 TO LEN(l$)
  837.             IF MID$(l$, i&, 1) = CHR$(9) THEN
  838.                 b$ = b$ + STRING$((f& \ TabV%) * TabV% + TabV% - f&, " ")
  839.                 '  |
  840.                 '  |
  841.                 ' \|/
  842.                 'TabV% - (f% - (f% \ TabV%) * TabV%) =
  843.                 'TabV% - (f% MOD TabV%)
  844.                 f& = (f& \ TabV%) * TabV% + TabV%
  845.             ELSE
  846.                 b$ = b$ + MID$(l$, i&, 1)
  847.                 f& = f& + 1
  848.             END IF
  849.         NEXT
  850.         l$ = b$
  851.     END IF
  852.  
  853. FUNCTION MIN& (YdimROW, filecount)
  854.     IF YdimROW < filecount THEN MIN& = YdimROW ELSE MIN& = filecount
  855.  
  856. FUNCTION AddCommas$ (numeral)
  857.     s$ = LTRIM$(STR$(numeral))
  858.     IF LEN(s$) > 3 THEN
  859.         IF (LEN(s$) MOD 3) THEN x$ = STRING$(3 - (LEN(s$) MOD 3), " ") + s$ ELSE x$ = s$
  860.         s$ = ""
  861.         FOR i = 1 TO LEN(x$) STEP 3
  862.             s$ = s$ + MID$(x$, i, 3) + ","
  863.         NEXT
  864.         s$ = LEFT$(s$, LEN(s$) - 1)
  865.     END IF
  866.     AddCommas$ = LTRIM$(s$)
  867.  
  868. SUB UpdateCLL (l, posit)
  869.     SHARED CLL_Field
  870.     SHARED YdimROW, FileArray$()
  871.     crx = POS(0)
  872.     cry = CSRLIN
  873.     q$ = AddCommas$(LEN(FileArray$(l)))
  874.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Current Line Length: " + q$ + STRING$(CLL_Field - LEN(q$), " ");
  875.     LOCATE cry, crx, 1, 30, 31
  876.  
  877. SUB UpdateNextToCCL_BUSY (posit)
  878.     SHARED YdimROW
  879.     crx = POS(0)
  880.     cry = CSRLIN
  881.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Status: BUSY";
  882.     LOCATE cry, crx, 1, 30, 31
  883.  
  884. SUB UpdateNextToCCL_DONE (posit)
  885.     SHARED YdimROW
  886.     crx = POS(0)
  887.     cry = CSRLIN
  888.     LOCATE YdimROW + 1, posit: COLOR 9, 0: PRINT "; Status: DONE";
  889.     LOCATE cry, crx, 1, 30, 31
  890.  
  891. SUB UpdateCLine (lineToWrite, columnToWrite, FRGR, BACKGR, ln)
  892.     SHARED FileArrayWINDOW$()
  893.     crx = POS(0)
  894.     cry = CSRLIN
  895.     COLOR FRGR, BACKGR
  896.     LOCATE lineToWrite, columnToWrite, 1, 30, 31
  897.     PRINT FileArrayWINDOW$(ln);
  898.     LOCATE cry, crx, 1, 30, 31
  899.  
  900. SUB UpdateWindowFrame (FRGR, BACKGR)
  901.     SHARED YdimROW, filecount, FileArray$(), File_Frame_y, XdimCOL, FileArrayWINDOW$()
  902.     COLOR FRGR, BACKGR
  903.     FOR i = 1 TO MIN&(YdimROW, filecount)
  904.         IF LEN(FileArray$(i + (File_Frame_y - 1))) >= XdimCOL THEN
  905.             FileArrayWINDOW$(i) = MID$(FileArray$(i + (File_Frame_y - 1)), 1, XdimCOL)
  906.         ELSE
  907.             FileArrayWINDOW$(i) = FileArray$(i + (File_Frame_y - 1)) + SPACE$(XdimCOL - LEN(FileArray$(i + (File_Frame_y - 1))))
  908.         END IF
  909.         LOCATE i, 1: PRINT FileArrayWINDOW$(i);
  910.     NEXT
  911.  
  912. SUB ReportTimeToLoad (posit)
  913.     SHARED YdimROW
  914.     SHARED TimeA, TimeB
  915.     crx = POS(0)
  916.     cry = CSRLIN
  917.     LOCATE YdimROW + 1, posit: COLOR 4, 0: PRINT "; Loaded in"; TimeB - TimeA; "seconds.";
  918.     LOCATE cry, crx, 1, 30, 31
  919.  
  920. '@rem This is 'MyCompile.bat', should be placed and run from qb64\:
  921.  
  922. '@rem 'recompile_win.bat' found at E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\temp:
  923. '@rem @echo off
  924. '@rem cd %0\..\
  925. '@rem echo Recompiling...
  926. '@rem cd ../c
  927. '@rem c_compiler\bin\g++ -mconsole -s -Wfatal-errors -w -Wall qbx.cpp  libqb\os\win\libqb_1_4_0000000001000.o  ..\..\.\internal\temp\icon.o -D DEPENDENCY_NO_SOCKETS -D DEPENDENCY_NO_PRINTER -D DEPENDENCY_ICON -D DEPENDENCY_NO_SCREENIMAGE   parts\core\os\win\src.a -lopengl32 -lglu32   -mwindows -static-libgcc -static-libstdc++ -D GLEW_STATIC -D FREEGLUT_STATIC     -lwinmm -lgdi32 -o "..\..\MASAKARI.exe"
  928. '@rem pause
  929.  
  930. 'rem We need to copy 3 files to qb64\internal\c
  931. 'rem dynamic name-and-content (name changes should get the one generated after QB64 -c MASAKARI.BAS from qb64\internal\c\libqb\os\win): libqb_1_4_0000000001000.o
  932. 'rem static name-and-content (take it from qb64\internal\temp): icon.o
  933. 'rem static name-and-content (take it from qb64\internal\c\parts\core\os\win): src.a
  934.  
  935. 'rem Should go to E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c
  936. 'rem Assuming we are in the "home folder" i.e. qb64:
  937. 'cd internal\c
  938. 'g++ -mconsole -s -Wfatal-errors -w -Wall qbx.cpp  libqb_1_4_0000000001000.o  icon.o -D DEPENDENCY_NO_SOCKETS -D DEPENDENCY_NO_PRINTER -D DEPENDENCY_ICON -D DEPENDENCY_NO_SCREENIMAGE   src.a -lopengl32 -lglu32   -mwindows -static-libgcc -static-libstdc++ -D GLEW_STATIC -D FREEGLUT_STATIC     -lwinmm -lgdi32 -o "MASAKARI_mycompile.exe"
  939.  
  940. '@rem The output of above:
  941. '@rem
  942. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>MyCompile.bat
  943. '@rem
  944. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>cd internal\c
  945. '@rem
  946. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c>g++ -mconsole -s -Wfatal-errors -w -Wall qbx.cpp  libqb_1_4_0000000001000.o  icon.o -D DEPENDENCY_NO_SOCKETS -D DEPENDENCY_NO_PRINTER -D DEPENDENCY_ICON -D DEPENDENCY_NO_SCREENIMAGE   src.a -lopengl32 -lglu32   -mwindows -static-libgcc -static-libstdc++ -D GLEW_STATIC -D FREEGLUT_STATIC     -lwinmm -lgdi32 -o "MASAKARI_mycompile.exe"
  947. '@rem
  948. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c>dir masa*
  949. '@rem  Volume in drive E is Sanmayce_111GB
  950. '@rem  Volume Serial Number is 1410-10F9
  951. '@rem
  952. '@rem  Directory of E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c
  953. '@rem
  954. '@rem 01/26/2021  06:11 AM         3,248,640 MASAKARI_mycompile.exe
  955. '@rem                1 File(s)      3,248,640 bytes
  956. '@rem                0 Dir(s)  36,627,079,168 bytes free
  957. '@rem
  958. '@rem
  959. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c>c:\WINDOWS\system32\fc MASAKARI_mycompile.exe ..\..\MASAKARI_original.exe /b
  960. '@rem Comparing files MASAKARI_mycompile.exe and ..\..\MASAKARI_ORIGINAL.EXE
  961. '@rem 00000088: 53 18
  962. '@rem 00000089: 96 93
  963. '@rem 000000D8: F9 BE
  964. '@rem 000000D9: A3 A0
  965. '@rem
  966. '@rem E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64\internal\c>
  967.  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Dav on January 26, 2021, 09:07:03 am
Very thoughtfully written. Even takes into account displaying well on old laptops like mine.

Nice work.

- Dav
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 26, 2021, 10:44:07 am
Thank you @Dav ,
gradually will refine it, many things are to be tested, my goal is Linux and Windows variants to be identical.

Hope, after some weeks to share one functional tool, at least covering some must-have features, in the near future I envision merging all my C tools under the Masakari hood.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Pete on January 26, 2021, 10:48:23 am
Very thoughtfully written. Even takes into account displaying well on old laptops like mine.

Nice work.

- Dav

That, and I like his coding, too. I hope he sticks around after this project is completed. He was a good choice in this year's draft pick. And to think, we only had to trade Clippy for him!

Pete
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on January 26, 2021, 06:05:12 pm
In order to have tons faster loading, loading in 5000+ seconds should be dropped to 5 seconds, a ton being a thousand, you know.

Here's some code for you to play around with:

Code: QB64: [Select]
  1. DEFLNG A-Z
  2.  
  3. 'Start the timer
  4. t## = TIMER
  5. OPEN "oed.dict" FOR BINARY AS #1
  6. temp$ = SPACE$(LOF(1))
  7. GET #1, 1, temp$
  8.  
  9. 'find CRLF
  10. IF INSTR(temp$, CHR$(13)) THEN CRLF = CHR$(13)
  11. IF INSTR(temp$, CHR$(10)) THEN CRLF = CHR$(10)
  12. IF INSTR(temp$, CHR$(13) + CHR$(10)) THEN CRLF = CHR$(13) + CHR$(10)
  13. IF INSTR(temp$, CHR$(10) + CHR$(13)) THEN CRLF = CHR$(10) + CHR$(13)
  14.  
  15. 'parse into an array
  16. REDIM lines(1000000) AS STRING
  17.     l = INSTR(l1, temp$, CRLF)
  18.     IF l THEN
  19.         count = count + 1
  20.         IF count > UBOUND(lines) THEN REDIM _PRESERVE lines(UBOUND(lines) + 1000000) AS STRING
  21.         lines(count) = MID$(temp$, l1, l - l1)
  22.         l1 = l + LEN(CRLF)
  23.     END IF
  24. LOOP UNTIL l = 0
  25. t1## = TIMER
  26.  
  27. PRINT USING "Loaded and parsed #,###,### lines, in ###.#### seconds."; count, t1## - t##
  28.  
  29. PRINT "LINE 1000 FOLLOWS:"
  30. PRINT lines(100)
  31. PRINT "LINE 10000 FOLLOWS:"
  32. PRINT lines(10000)
  33.  

And this is using a version of the OED which I found tucked away on a corner of my drive, though my copy is only about 350MB in size.

 


As you can see, I'm loading and parsing 6.7M lines in less than 2 seconds, and that's with a file of 374 MB (392,676,176 bytes) in size.  Even if you double the size, you'd still only be looking at about 4 seconds to load and parse.

That's a ton faster, by your requirements as listed above.  ;D
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: NOVARSEG on January 27, 2021, 01:18:19 am
@Sanmayce

Quote
(forked from the awesome WATCOM C) many years ago which works exactly the same with Windows and Linux, it is called Yoshi.exe or Youshi.elf, the .C source is also included in the attached to this post package. Basically, it lists all the files in current folder recursively, that is, giving us (optionally with full paths)

I did the same thing but wrote in assembler. It saves all the file names with full paths in a file for later processing.  Walks the files on any USB stick or hard drive and it is fast.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 27, 2021, 05:08:41 am
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Steve, a ton indeed, but what took you so long? Heh-heh.

Without strstr()-like, inhere instr(), exploitation, building these strings  is causa perduta, I knew that, yet I wanted to know how QB64 behaves.

Last night have had few hours and have come up with new parser, which I enliked instantly, mainly because it is written with minimal (in a lazy manner I converted the string array to ... a string function) efforts/changes.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

It is maybe 30x (150 seconds) slower than Steve's, however it is written having Wikipedia in mind, it has sub-variant not needing the file to be in RAM, commented for now.

The benefits:

- now the parsing is in one pass only;
- the simulated "string" now has a field housing its length, so LEN() is unnecessary;
- for the sub-variant not loading the file into physical memory the RAM footprint is MUTSUNKA - only (8bytes offset + 8bytes length) x lines, or 16x4MB=64+MB (in fact 133MB) for OED.DSL with 4,071,706 lines.

Since my wish is to browse files as big as 'enwiki-20210101-pages-articles.xml' 75.6 GB (81,193,612,108 bytes) on machines with 32GB the current parser fits in, since this XML dump requires 18GB (1,218,205,075 lines x 16bytes).
I chose 8bytes to house the maximal line length, since there are DNA sequences (not wrapped) exceeding 4 billion chars.

Code: QB64: [Select]
  1. F:\_KAZE_CPU_Benchmark_Fuzzy-Search-Wikipedia_OCN>dir
  2.  
  3. 01/17/2021  09:12    81,193,612,108 enwiki-20210101-pages-articles.xml
  4. 02/24/2018  12:23            69,120 LineWordreporter.exe
  5. 01/17/2021  05:16            52,761 LineWordreporter_r1stats.zip
  6.  
  7. F:\_KAZE_CPU_Benchmark_Fuzzy-Search-Wikipedia_OCN>dir enwiki-20210101-pages-articles.xml/b 1>q
  8.  
  9. F:\_KAZE_CPU_Benchmark_Fuzzy-Search-Wikipedia_OCN>LineWordreporter.exe q
  10. LineWordreporter, revision 1_stats, written by Kaze.
  11. Purpose: Reports number of lines(LFs) and words in files from a given filelist.
  12. Example:
  13. D:\>LineWordreporter.exe LQ2048.lst
  14. Note1: Files can exceed 4GB limit.
  15. Note2: For CRLF ending lines i.e. Windows style you must add -1.
  16. Buffered counting ...
  17. Reading enwiki-20210101-pages-articles.xml ...
  18. Read (total) bytes so far: 81,193,612,108
  19. LineWordreporter: Encountered lines in all files: 1,218,205,075
  20. LineWordreporter: Encountered words in all files: 10,762,241,151
  21. LineWordreporter: Longest line: 1,756,520
  22. LineWordreporter: Longest word: 104,895
  23.  
  24. F:\_KAZE_CPU_Benchmark_Fuzzy-Search-Wikipedia_OCN>
  25.  

Will play more when have time...

I did the same thing but wrote in assembler. It saves all the file names with full paths in a file for later processing.  Walks the files on any USB stick or hard drive and it is fast.

Salute you, "trivial" task done well is what I enjoy.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on January 27, 2021, 12:58:49 pm
This project reminds me of Text Fetch:
https://www.qb64.org/forum/index.php?topic=1876.msg111064#msg111064

and InForm version:
https://www.qb64.org/forum/index.php?topic=1874.msg111060#msg111060

No drag and drop, you just navigate your hard drive files and folders, load files into reader and select text for clipboard copy/paste.

Ha! looks like I used slow file loading method and I could update it now for Linux users, but not much interest when posted.


So far with Masakari, I've only managed to drag and drop 1 file into it. Have I a need of more instruction? It seems to be done after displaying 1 file but I did figure a trick for drag and drop from Windows Explorer drag to icon on toolbar which pops Masakari and then can drag/drop in.

What is Masakari anyway?
Quote
Dictionary source: Medieval Glossary. More: English to English translation of masakari. (masa-kari) is the Japanese word for an "axe" or a "hatchet", and is used to describe various tools of similar structure. As with axes in other cultures, ono are sometimes employed as weapons.

Ah! :)
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on January 28, 2021, 05:13:15 am
What is Masakari anyway?

Literally, a broadaxe, metaphorically, a powerful tool/weapon to cut evil/ignorance, I have made this booklet: http://www.sanmayce.com/MSKR/masakari_3.pdf (http://www.sanmayce.com/MSKR/masakari_3.pdf)

Also, as a big fan of Mech Commander I loved those battle mechs, the most awesome one was Masakari - the brutal destroyer in the field.

Here comes Masakari r.5 ...   


 

Glad to share the first complete revision, featuring:

- Ability to load a filelist (a file containing filenames, with paths or not) pressing SPACE and the selected one will be loaded in the same window;
- Ability to browse files bigger than available RAM;
- The parser is 64bit i.e. 4+GB files can be uploaded in fast mode;
- Two modes, fast (memory used will be filesize+lines*16) and efficient (smaller memory footprint, just lines*16 bytes);
- Built-in benchmark #1: LShift+RShift - Reporting (in the status line in red color) the time for load;
- Built-in benchmark #2: LCtrl+RCtrl - Reporting (in the status line in red color) the time for PgDn-ing the entire file;

On my laptop (i5-7200u @2.5GHz, 36GB DDR4 2133MHz, Windows 10, Samsung 860 PRO 256GB SATA 3), current r.5 loaded the Oxford English Dictionary in 96 seconds, in its fast mode (i.e. ToLoadOrNotFlag = 1).
In its efficient mode (i.e. ToLoadOrNotFlag = 0) the load time was 3,342 seconds.

However, Task Manager shows Memory Usage: 1248MB for fast and 141MB for the efficient one.

 


The benchmark #2 simulates holding PgDn key until the end is reached, in fast mode it gave 1162 seconds, or 4,071,706 lines / 60 lines / 1162 seconds =  58 Pages-Per-Second.
The benchmark #2 simulates holding PgDn key until the end is reached, in efficient mode it gave 1241 seconds, or 4,071,706 lines / 60 lines / 1241 seconds = 54 Pages-Per-Second.

 


In the incoming days will run Wikipedia benchmark i.e. loading the 76GB in fast mode, curious to see how much time will take.

Wanna use this revision for a while to see what else could be refined and simplified, I need a quick browser in Linux and Windows command prompts, two keys only in order to browse all files in current folder and its branches, and by hitting space to load for browsing desired file - 3 keys in total:
1] m
2] enter
[mouse wheel, or arrows to choose from a filelist]
3] space

The first being a .sh file executing yoshi.elf and masakari.elf - the three placed in bin/

Edit: Had to fix one bug, namely:
Code: QB64: [Select]
  1.         'Ugh, buggy, in r.5 below two "malloc" lines should be using 'NumberOfLFs' not 'FileSize'...
  2.         MhandleOFF = _MEMNEW(8&& * (NumberOfLFs + 1)) 'create new memory block of 8*NumberOfLFs bytes - each line has its own 64bit Offset
  3.         MhandleLEN = _MEMNEW(8&& * (NumberOfLFs + 1)) 'create new memory block of 8*NumberOfLFs bytes - each line has its own 64bit Length, kinda overkill, could be 32bit
  4.  

Now loading Wikipedia dump...

Loaded successfully in ... few hours.

Two things to be updated, pressing the two Shifts has to be revised (status line is not wide enough for GB in size files):

- expand the window from 128 to at least 198, in 1920x1080, see the current line - this line will be in next revisions - I have plans those 60 columns to be used as a side window (with purple/indigo foreground and black background), sidekicking/assisting the left window - while they both being in one physical window.

In next days, I intend to make a single add-on, showing in this (already calling it 'Indigo') window the richest wordlist of English language - the Schizandrafield revision C - being 788,068,084 distinct-words strong! Crazy is good, isn't it, thus when loading some text in Masakari, the user would see whether the word (the phrase, in the future, also) where cursor is appear in corpora listed below, automatically the Indigo "window" will be positioned at the proper line (of course the Schizandrafield will not be loaded in RAM but searched as a fixed length field)...

- the reported seconds were negative, still don't have adequate function returning seconds when midnight is passed...

Edit, 2021-Jan-29:

Okay, did fix the above two issues, the load time in fast mode was 14048/3600= 4- hours (when have enough time will write faster parser), a side issue is that after the Windows 10 PRO update 2020 H2 OS Build 19042.746 my CPU was "downgraded" (CPU-Z and AIDA64 both report 13x multiplier instead of 31x) somehow from having 26GB/s Memory Read (3.1GHz max turbo) down to 16GB/s Memory Read (1.3GHz with no turbo), therefore results on other machines should be better. My first guess is that the hacking (installing 32GB stick which was said was impossible) triggered this behavior, updating BIOS could resolve it. Anyway, by chance my value of 65536MB for swap file in Windows was by chance enough in this Wikipedia load, 36GB + 64GB Virtual = 99GB, after loading the 76GB Wikipedia only 400MB were free, after some minutes Windows did automatic compression and freed ~8GB, so my advice is one to have 128GB virtual RAM since Wikipedia is steadily increased in size, AFAIR 6 years ago it was half that size.

 


Code: QB64: [Select]
  1. WKE_0,000,001_kaoudi

Three fields constitute the whole line (to be padded with spaces at the right):
3 bytes for TAG
2 bytes for two delimiters - the underscore
9 bytes for Number Of Occurrences
32 bytes for the word (the longest word in Heritage Dictionary was 31)
So, 3+2+9+32=46, even 14 more characters left.
The booklet is in .PDF here:

 

Code: [Select]
[Schizandrafield 1-gram Corpus, revision C, derives from next corpora:]

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Corpus Tag, Name                                                                                                     | Corpus size (in bytes) |     Total Words | Unique Words | Needed memory to rip in a single pass |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| AHD, American_Heritage_Dictionary_4_(En-En)_WHOLEWORDS.dsl                                                           |             41,742,099 |       7,083,439 |      176,377 |                              16,512KB |
| BNC, Machine-Learning_British-National-Corpus_XML-edition.tar                                                        |          4,680,140,800 |     980,238,337 |      367,921 |                              34,389KB |
| BRE, Britannica_Encyclopedia_2010_1.563_miled_(En-En)_ANSI.dsl                                                       |            297,981,779 |      46,958,317 |      356,417 |                              33,322KB |
| CAL, Cambridge_Advanced_Learner's_Dictionary_4th_Ed_(En-En).dsl                                                      |             76,257,922 |      13,994,351 |       57,787 |                               5,417KB |
| CCA, Collins_COBUILD_Advanced_Learner's_English_Dictionary_(5th_ed)_(En-En)_WHOLEWORDS.dsl                           |             22,960,485 |       4,553,432 |       61,575 |                               5,772KB |
| DMC, DeepMind_Q_and_A_Dataset_cnn_downloads_(92579_files).tar                                                        |          7,270,204,928 |     988,686,300 |      499,244 |                              46,623KB |
| DMD, DeepMind_Q_and_A_Dataset_dailymail_downloads_(219506_files).tar                                                 |         59,019,643,392 |   7,533,039,068 |      886,887 |                              82,582KB |
| EDR, encyclopediadramaticase-20150628-current.tar                                                                    |            302,959,104 |      41,642,066 |      456,251 |                              42,635KB |
| EJD, Encyclopaedia_Judaica_(in_22_volumes)_TXT.tar                                                                   |            107,784,192 |      16,158,364 |      195,273 |                              18,281KB |
| EJN, ENAMDICT_Japanese_names                                                                                         |             26,392,511 |       1,645,705 |      343,460 |                              32,106KB |
| FDU, For_Dummies_978-ebooks_Collection.tar                                                                           |            811,308,544 |     122,351,592 |      302,353 |                              28,282KB |
| GGB, Google_Books_corpus_version_20130501_English_All_Nodes.txt                                                      |         10,624,363,237 |     178,439,407 |    7,477,257 |                             664,635KB |
| HCN, Hacker_News_2006_to_2017-jul.json                                                                               |          7,046,506,518 |   1,075,832,079 |    2,188,058 |                             201,838KB |
| IST, INTERNET_SACRED_TEXT_ARCHIVE_DVD-ROM_9_(English_140479_htm_files).tar                                           |          2,037,880,832 |     304,410,076 |    1,333,036 |                             123,688KB |
| LDC, Longman_Dictionary_of_Contemporary_English_5th_Ed_(En-En)_WHOLEWORDS.dsl                                        |             52,870,741 |       9,722,686 |       85,217 |                               7,987KB |
| MCD, Macmillan_English_Dictionary_(En-En)_.dsl                                                                       |             79,686,074 |      11,750,813 |       67,340 |                               6,312KB |
| MCT, Macmillan_English_Thesaurus_(En-En).dsl                                                                         |             29,580,755 |       4,650,089 |       39,528 |                               3,708KB |
| NSO, New_Shorter_Oxford_English_Dictionary_fifth_edition.tar                                                         |            132,728,832 |      25,920,769 |      259,990 |                              24,321KB |
| OED, Oxford_English_Dictionary_2nd_Edition_Version_4_(En-En)_WHOLEWORDS.dsl.txt                                      |            564,235,251 |     101,798,550 |    1,089,240 |                             101,214KB |
| OSH, OSHO.TXT                                                                                                        |            206,908,949 |      31,957,006 |       58,893 |                               5,522KB |
| PGT, Project_Gutenberg_DVD-2010_(29180_files).tar                                                                    |         11,110,769,152 |   1,870,216,915 |    3,847,963 |                             350,566KB |
| RDD, Reddit_Comments_(JSON_objects)_from_(2005-12_to_2018-01).json                                                   |      2,277,975,364,152 | 333,829,940,270 |  689,949,388 |                          54,703,959KB |
| RHW, Random_House_Webster's_Unabridged_Dictionary_(En-En)_.dsl                                                       |             53,483,152 |       9,367,457 |      282,580 |                              26,428KB |
| SNT, Machine-Learning_WestburyLab.NonRedundant.UsenetCorpus_(47860_English_language_non-binary-file_news_groups).tar |         39,513,013,248 |   6,316,689,948 |    4,835,188 |                             437,662KB |
| STX, archive.org_stackexchange_(346_corpora_2017-Oct-12).tar                                                         |        274,935,801,856 |  38,077,068,727 |   29,194,792 |                           2,344,214KB |
| TAL, the-anarchist-library-2016-01-18-en_html.tar                                                                    |            153,703,936 |      24,339,935 |      136,000 |                              12,738KB |
| TXF, TEXTFILES.COM_(58096_files).tar                                                                                 |          1,382,122,496 |     192,893,874 |    1,008,780 |                              93,840KB |
| URB, Machine-Learning_Urban_Dictionary_Definitions_Corpus_(1999_-_May-2016).words.json                               |          1,917,822,288 |     263,253,093 |    2,631,962 |                             241,852KB |
| WKD, dumps.wikimedia.org_Germany_dewiki-20180220-pages-articles.xml                                                  |         18,954,897,343 |   2,362,729,484 |   17,415,343 |                           1,467,593KB |
| WKE, dumps.wikimedia.org_English_enwiki-20180220-pages-articles.xml                                                  |         65,865,333,874 |   8,739,196,084 |   39,440,894 |                           3,071,920KB |
| WKF, dumps.wikimedia.org_France_frwiki-20180220-pages-articles.xml                                                   |         17,802,386,071 |   2,429,769,009 |   12,192,025 |                           1,055,599KB |
| WKI, dumps.wikimedia.org_Italy_itwiki-20180220-pages-articles.xml                                                    |         10,887,321,918 |   1,372,430,005 |    8,960,466 |                             790,544KB |
| WKN, dumps.wikimedia.org_Netherlands_nlwiki-20180220-pages-articles.xml                                              |          6,808,875,477 |     800,283,886 |    8,596,100 |                             760,225KB |
| WKP, dumps.wikimedia.org_Portugal_ptwiki-20180220-pages-articles.xml                                                 |          6,891,588,341 |     940,571,722 |    6,736,349 |                             602,633KB |
| WKS, dumps.wikimedia.org_Spain_eswiki-20180220-pages-articles.xml                                                    |         12,200,295,384 |   1,682,091,803 |    9,780,910 |                             858,723KB |
| WMB, dumps.wikimedia.org_English_enwikibooks-20180220-pages-articles.xml                                             |            641,413,774 |      94,801,223 |      971,592 |                              90,438KB |
| WMN, dumps.wikimedia.org_English_enwikinews-20180220-pages-articles.xml                                              |            201,872,863 |      27,328,349 |      404,890 |                              37,839KB |
| WMP, dumps.wikimedia.org_English_specieswiki-20180220-pages-articles.xml                                             |          1,009,303,358 |     107,856,282 |    2,765,079 |                             254,016KB |
| WMQ, dumps.wikimedia.org_English_enwikiquote-20180220-pages-articles.xml                                             |            410,396,147 |      64,809,361 |      561,894 |                              52,455KB |
| WMS, dumps.wikimedia.org_English_enwikisource-20180220-pages-articles.xml                                            |          8,352,677,820 |   1,282,920,260 |    8,547,509 |                             755,716KB |
| WMU, dumps.wikimedia.org_English_enwikiversity-20180220-pages-articles.xml                                           |            369,987,893 |      52,322,592 |      640,606 |                              59,767KB |
| WMV, dumps.wikimedia.org_English_enwikivoyage-20180220-pages-articles.xml                                            |            354,919,743 |      49,701,293 |      734,403 |                              68,474KB |
| WMW, dumps.wikimedia.org_English_enwiktionary-20180220-pages-articles.xml                                            |          5,379,842,566 |     597,315,425 |   14,743,543 |                           1,259,179KB |
| WUD, Webster's_Unabridged_3_(En-En)_WHOLEWORDS_ANSI.dsl                                                              |            134,706,719 |      24,014,478 |      364,352 |                              34,052KB |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

[Schizandrafield 1-gram Corpus, revision C, holds within next tagged-counted-wordlists:]

   237,859,509 dumps.wikimedia.org_Spain_eswiki-20180220-pages-articles.1gram
   161,745,186 dumps.wikimedia.org_Portugal_ptwiki-20180220-pages-articles.1gram
   211,751,899 dumps.wikimedia.org_Netherlands_nlwiki-20180220-pages-articles.1gram
   216,667,608 dumps.wikimedia.org_Italy_itwiki-20180220-pages-articles.1gram
   969,819,544 dumps.wikimedia.org_English_enwiki-20180220-pages-articles.1gram
   452,471,230 dumps.wikimedia.org_Germany_dewiki-20180220-pages-articles.1gram
   294,822,021 dumps.wikimedia.org_France_frwiki-20180220-pages-articles.1gram
    23,100,108 dumps.wikimedia.org_English_enwikibooks-20180220-pages-articles.1gram
   204,113,124 dumps.wikimedia.org_English_enwikisource-20180220-pages-articles.1gram
     9,347,743 dumps.wikimedia.org_English_enwikinews-20180220-pages-articles.1gram
    13,259,587 dumps.wikimedia.org_English_enwikiquote-20180220-pages-articles.1gram
    15,131,207 dumps.wikimedia.org_English_enwikiversity-20180220-pages-articles.1gram
    18,031,161 dumps.wikimedia.org_English_enwikivoyage-20180220-pages-articles.1gram
   355,881,851 dumps.wikimedia.org_English_enwiktionary-20180220-pages-articles.1gram
    65,846,403 dumps.wikimedia.org_English_specieswiki-20180220-pages-articles.1gram
     4,653,581 Encyclopaedia_Judaica_(in_22_volumes)_TXT.1gram
     8,889,960 Webster's_Unabridged_3_(En-En)_WHOLEWORDS_ANSI.dsl.1gram
     3,288,498 the-anarchist-library-2016-01-18-en_html.tar.1gram
     6,973,687 Random_House_Webster's_Unabridged_Dictionary_(En-En)_.dsl.1gram
    26,501,920 Oxford_English_Dictionary_2nd_Edition_Version_4_(En-En)_WHOLEWORDS.dsl.txt.1gram
     1,404,700 OSHO.TXT.1gram
     6,280,919 New_Shorter_Oxford_English_Dictionary_fifth_edition.tar.1gram
       941,039 Macmillan_English_Thesaurus_(En-En).dsl.1gram
     1,609,423 Macmillan_English_Dictionary_(En-En)_.dsl.1gram
     2,044,933 Longman_Dictionary_of_Contemporary_English_5th_Ed_(En-En)_WHOLEWORDS.dsl.1gram
     7,354,174 For_Dummies_978-ebooks_Collection.tar.1gram
    11,464,911 encyclopediadramaticase-20150628-current.tar.1gram
     8,840,362 ENAMDICT_Japanese_names.1gram
     1,466,506 Collins_COBUILD_Advanced_Learner's_English_Dictionary_(5th_ed)_(En-En)_WHOLEWORDS.dsl.1gram
     1,380,759 Cambridge_Advanced_Learner's_Dictionary_4th_Ed_(En-En).dsl.1gram
     8,621,181 Britannica_Encyclopedia_2010_1.563_miled_(En-En)_ANSI.dsl.1gram
     4,268,314 American_Heritage_Dictionary_4_(En-En)_WHOLEWORDS.dsl.1gram
   186,006,261 Google_Books_corpus_version_20130501_English_All_Nodes.1gram
    32,262,044 INTERNET_SACRED_TEXT_ARCHIVE_DVD-ROM_9_(English_140479_htm_files).1gram
    96,997,413 Project_Gutenberg_DVD-2010_(29180_files).1gram
    24,179,167 TEXTFILES.COM_(58096_files).1gram
   797,764,729 archive.org_stackexchange_(346_corpora_2017-Oct-12).1gram
     8,823,193 Machine-Learning_British-National-Corpus_XML-edition.1gram
    65,616,610 Machine-Learning_Urban_Dictionary_Definitions_Corpus_(1999_-_May-2016).words.1gram
   120,939,472 Machine-Learning_WestburyLab.NonRedundant.UsenetCorpus_(47860_English_language_non-binary-file_news_groups).1gram
    12,375,594 DeepMind_Q_and_A_Dataset_cnn_downloads_(92579_files).1gram
    20,878,468 DeepMind_Q_and_A_Dataset_dailymail_downloads_(219506_files).1gram
16,261,229,827 reddit.1gram
    54,744,506 Hacker_News_2006_to_2017-jul.json.1gram

[The way they were ripped:]

E:\Schizandrafield_workshop>dir dumps.wikimedia.org_English_enwiki-20180220-pages-articles.xml/b  >dumps.wikimedia.org_English_enwiki-20180220-pages-articles.lst
E:\Schizandrafield_workshop>echo WKE>Leprechaun.tag
E:\Schizandrafield_workshop>Leprechaun_x-leton_32bit_Intel_01_008p.exe dumps.wikimedia.org_English_enwiki-20180220-pages-articles.lst dumps.wikimedia.org_English_enwiki-20180220-pages-articles.1gram 1399888 Y
...
E:\Schizandrafield_workshop>type dumps.wikimedia.org_English_enwiki-20180220-pages-articles.1gram|more
WKE_0,000,003_byjnf
WKE_0,000,001_richardmullaney
WKE_0,000,001_vfycdm
WKE_0,000,001_kaoudi
WKE_0,000,001_bzolqoptifgvgptya
WKE_0,000,016_bristolcombination
WKE_0,000,001_hermanaustinamstate
WKE_0,000,004_meweyqhwn
WKE_0,000,002_habsfrontcricket
WKE_0,000,001_hobergsclub
WKE_0,000,001_kwagedle
WKE_0,000,001_buvvhel
WKE_0,000,001_wnjyat
WKE_0,000,001_dilmenpeds
WKE_0,000,001_ovldtxrjaaqiy
...
E:\Schizandrafield_workshop>

[The way they were concatenated/sorted:]

C:\>copy/b *.1gram unsorted
C:\>sort.exe /+15 /M 1048576 /T d: "unsorted" /O "Schizandrafield_Corpus_revision_C_(44-corpora_-unique-words).sorted"

Thanks to my brother, here the video and the Linux trio (m,yoshi,masakari - just place them in folder with path to it) come:

Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 01, 2021, 12:46:21 pm
Sanmayce's Haikuoid inspired by "the first kill" (Brian Geraghty's mourningfulness) scene from "The Hurt Locker" movie:
Gunlight
Daylight
Sunset
Loss


My word is for Zennish sensitivity... to be activated and the artistism within to reveal, by itself, nifty practical etudes.

In r.6 were added:

- Four different sub-variants: r6_Fast_Wrapper, r6_Slow_Wrapper, r6_Fast_Vanilla, r6_Slow_Vanilla:
-- Fast/Slow mode - decided by the variable 'ToLoadOrNotFlag', 1/0 respectively
-- Wrapper/Vanilla mode - decided by the variable 'WrapFlag', 1/0 respectively

- When loading, there is progress bar in the 'Status Line'
- In the 'Status Line' now reporting Current Line Number (was reluctant to add it since my plan for streaming was in conflict, meh)

- Title is now containing the actual size of the text window, plus the filename of loaded file
- The command prompt now offers "help" i.e. all the keyboard and mouse combos.

- In order to browse via mouse only, I have come up with two quite ergonomic (the left hand hitting 'm' and 'Enter' and 'Space', while the right is on the mouse non-stop) mouse combos, mimicking 'LCtrl+Home' and 'LCtrl+End':
-- Button 2 + Wheel Up - going to the top left position
-- Button 2 + Wheel Dn - going to the bottom left position

In r.6 were fixed:

- Now, Left Mouse click cannot be placed past last line (when loaded lines are less than Window Height i.e. YdimROW)

The screenshot shows Oxford English Dictionary loaded by r6_Fast_Wrapper_64bit on my crippled laptop with i5-7200U 1.3GHz (32+4)GB:

 


The screenshot shows English Wikipedia XML dump from 2021-Jan-01 loaded by r6_Fast_Vanilla_64bit on laptop with Ryzen 7 4800H 4300MHz, 2x32GB 3200MHz:

 


Also, a batch file compiling the four sub-variants is included:

Code: [Select]
E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>_Make_EXEs.bat

E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>qb64 -c MASAKARI_r6_Fast_Vanilla.BAS

E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>qb64 -c MASAKARI_r6_Fast_Wrapper.BAS

E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>qb64 -c MASAKARI_r6_Slow_Vanilla.BAS

E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>qb64 -c MASAKARI_r6_Slow_Wrapper.BAS

E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>fc MASAKARI_r6_Fast_Vanilla.BAS MASAKARI_r6_Fast_Wrapper.BAS
Comparing files MASAKARI_r6_Fast_Vanilla.BAS and MASAKARI_R6_FAST_WRAPPER.BAS
***** MASAKARI_r6_Fast_Vanilla.BAS

WrapFlag = 0 ' 1 means wrapping
ToLoadOrNotFlag = 1 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient
***** MASAKARI_R6_FAST_WRAPPER.BAS

WrapFlag = 1 ' 1 means wrapping
ToLoadOrNotFlag = 1 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient
*****


E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>fc MASAKARI_r6_Fast_Vanilla.BAS MASAKARI_r6_Slow_Vanilla.BAS
Comparing files MASAKARI_r6_Fast_Vanilla.BAS and MASAKARI_R6_SLOW_VANILLA.BAS
***** MASAKARI_r6_Fast_Vanilla.BAS
WrapFlag = 0 ' 1 means wrapping
ToLoadOrNotFlag = 1 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient

***** MASAKARI_R6_SLOW_VANILLA.BAS
WrapFlag = 0 ' 1 means wrapping
ToLoadOrNotFlag = 0 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient

*****


E:\_KAZE_Smxrt_Benchmarks\QB64_kit_v1.4_2.48 GB\qb64>fc MASAKARI_r6_Fast_Vanilla.BAS MASAKARI_r6_Slow_Wrapper.BAS
Comparing files MASAKARI_r6_Fast_Vanilla.BAS and MASAKARI_R6_SLOW_WRAPPER.BAS
***** MASAKARI_r6_Fast_Vanilla.BAS

WrapFlag = 0 ' 1 means wrapping
ToLoadOrNotFlag = 1 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient

***** MASAKARI_R6_SLOW_WRAPPER.BAS

WrapFlag = 1 ' 1 means wrapping
ToLoadOrNotFlag = 0 ' 1 means fast load but memory greedy; 0 means slow load but memory efficient

*****

In the attached .ZIP package, there is README.TXT:

Code: [Select]
README.TXT

A quick .DIZ for Masakari, revision 6

Masakari is a free and open source tool with simplistic GUI aiming at sidekicking browsing text files in Linux/Windows command prompts.

This .ZIP package contains:

```
02/01/2021  03:16 PM             4,446 README.TXT                                  ! This file

01/29/2021  03:05 PM               171 m                                           ! Linux .sh file invokes yoshi and masakari
01/29/2021  03:05 PM           336,644 yoshi                                       ! Linux .ELF 64bit
02/01/2021  06:43 PM           331,852 masakari                                    ! Linux .ELF 64bit same as 'MASAKARI_r6_Fast_Vanilla_64bit'

02/01/2021  03:16 PM         1,453,926 ColumnChart.ico                             ! Needed during compilation
02/01/2021  03:16 PM             2,991 MEM.H                                       ! Needed during compilation

02/01/2021  03:16 PM               492 m.bat                                       ! Accepts wildcards, invokes Yoshi.exe and MASAKARI_r6_Fast_Vanilla_64bit.exe
02/01/2021  03:16 PM            52,633 MASAKARI_r6_Fast_Vanilla.BAS
02/01/2021  03:16 PM         3,288,576 MASAKARI_r6_Fast_Vanilla_32bit.exe
02/01/2021  03:16 PM         3,647,488 MASAKARI_r6_Fast_Vanilla_64bit.exe
02/01/2021  06:43 PM           331,852 MASAKARI_r6_Fast_Vanilla_64bit.elf
02/01/2021  03:16 PM            52,633 MASAKARI_r6_Fast_Wrapper.BAS
02/01/2021  03:16 PM         3,288,576 MASAKARI_r6_Fast_Wrapper_32bit.exe
02/01/2021  03:16 PM         3,647,488 MASAKARI_r6_Fast_Wrapper_64bit.exe
02/01/2021  06:43 PM           331,852 MASAKARI_r6_Fast_Wrapper_64bit.elf
02/01/2021  03:16 PM            52,633 MASAKARI_r6_Slow_Vanilla.BAS
02/01/2021  03:16 PM         3,288,576 MASAKARI_r6_Slow_Vanilla_32bit.exe
02/01/2021  03:16 PM         3,647,488 MASAKARI_r6_Slow_Vanilla_64bit.exe
02/01/2021  06:44 PM           331,852 MASAKARI_r6_Slow_Vanilla_64bit.elf
02/01/2021  03:16 PM            52,633 MASAKARI_r6_Slow_Wrapper.BAS
02/01/2021  03:16 PM         3,288,576 MASAKARI_r6_Slow_Wrapper_32bit.exe
02/01/2021  03:16 PM         3,647,488 MASAKARI_r6_Slow_Wrapper_64bit.exe
02/01/2021  06:44 PM           331,860 MASAKARI_r6_Slow_Wrapper_64bit.elf

02/01/2021  03:16 PM           660,672 M_r6_OED.png                                ! Screenshot of Oxford English Dictionary loaded by Fast_Wrapper
02/01/2021  03:16 PM           416,939 warwalk_180hue-39sat_x3_NearestNeighbor.gif ! The logo

02/01/2021  03:16 PM               240 z.bat
02/01/2021  03:16 PM               340 _Make_EXEs.bat

02/01/2021  03:16 PM            41,814 Yoshi.exe                                   ! tool for generating 'dir/b' and 'ls' like output
02/01/2021  03:16 PM           972,575 Yoshi7-.zip

02/01/2021  03:16 PM                39 _MAKE_HEX_dump.bat                          ! give it a filename to generate HEX output in text format
02/01/2021  03:16 PM           111,328 DUMP_HEX_header.c
02/01/2021  03:16 PM            77,312 DUMP_HEX_header.exe
02/01/2021  03:16 PM            69,120 LineWordreporter.exe
02/01/2021  03:16 PM            52,761 LineWordreporter_r1stats.zip
```

New releases and announcements at https://twitter.com/Sanmayce

This is how the it looks like in the prompt:

```
E:\qb64>MASAKARI_r6_Fast_Vanilla.exe -h
Masakari, revision 6_Fast_Vanilla, written in QB64 by Kaze, source code downloadable at https://www.qb64.org/forum
Usage: Masakari filename|/help
Currently are implemented only:
Mouse:
      Button 1 - sets the cursor and the inverse line to the chosen position
      Button 3 - PgDn
      Wheel Up - Up
      Wheel Dn - Dn
      Button 2 + Wheel Up - going to the top left position
      Button 2 + Wheel Dn - going to the bottom left position
Keyboard:
       Up
       Down
       Left - still no sideways scroll
       Right - still no sideways scroll
       LCtrl+Home - going to the top left position
       LCtrl+End  - going to the bottom left position
       Alt+X or Alt+Q - quit to the system, without demanding keypress.
       Space - loads the highlighted line (if it is an actual filename)
Benchmarking:
       LShift+RShift - Reporting (in the status line in red color) the time for load
       LCtrl+RCtrl - Reporting (in the status line in red color) the time for PgDn-ing the entire file

E:\qb64>
```

Enfun!

Kaze,
2021-Jan-31

In the incoming revision 7, there will be an additional parser (like the 'Slow' sub-variant, now) NOT loading the entire file, in RAM will be loaded only the 16bytes (Offset+Size) descriptors ... in a buffered way. I fully expect those nasty 4672 seconds to be shrunk to few minutes.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 03, 2021, 04:58:44 am
Did write the new parser.
Will upload Masakari revision 7 tomorrow, busy with other things, want to add the old 'LCtrl+S' combo spell-checking the current window...

Yet, want to share the first known to me 64bit parser of CRLF or LF  (or both, since Linux and Windows text files could be part of a .tar file), 87 lines in length:

Code: QB64: [Select]
  1.                 ReadBytes = 0 ' Have to load the 2+GB "malloc" in chunks...
  2.                 chunk128KB$ = SPACE$(128 * 1024 * 1024)
  3.                 DO WHILE ReadBytes + (128 * 1024 * 1024) < FileSize
  4.                     GET #1, , chunk128KB$
  5.                     'IF INSTR(1, chunk128KB$, CHR$(0)) THEN PRINT "Termination! 'Null' character encountered.": _DISPLAY: END
  6.                     I = 1
  7.                     DO WHILE I <= (128 * 1024 * 1024)
  8.                         I = INSTR(I, chunk128KB$, CHR$(10))
  9.                         IF I = 0 THEN EXIT DO
  10.                         NumberOfLFs = NumberOfLFs + 1
  11.                         I = I + 1
  12.                     LOOP
  13.                     ReadBytes = ReadBytes + (128 * 1024 * 1024)
  14.                 LOOP
  15.                 IF (FileSize - ReadBytes) THEN
  16.                     RemainingChunk$ = SPACE$(FileSize - ReadBytes)
  17.                     GET #1, , RemainingChunk$
  18.                     'IF INSTR(1, RemainingChunk$, CHR$(0)) THEN PRINT "Termination! 'Null' character encountered.": _DISPLAY: END
  19.                     I = 1
  20.                     DO WHILE I <= LEN(RemainingChunk$)
  21.                         I = INSTR(I, RemainingChunk$, CHR$(10))
  22.                         IF I = 0 THEN EXIT DO
  23.                         NumberOfLFs = NumberOfLFs + 1
  24.                         I = I + 1
  25.                     LOOP
  26.                 END IF
  27.  
  28.             ' Parser for r.7 [[[[[[
  29.             IF ToLoadOrNotFlag = 0 THEN
  30.                 ReadBytes = 0 ' Have to load the 2+GB "malloc" in chunks...
  31.                 ChunkLen = 128 * 1024
  32.                 chunk128KB$ = SPACE$(ChunkLen) '+1 for sentinel
  33.                 j = 1 ' is the current offset where new GET reads
  34.                 QWORDlast = 1
  35.                 PrevByte = ""
  36.                 DO WHILE ReadBytes + (ChunkLen) < FileSize ' this '<' is important, on purpose not using '<=' since there should be a remnant chunk (where LF postfixing is enforced, eventually)
  37.                     LastByte = RIGHT$(chunk128KB$, 1) 'to handle eventual CR, left behind i.e. in previous chunk
  38.                     GET #1, j, chunk128KB$
  39.                     I = 1
  40.                     FoundAt = INSTR(I, chunk128KB$, CHR$(10))
  41.                     IF FoundAt THEN
  42.                         DO WHILE FoundAt
  43.                             IF FoundAt = 1 THEN PrevByte = LastByte ELSE PrevByte = MID$(chunk128KB$, FoundAt - 1, 1)
  44.                             QWORD = (j - 1) + FoundAt
  45.                             LineLen13 = QWORD - QWORDlast
  46.                             _MEMPUT MhandleOFF, MhandleOFF.OFFSET + 8&& * filecount, QWORDlast
  47.                             QWORDlast = QWORD + 1
  48.                             IF PrevByte = CHR$(13) THEN LineLen13 = LineLen13 - 1
  49.                             _MEMPUT MhandleLEN, MhandleLEN.OFFSET + 8&& * filecount, LineLen13
  50.                             IF LineLen13 > LongestLine THEN LongestLine = LineLen13
  51.                             filecount = filecount + 1
  52.                             I = FoundAt + 1
  53.                             IF I > (ChunkLen) THEN EXIT DO 'could use sentinel (buffer+1), in order this line to drop out
  54.                             FoundAt = INSTR(I, chunk128KB$, CHR$(10))
  55.                         LOOP
  56.                     END IF
  57.                     j = j + (ChunkLen)
  58.                     ReadBytes = ReadBytes + (ChunkLen)
  59.                 LOOP
  60.                 IF (FileSize - ReadBytes) THEN
  61.                     RemainingChunk$ = SPACE$(FileSize - ReadBytes) '+1 for sentinel
  62.                     LastByte = RIGHT$(chunk128KB$, 1) 'to handle eventual CR, left behind i.e. in previous chunk
  63.                     GET #1, , RemainingChunk$
  64.                     IF RIGHT$(RemainingChunk$, 1) <> CHR$(10) THEN RemainingChunk$ = RemainingChunk$ + CHR$(10) ' dirty, enforcing not missing the last line (if it is not postfixed with LF)
  65.                     'Beware, yes be aware that above line should have been applied for above/first fragment because the filesize could be multiple of the chunk length i.e. no remaining chunk, however it was feinted by '<'
  66.                     I = 1
  67.                     FoundAt = INSTR(I, RemainingChunk$, CHR$(10))
  68.                     IF FoundAt THEN
  69.                         DO WHILE FoundAt
  70.                             IF FoundAt = 1 THEN PrevByte = LastByte ELSE PrevByte = MID$(RemainingChunk$, FoundAt - 1, 1)
  71.                             QWORD = (j - 1) + FoundAt
  72.                             LineLen13 = QWORD - QWORDlast
  73.                             _MEMPUT MhandleOFF, MhandleOFF.OFFSET + 8&& * filecount, QWORDlast
  74.                             QWORDlast = QWORD + 1
  75.                             IF PrevByte = CHR$(13) THEN LineLen13 = LineLen13 - 1
  76.                             _MEMPUT MhandleLEN, MhandleLEN.OFFSET + 8&& * filecount, LineLen13
  77.                             IF LineLen13 > LongestLine THEN LongestLine = LineLen13
  78.                             filecount = filecount + 1
  79.                             I = FoundAt + 1
  80.                             IF I > (FileSize - ReadBytes) THEN EXIT DO 'could use sentinel (buffer+1), in order this line to drop out
  81.                             FoundAt = INSTR(I, RemainingChunk$, CHR$(10))
  82.                         LOOP
  83.                     END IF
  84.                 END IF
  85.             END IF
  86.             SEEK #1, 1
  87.             ' Parser for r.7 ]]]]]]
  88.  

The speed is MUTSI! Oxford English Dictionary was loaded in 5 seconds on my 1.3GHz i5-7200U, the memory usage is roughly 400MB:

 


Also tried the vanilla (non-wrapped) English Wikipedia, the load time is 1188 seconds, the memory usage is around 19GB:

 


Also, the new revision, already, handles unwrappable files (such as Wikipedia) by dumping all unwrappable lines into filename+".unwrappable" while wrapping all the rest, and reports in the status line how many lines are unwrappable, excited to see in next days for the first time Wikipedia loaded in readable format, expecting some 6 billion lines... Edit: Actually 1.4 billion, only plus 200 million since the 198 chars wide window accommodated most of them:

The actual wrapped Wikipedia loaded in 375 seconds:

 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 05, 2021, 09:55:33 am
So glad to share the first operational revision that is the actual fulcrum/skeleton.

Code: [Select]
README.TXT

A quick .DIZ for Masakari, revision 7

Masakari is a free and open source tool with simplistic GUI aiming at sidekicking browsing text files in Linux/Windows command prompts.

This .ZIP package contains:

```
README.TXT                                  ! This file

catalog_2021-02-05_16-20-22.png             ! Screenshot of how 'masakari.tgz' was created
masakari.tgz:                               ! Contains the trio, with attributes (executable flag) set:
 m                                          ! Linux .sh file invokes yoshi and masakari
 yoshi                                      ! Linux .ELF 64bit
 masakari                                   ! Linux .ELF 64bit same as 'MASAKARI_r7_Vanilla_64bit'

ColumnChart.ico                             ! Needed during compilation
MEM.H                                       ! Needed during compilation

m.bat                                       ! Accepts wildcards, invokes Yoshi.exe and MASAKARI_r7_Vanilla_64bit.exe

MASAKARI_r7_Vanilla.BAS
MASAKARI_r7_Vanilla_32bit.exe
MASAKARI_r7_Vanilla_64bit.elf
MASAKARI_r7_Vanilla_64bit.exe
MASAKARI_r7_Wrapper.BAS
MASAKARI_r7_Wrapper_32bit.exe
MASAKARI_r7_Wrapper_64bit.elf
MASAKARI_r7_Wrapper_64bit.exe

MASAKARI_r7_Vanilla_OED.png                 ! Screenshot of Oxford English Dictionary loaded by Vanilla
MASAKARI_r7_Vanilla_Wikipedia.png           ! Screenshot of English Wikipedia loaded by Vanilla
warwalk_180hue-39sat_x3_NearestNeighbor.gif ! The logo

z.bat
_Make_EXEs.bat

Yoshi.exe                                   ! tool for generating 'dir/b' and 'ls' like output
Yoshi7-.zip

_MAKE_HEX_dump.bat                          ! give it a filename to generate HEX output in text format
DUMP_HEX_header.c
DUMP_HEX_header.exe
LineWordreporter.exe
LineWordreporter_r1stats.zip
```

New releases and announcements at https://twitter.com/Sanmayce

This is how it looks like in the prompt:

```
E:\qb64>MASAKARI_r7_Vanilla_32bit.exe -h
Masakari, revision 7_Vanilla, written in QB64 by Kaze, source code downloadable at https://www.qb64.org/forum
Usage: Masakari filename|/help
Currently are implemented only:
Mouse:
      Button 1 - sets the cursor and the inverse line to the chosen position
      Button 3 - PgDn
      Wheel Up - Up
      Wheel Dn - Dn
      Button 2 + Wheel Up - going to the top left position
      Button 2 + Wheel Dn - going to the bottom left position
      Button 2 + dragging (from left to right, or from right to left) for at least 90 columns/cells (within 2 seconds) - same as Alt+X, Alt+Q
      Button 2 + dragging (from top to bottom) for at least 5 lines/cells (within 2 seconds) - same as PgUp
      Button 2 + dragging (from bottom to top) for at least 5 lines/cells (within 2 seconds) - same as PgDn
Keyboard:
       Up
       Down
       PgUp
       PgDn
       Left - still no sideways scroll
       Right - still no sideways scroll
       LCtrl+Home - going to the top left position
       LCtrl+End  - going to the bottom left position
       Alt+X or Alt+Q - quit to the system, without demanding keypress.
       Space - loads the highlighted line (if it is an actual filename)
Benchmarking:
       LShift+RShift - Reporting (in the status line in red color) the time for load
       LCtrl+RCtrl - Reporting (in the status line in red color) the time for PgDn-ing the entire file
Note1: The 'Vanilla' sub-variant loads textual files without wrapping the lines.
Note2: The 'Wrapper' sub-variant makes the text file viewable without side/lateral scroll,
       If unwrappable lines exist then those lines are dumped to filename+".unwrappable",
       otherwise, the wrapped lines are dumped to filename+".wrapped", and auto-loaded.
       If wrapped file exists during start then it is used, not re-created.

E:\qb64>
```

Enfun!

Kaze,
2021-Feb-05
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 19, 2021, 08:09:58 am
So glad to announce that the first Masakari/Kazahana duo is ready, on Monday I will make and upload on YouTube a video clip how the whole Wikipedia is traversed from Masakari via Kazahana (the fastest exact/wildcard/fuzzy scalar searcher on Internet)... The *nix users (along with Windows ones) will be able to download a package from here with precompiled static binaries (.elf and .exe), and the SOURCE CODE, and how to compile it. Of course, for 64bit as well.

No time at the moment, but here is how it looks like on Windows XP 32bit:

The drag-and-drop, waiting for a file:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

The Search Panel:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

My brother's fast testmachine (AMD 4800H, 16 threads, 64GB RAM, m2 SSD with 2400MB/s) will be used, but it cannot keep up with the awesomeness of Kazahana, it devours the read data with its 16-threads thus reaching 3000MB/s search rates, to be seen...
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 22, 2021, 02:46:11 pm
For the first time the fastest fulltext search console tool can be run from Masakari.

Step #1:

 


Step #2:

 


The search rate was 1500+MB/s or 48 seconds for fulltext searching in Wikipedia, not that good because the nvme SSD could do 2400MB/s, for some reason Windows didn't allow it, in next weeks will retest the same benchmark on Linux.

I did the video, however not satisfied with the result, too many blurred scenes, yet, it shows:
- decompressing the .zip package;
- sending the shortcut of Masakari.exe to the Desktop;
- running the shortcut;
- drag-and-drop the Wikipedia;
- searching with Kazahana;
- auto-scrolling with LAlt+RAlt combo, and pressing PgUp key in order to advance ... backwards while the scroll is on (line-by-line).



Was curious how one of the best editors (UltraEdit v.28) deals with the same benchmark, here is what I saw:

UltraEdit v.28:
Load Time: 0s (it has streaming approach)
Fulltext Search Time: 17min 10s

Masakari r7+:
Load Time: 309s (it has indexing approach)
Fulltext Search Time: 49s

Wikipedia can be downloaded at:
https://dumps.wikimedia.org/enwiki/ (https://dumps.wikimedia.org/enwiki/)
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: NOVARSEG on February 23, 2021, 12:41:37 am
@Sanmayce

 chunk128KB$ = SPACE$(128 * 1024 * 1024)


should be 128MB$  ?

****
Quote
I = 1
                    DO WHILE I <= (128 * 1024 * 1024)
                        I = INSTR(I, chunk128KB$, CHR$(10))
                        IF I = 0 THEN EXIT DO
                        NumberOfLFs = NumberOfLFs + 1
                        I = I + 1
                    LOOP

I think that INSTR returns the position of CHR$(10) in the string

from wiki
Quote
The function returns the position% in the baseString$ where the searchString$ was found.
so

I = 0
                        DO
                        I = INSTR(1 + I, chunk128KB$, CHR$(10))
                        IF I = 0 THEN EXIT DO
                        NumberOfLFs = NumberOfLFs + 1
                       
                    LOOP
When the code exits the LOOP there is likely some bytes that are left over at the end of the string that might be data for the next line.

not tested

Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on February 23, 2021, 02:32:28 am
@Sanmayce

 chunk128KB$ = SPACE$(128 * 1024 * 1024)


should be 128MB$  ?

****
I think that INSTR returns the position of CHR$(10) in the string

from wikiso

I = 0
                        DO
                        I = INSTR(1 + I, chunk128KB$, CHR$(10))
                        IF I = 0 THEN EXIT DO
                        NumberOfLFs = NumberOfLFs + 1
                       
                    LOOP
When the code exits the LOOP there is likely some bytes that are left over at the end of the string that might be data for the next line.

not tested

CHR$(10) is the EOL character (End of Line).  Anything past it goes on the next line.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: NOVARSEG on February 23, 2021, 03:38:14 am
A general CHUNK processor

Code: QB64: [Select]
  1. ReadBytes = 0 ' Have to load the 2+GB "malloc" in chunks...
  2.  
  3. Filesize = LOF(1)
  4. DIM Chunksize AS _UNSIGNED LONG
  5. DIM ReadBytes AS _UNSIGNED LONG
  6. Chunksize = 128 * 1024 * 1024
  7. DIM String1 AS STRING
  8.  
  9.     IF Filesize = 0 THEN EXIT DO
  10.  
  11.  
  12.     IF Filesize <= Chunksize THEN
  13.         ReadBytes = Filesize
  14.         Filesize = 0
  15.         GOSUB process
  16.     END IF
  17.  
  18.  
  19.     IF Filesize > Chunksize THEN
  20.      ReadBytes = Chunksize  
  21.      Filesize = Filesize - Chunksize
  22.      GOSUB process
  23.     END IF
  24.  
  25.  
  26.  
  27.  
  28.  
  29. process:
  30. String1 = SPACE$(ReadBytes)
  31.  
  32. GET #1, , String1
  33.  
  34.  
  35. ' ETC
  36.  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 23, 2021, 09:32:46 am
@NOVARSEG

Thanks, you are right, but the possible line left behind unhandled is "COVERED" by adding one extra line in the "malloc" lines, which are right behind the loopS searching for number of LFs:

Code: QB64: [Select]
  1.             MhandleOFF = _MEMNEW(8&& * (NumberOfLFs + 1)) 'create new memory block of 8*NumberOfLFs bytes - each line has its own 64bit Offset
  2.             MhandleLEN = _MEMNEW(8&& * (NumberOfLFs + 1)) 'create new memory block of 8*NumberOfLFs bytes - each line has its own 64bit Length, kinda overkill, could be 32bit
  3.  

The idea is simply to know the number of LF in the incoming file, if the file doesn't end in LF, the above +1 ensures we don't miss the last line.
The best way to count is not INSTR() nor memchr(), it is a manual/dedicated vectorized function counting all the LFs in the vector (not as vectorized memchr() which stops at first hit). Of course for best speeds, it has to be multi-threaded, I found that 4 threads are enough to saturate the memory read of MAIN RAM. Imagine the scenario you have 24GB + 77GB or just machine with 128GB RAM, then the whole Wikipedia will be cached, in such scenario search speed goes up 2x or 3x, as a minimum, I tested a text corpus 400+ million lines (subtitles from movies) 13GB strong, and Kazahana reported 4+GB/s:

 


If you are interested in what I say, see NyoTengu's source code, in there the fastest search, known to me, is done achieving 30+GB/s search rates.
Always glad to talk to coders appreciating the details... ask me what you see as NG (no good), will try in next months to address it.

Add-on, Mar-05:

Always, it is a good idea to have one's sources in hardcopy i.e. on paper, in .PDF, here they are:

MASAKARI_r8+_Vanilla.BAS:

 


TetraNyoTengu.c:

Upload Denied, size limitation...

 
   
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on March 05, 2021, 06:09:09 pm
Many thanks go to @Galleon ! So glad I am, having written the latest and most refined Masakari, once more I realized how the powerful simplicity of QB64 allowed me to have my own browsing/searching tool in such a short time. Way to go...

Now I have my master laptop fixed and running both latest Windows 10 and latest Linux Fedora 33, with QB64 v1.5:

Soon will write a console tool converting UTF-8 to Gesch codepage, thus allowing Russian texts to be browsed as well with the superb Toshiba TxL2 font (spotted after watching @FellippeHeitor videos on YouTube, thanks a lot), for the moment I wrote codepage 1251 to Gesch codepage - the one used by Masakari to show Cyrillic:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

In the attached package, there is a quick description file:

Code: [Select]
README.DIZ.TXT

A quick .DIZ for Masakari, revision 8+

Masakari is a free and open-source tool with simplistic GUI, aiming at sidekicking browsing textual/.tar files in Linux/Windows command prompts.

New releases and announcements at twitter.com/Sanmayce

New features:
- Automatically switches to the excellent Toshiba unicode 16x32px font, in 4K, otherwise using its 8x16px variant in 1366x768, 1680x1050 and FHD modes;
- Allows browsing Bulgarian/Russian texts;
- Scrollwise, refined bigtime, ability to scroll with mouse-keyboard combos or just with mouse alone;
- Source code in form of a .PDF booklet - specially done for QB64 community and coders wanting to help/learn/improve.

This is how it looks like in the prompt:

```
E:\Masakari_source-ELF-EXE_rev8+_Kazahana_NyoTengu_Leprechaun>MASAKARI_Vanilla.exe -h
___  ___                    _                 _                       _____
|  \/  |                   | |               (_)                     |  _  |
| .  . |  __ _  ___   __ _ | | __ __ _  _ __  _    _ __  ___ __   __  \ V /     _
| |\/| | / _` |/ __| / _` || |/ // _` || '__|| |  | '__|/ _ \\ \ / /  / _ \   _| |_
| |  | || (_| |\__ \| (_| ||   <| (_| || |   | |  | |  |  __/ \ V /_ | |_| | |_   _|
\_|  |_/ \__,_||___/ \__,_||_|\_\\__,_||_|   |_|  |_|   \___|  \_/(_)\_____/   |_|

Masakari, revision 8+_Vanilla, written in QB64 by Kaze, source code downloadable at https://www.qb64.org/forum
Usage: Masakari [filename]|[/help]
Note: The 'filename' could be a filelist, i.e. a list of filenames (see Space and Double-Left-Click).

Mouse:
       Button 1 - sets the cursor and the inverse line to the chosen position
       Button 3 - Burst PgDn
       Wheel Up/Dn - Up/Dn
       Button 2 + Wheel Up - going to the top left position
       Button 2 + Wheel Dn - going to the bottom left position
       Button 2 + dragging (sideways) for at least 100 columns/cells (within 2 seconds) - same as Alt+X, Alt+Q
       Button 2 + dragging (from top to bottom) for at least 5 lines/cells (within 2 seconds) - same as PgUp
       Button 2 + dragging (from bottom to top) for at least 5 lines/cells (within 2 seconds) - same as PgDn
       Button 1 + Button 1 (within 0.33 seconds) - Double-Left-Click - PgUp or loads the inverse line (if it is a valid file)
       Button 2 + Button 2 (within 0.33 seconds) - Double-Right-Click - PgDn
       LShift + Button 1/2 - Burst Up/Dn
       LCtrl + Button 1/2 - Burst PgUp/PgDn
       LAlt + Button 1 = LCtrl+Home - going to the top left position
       LAlt + Button 2 = LCtrl+End - going to the bottom left position
Keyboard:
       F1 - this help panel
       Up/Dn/PgUp/PgDn
       Left/Right - still no sideways scroll
       LCtrl+Home - going to the top left position
       LCtrl+End  - going to the bottom left position
       Alt+X or Alt+Q - quit to the system, without demanding keypress
       Space - loads the highlighted line (if it is an actual filename)
       RCtrl|RShift - (can hold it) highlighting all unfamiliar words to masakari.wrd file/wordlist
       LCtrl+F3 - Search Panel, Kazahana (with 16 threads) searches the file, currently displayed
Benchmarking:
       LAlt+RAlt - Reporting (in the status line in red color) the time for load
       LCtrl+RCtrl - Reporting (in the status line in red color) the time for PgDn-ing (page-by-page) the entire file
       LShift+RShift - Reporting (in the status line in red color) the time for Down-ing (line-by-line) the entire file
       Esc - Stops the auto-scrolling started with LCtrl+RCtrl or LShift+RShift
Note1: During the LShift+RShift auto-scroll, you can still press/hold RCtrl, during the LCtrl+RCtrl, you cannot.
Note2: During the auto-scroll, you can still press PgUp, PgDn, LCtrl+Home, LCtrl+End, Esc.
Note3: The 'Vanilla' sub-variant loads textual files without wrapping the lines.
Note4: The 'Wrapper' sub-variant makes the text file viewable without side/lateral scroll.
       If unwrappable lines exist then those lines are dumped to filename+".unwrappable",
       otherwise, the wrapped lines are dumped to filename+".wrapped", and auto-loaded.
       If wrapped file exists during start then it is used, not re-created.

E:\Masakari_source-ELF-EXE_rev8+_Kazahana_NyoTengu_Leprechaun>
```
Some explanations:

     1,472,368 1251toGesch                  ! 64bit ELF !
         5,784 1251toGesch.bas              ! Convertor from 1251 codepage to Gesch codepage ! Allowing reading Bulgarian/Russian !
     1,724,416 1251toGesch.exe              ! 32bit EXE !

<DIR>          Kazahana_sources_binaries    ! The binaries and source of fastest scalar fulltext searcheress !
       484,124 kazahana                     ! 64bit ELF !
       111,118 Kazahana.exe                 ! 32bit EXE !

<DIR>          NyoTengu                     ! The binaries and source of fastest vector fulltext searcheress !
        96,256 TetraNyotengu.exe            ! 32bit EXE !
     1,042,360 libiomp5md.dll               ! TetraNyotengu needs this Intel OpenMP .DLL!

<DIR>          x-gram_corpora               ! The binaries and source of fastest x-gram ripper !

    10,229,600 masakari.ind                 ! Needed by RCtrl or RShift in Masakari - highlights the unfamiliar to masakari.wrd words !
     3,903,143 masakari.wrd                 ! Kaze's unigram English corpus i.e. spell-check wordlist !

     1,453,926 ColumnChart.ico              ! The ICON of Masakari !
         2,991 MEM.H                        ! Needed for Windows compilation of Masakari !
     2,537,104 MASAKARI_Vanilla             ! 64bit ELF !
       135,085 MASAKARI_Vanilla.BAS
     4,319,232 MASAKARI_Vanilla.exe         ! 32bit EXE !
     2,537,104 MASAKARI_Wrapper             ! 64bit ELF !
       135,085 MASAKARI_Wrapper.BAS
     4,319,232 MASAKARI_Wrapper.exe         ! 32bit EXE !

            98 ml.sh                        ! this script gives 'ls -l' in a scrollable list !
            98 m1.sh                        ! Allows to choose-n-load a file from the the shown filelist !
            51 mGesch.sh                    ! Converts codepage 1251 to Gesch and loads wrapped file in Masakari !
           418 m.bat
         1,633 MokujIN JADE 217 prompt.lnk  ! Kaze's Windows command prompt !

       303,296 cour.ttf
       115,068 lucon.ttf
       346,524 MxPlus_Cordata_PPC-400.ttf
       146,744 MxPlus_ToshibaTxL2_8x16.ttf  ! The Kaze's font-of-choice, many thanks go to VileR, https://int10h.org/oldschool-pc-fonts/ !

       570,901 Gulyakovskiyi_E._Dolgiyi_Voshod_Na_Yenne.html ! The Line-By-Line Scroll Rate Benchmark, sh mGesch.sh Gulyakovskiyi_E._Dolgiyi_Voshod_Na_Yenne.html !

Enfun!

Kaze,
2021-Mar-05

Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on May 24, 2021, 10:25:33 pm
So glad to share my latest GUI texttoy,
here comes MASAKARI revision 8+++, enjoy!

Three new features were added:

- Thanks to VileR (https://int10h.org), the superb Japanese 6x12 font was added - it allows beautiful 300x80 textual matrix in FHD;
- Creating the unseen x-gram (better defined than n-gram) tree - called PAGODA - by mere clicking Left Mouse Button + Right Mouse button, over a word;
- Added three searching (via keyboard) modes - F3, Lshift+F3, LAlt+F3.

Look up the attached package for README.DIZ.TXT for a bit more detailed description.

Just to get a visual sense of what the power of PAGODA structure is:

Step #1, just clicking Left Mouse Button + Right Mouse Button, over a word, it highlights it:

 


Step #2, browsing the PAGODA tree, it saves a ton of time for searching/browsing by giving the "environment of a word" - built by all unigrams, bigrams, trigrams, tetragrams and pentagrams adjusted in such a manner that the "root/pillar" word stays centered, whereas the branches come in top-bottom and right-left order:

 


More about PAGODA structure can be found in this 8 pages booklet:

 

Also, the font sharings of VileR (an Israeli guy) have huge impact on me, see below the ultrab 300 columns in 1920x1080 - the font matrix of 6x12 is the smallest one allowing undistorted shape to be retained, as far as I know. Sometimes, a file with long lines (200+) has to be browsed and searched, then the new MASAKARI_Vanilla_NEC[.exe] comes in handy, it is to be used, instead of Toshiba 'Vanilla':

 


Sadly, didn't have enough time to create the Linux counterparts of files (the ELFs and .sh batches) needed to create PAGODA, to be done...
Also, the PDF booklet with the source code didn't fit in the 20MB limit, so here are the 68 pages, it turns out that the Toshiba font is quite good when printing in hardcopy as well, it gives the Matrix Printer feel of it:
http://www.sanmayce.com/Masakari.zip

Hope, fellow members, interested in textual processing/visualization, to benefit from this package, as I benefited down the years from ... other sharers.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on July 21, 2021, 02:40:11 am
Glad to share my new mouse handling fragment. I have had nasty problems with double-clicks using mindlessly written code of old, now all the instances of Double-Clicks are handled properly without omitting any!

First, I wrote this standalone testbed, and later have included it into the latest Masakari - to be shared in next hours...

Code: QB64: [Select]
  1. 'mouse mumbo-jumbo [
  2.  
  3. SCREEN _NEWIMAGE(600, 900, 256)
  4.  
  5. ShutDownDuration = 4 ' 4 seconds
  6. DclickTime = 0.33 ' 1/3 of a second, usually it is 0.27s, so 0.33 suits even the slow clickers
  7. DIM Button1LOG_firstDetection#(4)
  8. DIM Button1LOG_ForHowLongHolded#(4)
  9. PrevClick# = 0
  10. PRINT "You may exit with Esc or by holding left mouse button for 4 seconds..."
  11.  
  12.     AsIfItIsINKEY% = _MOUSEINPUT '      Check the mouse status
  13.     IF AsIfItIsINKEY% THEN
  14.         buttondown1 = _MOUSEBUTTON(1)
  15.         buttondown2 = _MOUSEBUTTON(2)
  16.         buttondown3 = _MOUSEBUTTON(3)
  17.         mwheel = _MOUSEWHEEL
  18.     END IF
  19.  
  20.     IF (buttondown1 AND PrevClick# = 0) THEN 'first detection of the click
  21.         PrevClick# = TIMER(0.001)
  22.     END IF
  23.  
  24.     IF (buttondown1 AND PrevClick# <> 0) THEN 'already clicked
  25.         'PrevClick# = TIMER(0.001)
  26.         ForHowLongWasPressed# = TIMER(0.001) - PrevClick#
  27.     END IF
  28.  
  29.     IF buttondown1 = 0 AND PrevClick# <> 0 THEN 'write to the log
  30.         PRINT
  31.         FOR MumboJumbo = 1 TO 4
  32.             PRINT "OLD"; Button1LOG_firstDetection#(MumboJumbo), Button1LOG_ForHowLongHolded#(MumboJumbo)
  33.         NEXT
  34.  
  35.         FOR MumboJumbo = 1 TO 3
  36.             Button1LOG_firstDetection#(MumboJumbo) = Button1LOG_firstDetection#(MumboJumbo + 1)
  37.             Button1LOG_ForHowLongHolded#(MumboJumbo) = Button1LOG_ForHowLongHolded#(MumboJumbo + 1)
  38.         NEXT
  39.         Button1LOG_firstDetection#(4) = PrevClick#
  40.         Button1LOG_ForHowLongHolded#(4) = ForHowLongWasPressed#
  41.         PrevClick# = 0
  42.  
  43.         FOR MumboJumbo = 1 TO 4
  44.             PRINT "NEW"; Button1LOG_firstDetection#(MumboJumbo), Button1LOG_ForHowLongHolded#(MumboJumbo)
  45.         NEXT
  46.  
  47.     END IF
  48.  
  49.     IF Button1LOG_firstDetection#(3) AND (Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(3) < DclickTime) THEN Double_LeftClick = 1 ELSE Double_LeftClick = 0
  50.     IF Double_LeftClick = 1 THEN PRINT "Double_LeftClick detected. Done in"; INT((Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(3)) * 1000); "ms."
  51.  
  52.     IF Button1LOG_firstDetection#(2) AND (Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(2) < DclickTime * 2) THEN Triple_LeftClick = 1 ELSE Triple_LeftClick = 0
  53.     IF Triple_LeftClick = 1 THEN PRINT "Triple_LeftClick detected. Done in"; INT((Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(2)) * 1000); "ms."
  54.  
  55.     IF Button1LOG_firstDetection#(1) AND (Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(1) < DclickTime * 3) THEN Quadruple_LeftClick = 1 ELSE Quadruple_LeftClick = 0
  56.     IF Quadruple_LeftClick = 1 THEN PRINT "Quadruple_LeftClick detected. Done in"; INT((Button1LOG_firstDetection#(4) - Button1LOG_firstDetection#(1)) * 1000); "ms."
  57.  
  58.     IF (ForHowLongWasPressed# > ShutDownDuration) THEN
  59.         ShutDown_LeftClick = 1: IF ShutDown_LeftClick = 1 THEN PRINT "ShutDown_LeftClick detected.": END
  60.     END IF
  61.  
  62.     _LIMIT 500
  63.     _DISPLAY
  64.  
  65. 'Note1: From above experiments I see Double-Click fits usually in DclickTime s window.
  66. 'Note2: Double-Click is detected when the difference between two initial clicks is below DclickTime s i.e. Button1LOG_firstDetection#(4)-Button1LOG_firstDetection#(3) < DclickTime
  67. ' ForHowLongWasPressed# = B1 - A1 i.e. duration of holding down:
  68. ' where
  69. ' A1=first detection of the click   B1=released A2=first detection of the click   B2=released
  70. ' [                                ][          ][                                ][          ]
  71.  
  72. 'mouse mumbo-jumbo ]
  73.  

Soon will write a console tool converting UTF-8 to Gesch codepage, thus allowing Russian texts to be browsed as well with the superb Toshiba TxL2 font...

Did it, now browsing 800,000+ lines of Russian (either in UTF-8 or CP-1251) mini-articles is possible, when a line is of interest, just release Enter over it, and when done reading, again release Enter in order to return in non-wrapped view:

 


 


 


As always, I attached the Linux binaries, speaking of releasing keys, for some reason there is a discrepancy when compared with Windows binaries - on Linux it doesn't wait for releasing the key but acts as soon as the key is hit?! Any ideas why?
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on July 25, 2021, 05:50:05 am
Enter Gesch encoding...

It's time to break away, no more limitations on browsing Italian/French/German/Spanish/Bulgarian/Russian ... without using any UNICODE!

In next days will write the search panel in which all those symbols (from my Gesch codepage), for now I wrote only the converter from UTF-8 to Gesch, attached at the end.

Here it is the "legacy" codepage, which in my opinion was made by a total schmuck:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Here is the newwave in codepage encodings :P

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

As always, I checked all the converted symbols against the https://utf8-chartable.de, and there were no mismatches:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

One quick example is how Don Quixote is readable in Gesch encoding:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Simply, when I need to browse some UTF-8 file, I won't be bothered whether there are Russian or/and French or/and German texts within, just will run UTF8toGesch.exe converter and Drag-n-Drop the .Gesch file.
In next releases will add the ability to search for those symbols.

Halving the file size comes as a "side effect", as a bonus. For example I have one Russian corpus 15,000+ ebooks in UTF-8 strong and 11GB in size. Guess what, instead of fulltext searching 11GB in UTF-8 the traverse distance becomes ~6GB.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on July 28, 2021, 12:30:02 pm
The need for more ergonomic (that is, easily accessible) shortcuts (strictly keyboardish) got me thinking...

Holy hell, why no one introduced the analogues/counterparts of "double-clicks" - the first that comes to mind: the "double-hits".
Both, being just taps.
Currently, in Masakari there are:
- shortcuts, purely keyboardish;
- shortcuts, mix of keys and mouse buttons;
- shortcuts, purely mouseish, just mouse stuff - buttons and wheel.

From revision 8.1+ onward, following double-hits were implemented:
Double LShift; Double LCtrl; Double LAlt; Double RAlt.
The thing is that "legacy" shortcuts as Ctrl+F3 (even the F3) force the user to "locate" their position and to overreach - meaning hovering pass the SPACEBAR area - which is most easy to hit since the wrists/palms have support, and are simply closer.
To me, the traditional key sequences are to be replaced/enriched with more convenient, more close to the first row of the keyboard, ones.
Currently, my main keyboard is a nasty one (laptopish, with low profile, non-tactile, half-sized F-keys, and tightly packed), when e.g. a LCtrl+F3 search is needed, spotting this halved F3 is a drag, therefore the double-hit of e.g. LCtrl saves the situation - just double-tap it - the timings between the two pressings are handled by the same logic as the mouse double/triple/quadruple-clicks.
The following stand-alone etude is the same as the previously shared mouse_mumbo-jumbo.bas, except:
Code: QB64: [Select]
  1. buttondown1 = _MOUSEBUTTON(1)
should be replaced with
Code: QB64: [Select]
  1. KeyTap_buttondown1 = _KEYDOWN(LSHIFTkey&)

The attached package contains the most refined revision so far, with all accompanying  tools, 32bit and 64bit executables for Windows, and 64bit ELF for Linux.
There is one file, called Word-list_584879_words_Russian_Spell-Check.txt.Gesch.oneline.198, it serves as a scroll line-by-line testfile benchmark, on my laptop running both Windows 10 and Fedora 33, it gave 45 Lines-Per-Second scroll speed:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

And the PDF booklet with the QB64 sourcecode at:
www.sanmayce.com/Masakari.zip (http://www.sanmayce.com/Masakari.zip)

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on October 12, 2021, 07:45:33 am
My word is for QB64 toolbox/application enrichment.

Didn't want to initiate a thread about hashing, especially for having the so needed fastest 128bit hash function.
As the need for speed is constantly on my mind, recently I wrote Gumbotron:
https://github.com/google/highwayhash/issues/102# (https://github.com/google/highwayhash/issues/102#)

 


The idea is to solve problematic search/index scenarios with reliable/optimized tools/etudes and feeding the QB64 application with resultant data.
Too often 1,000,000,000 records e.g. 64,128 or 256 bytes long are to be searched, how to deal with it?!
The discussions in other sub-forums focus on languages and their advance features, but the problem stays as long as one sees within the box and forgets to look outwith, that is, beyond the languages limitations.
Gumbotron is such a case, it makes the hashing in inside-out not in outside-in manner, meaning all the permutations of the key for hashing are dealt with outside the hasher itself, the "traditional" hashers make all kind of rotations/multiplications/shifts within the body serving as a LINEAR MIXER, but the really smart coders already did such a LINEAR MIXER hardwarely embedding all the stages of AES into a single instruction with latency 3 clocks and throughput 1 clock!
So, the moral is to exploit all the available resources (either languages, CPU extensions, algorithms), not to burden oneself with giving tasks as forcing a dog to pull a plug, yes the ox is better, but dog has other functionality - it is a matter of proper assignment.

Hm, don't feel I am getting my point across, back in the day Assembler/Assembly was popularized by the "bad guy" Phil Katz, the documentary says a lot. The favorite part of mine is where the screen says "... the damage was done" referring to speeding up the ARC 10x, rewriting C parts into Assembly. Very funny and sad at the same time, the bad guy gives PKARC/PKZIP and teaches in a practical way how things are to be done, and the community slams him as being the devil. If the devil offers superspeeds, let us reject them since they are ... born in sin, hee-hee.



Also, reading, in the forum, the discussion about highlighting/popularizing the usefulness of QB64, didn't want to write obvious things, yet to me the most obvious way is by ... example.
Yes, sharing etudes/tools written well with real practical value would showcase the power of one approach/language/method in a macho (Clint Eastwood's last film taught me this word) way.
Imagine, a well-written tool, it would serve as an ad for the language used, quite naturally. Having such a good forum prompts for sharing code that catches the attention of users and makes them enthusiasts, daring to try themselves, but they have to have a starting point/code/tool to play with.
Will share this thread/tool on the biggest English language forum:
https://forum.thefreedictionary.com/postst31183p4_MASAKARI--The-people-s-choice--General-Purpose-Grade--English-wordlist.aspx (https://forum.thefreedictionary.com/postst31183p4_MASAKARI--The-people-s-choice--General-Purpose-Grade--English-wordlist.aspx)

And just wanted to announce the incoming new Masakari revision allowing dictionaries lookups in a better way than most software out there, including the original Oxford, Webster, Wiktionary...
My vision is to present all the .DSL files into an unified/standardized manner, simplistic and ergonomic, having in mind cross-searches as well.
The draft looks like this (yes, targeting the old and super durable laptops, as Thinkpad, having low resolutions as 1366x768):

 


Writing such a practical tool (allowing quick lookups into 16+1+1+1 major dictionaries) could serve as a starting point for contemplating new ideas of refining and boosting the search capabilities even more...

I intend gradually to add all these:
Code: QB64: [Select]
  1. 02/28/2021  08:34 PM        42,257,313 Dictionary_Specification_Language_(ABBYY_Software_House)_American_Heritage_Dictionary_4_(En-En)_UTF-8.dsl
  2. 02/28/2021  08:36 PM       299,225,953 Dictionary_Specification_Language_(ABBYY_Software_House)_Britannica_Encyclopedia_2010_1.563_miled_(En-En)_ANSI.dsl
  3. 02/28/2021  08:58 PM        75,122,799 Dictionary_Specification_Language_(ABBYY_Software_House)_Cambridge_Advanced_Learner's_Dictionary_4th_Ed_(En-En).dsl
  4. 02/28/2021  09:00 PM        23,413,283 Dictionary_Specification_Language_(ABBYY_Software_House)_Collins_COBUILD_Advanced_Learner's_English_Dictionary_(5th_ed)_(En-En).dsl
  5. 02/28/2021  09:05 PM        37,870,978 Dictionary_Specification_Language_(ABBYY_Software_House)_Longman_Activator_2nd_Ed_(En-En).dsl
  6. 02/28/2021  09:10 PM        52,743,002 Dictionary_Specification_Language_(ABBYY_Software_House)_Longman_Dictionary_of_Contemporary_English_5th_Ed_(En-En).dsl
  7. 02/28/2021  09:19 PM        83,412,925 Dictionary_Specification_Language_(ABBYY_Software_House)_Macmillan_English_Dictionary_(En-En)_UTF-8.dsl
  8. 02/28/2021  09:19 PM        29,772,872 Dictionary_Specification_Language_(ABBYY_Software_House)_Macmillan_English_Thesaurus_(En-En)_UTF-8.dsl
  9. 02/28/2021  09:15 PM       101,528,058 Dictionary_Specification_Language_(ABBYY_Software_House)_Merriam-Webster's_Collegiate_Dictionary_11th_Edition_(En-En).dsl
  10. 02/28/2021  09:29 PM        57,854,694 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_Advanced_Learner's_Dictionary_8th_Edition_(En-En).dsl
  11. 02/28/2021  09:32 PM        44,362,425 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_American_Dictionary_2nd_Edition.dsl
  12. 02/28/2021  09:33 PM        11,747,238 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_American_Thesaurus_(En-En).dsl
  13. 02/28/2021  09:38 PM       559,408,265 Dictionary_Specification_Language_(ABBYY_Software_House)_Oxford_English_Dictionary_2nd_Edition_Version_4_(En-En)_ANSI.dsl
  14. 02/28/2021  09:33 PM        53,483,030 Dictionary_Specification_Language_(ABBYY_Software_House)_Random_House_Webster's_Unabridged_Dictionary_(En-En)_UTF-8.dsl
  15. 02/28/2021  09:53 PM        12,202,934 Dictionary_Specification_Language_(ABBYY_Software_House)_The_Collins_Cobuild_School_Dictionary_of_American_English_(En-En).dsl
  16. 02/28/2021  08:26 PM       137,754,899 Dictionary_Specification_Language_(ABBYY_Software_House)_Webster's_Unabridged_3_(En-En)_UTF-8.dsl
  17.  
  18. 03/28/2019  02:31 PM         5,340,386 dict2txt_Online_Etymology_Dictionary1.1.txt
  19.  
  20. 10/08/2021  08:42 AM     7,015,793,795 enwiktionary-20210920-pages-articles.xml
  21.  
  22. 07/10/2021  09:57 PM     1,917,822,288 Machine-Learning_Urban_Dictionary_Definitions_Corpus_(1999_-_May-2016).words.json
  23.  

For a long time, the need for English language speedy lookups into constellation of dictionaries (on a netbook) drives me toward writing a tool sidekicking macholy, once and for all.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on October 23, 2021, 11:22:27 pm
Thanks @The Librarian for sharing this:
https://www.qb64.org/forum/index.php?topic=1598.0

This function is a must-have, for example it can be used for controlling _LIMIT in a "stepping" fashion, as the CPUs are downclocked.

Consider a main loop with _LIMIT 500 and the user is using the application touch-and-go-ly, it is a good idea to reduce the 500 by 10% each minute (down to 90%) of inactiveness i.e. not doing keyboard input.

Here is a bit modified variant, after 13 minutes it enters maximum ... minimum:

 


Already incorporated this etude in Masakari r.8.1++, also finished the Schizandrafield rev.D lookup functionality:

 


Simple functionalities such as automatic highlighting of identical entries (above and below) to the current/inverse line are nice since the eyes stop constantly seeking whether neighbors are identical.

Also, finally, did what every GUI tool has to offer - the Color Scheme defined in a file (allowing the user to play with it), in this case the file is called Masakari.RGB - it is 48 bytes long, all the 16 colors given from 0 to 15 in three bytes sequence, RGB:

 


Sometimes, when working outdoors (on a shiny day), more brightness is needed, laptops lack such a regulator so just pressing 'I' will increase all channels by 1 point:

 

The feeling, of seeing the actual window colorized, is different from seeing some small box, moreover the combinations of foreground and background are tricky to please the user, therefore one can play with channels and intensity and once seeing a pleasing combination then can save the RGB values on paper and remap whichever color in the Masakari.RGB is wanted to be replaced.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on October 30, 2021, 08:42:14 am
What is the quicksort routine that QB64 community uses?!

Back in the day, I wrote an XMS QuickSort, now dusted off and shared here.
From time to time, I visit the very informative site 'rosettacode' where multi languages etudes are given side by side, it is a shame QB64 is not presented there as it should, especially unacceptable is the situation with the QS64, standing for QuickSort 64bit, not having its QB64  presence.
Today, I have added my Quicksort variant, thus putting QB64 in this must-be "Quick" category:

https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#QB64 (https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#QB64)

Soon will include this very subroutine into Masakari sorting the QWORD  long indexes to lines...

Also, did make a benchmark (source code and binary attached) with QB64 executable which can be used as a general speed benchmark, stressing caches and somewhat uncached (or rather not well cached) RAM accesses (despite QS being with good locality) - very interesting it would be when AMD 3D cache comes along, and mostly with M1 Apple's unified memory (with RAM latency ~35ns being the half of PCs, AFAIK).
Whoever owns M1 Max, please compile it and share with us how well Apple performs.

On my Kaby Lake laptop (i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz) it took 11 minutes to sort 1.7 billion QWORDS (i.e. 8 bytes elements). They are in range 0..9, which makes sorting harder due to the many repetitions.

Here we go:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

The panel at the end checks for sanity:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Actually, the digits come from the 22,338,618 bytes long file containing the dump of 2^74207281-1, which was the biggest known prime number in 2016.

Here is the dumper of my testdataset, thanks to Fabrice Bellard:
Code: C++: [Select]
  1. // https://bellard.org/mersenne.html
  2. // A small C program to print the biggest prime number
  3. // Here it is (448 bytes):
  4. /*
  5. int m=1811939329,N=1,t[1<<26]={2},a,*p,i,e=73421233,s,c,U=1;g(d,h){for(i=s;i<1<<
  6. 25;i*=2)d=d*1LL*d%m;for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=p[s]*(h?c:1LL)%m,p[s]
  7. =(m*1U+*p-a)*(h?1LL:c)%m,*p=(a*1U+*p)%m,p++,c=c*1LL*d%m;}main(){while(e/=2){N*=2
  8. ;U=U*1LL*(m+1)/2%m;for(s=N;s/=2;)g(136,0);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;
  9. for(s=1;s<N;s*=2)g(839354248,1);for(a=0,p=t;p<t+N;)a+=*p<<(e&1),*p++=a%10,a/=10;
  10. }while(!*--p);for(t[0]--;p>=t;)putchar(48+*p--);}
  11. */
  12. // This program computes 2^74207281-1, which was the biggest known prime number in 2016 (about 23 million digits !). For more information about how it was // found and who found it, look at the GIMPS Project .
  13. //
  14. // I compiled it successfully with gcc with Linux. In order to compile it, your C compiler must support the 64 bit long long type.
  15. //
  16. // In order to have a small and yet asymptotically efficient code, I decided to do the computation of 2N-1 directly in base 10. The power involves repeated // squarings and multiplications by two. The squarings are implemented by doing fast convolutions using a Number Theoretic Transform.
  17. //
  18. // A previous version of this program to compute 2^6972593-1 won the International Obfuscated C Code Contest of Year 2000.
  19. //
  20. // Thanks to Marco Cecchi who suggested some syntactic changes to save a few characters.
  21. //
  22. // This program is Freeware.
  23. //
  24. // Fabrice Bellard - http://bellard.org/
  25. // last update: Sep 26, 2016
  26.  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: jack on October 30, 2021, 09:58:06 am
From time to time, I visit the very informative site 'rosettacode' where multi languages etudes are given side by side, it is a shame QB64 is not presented there as it should, especially unacceptable is the situation with the QS64, standing for QuickSort 64bit, not having its QB64  presence.
yes I agree, here's one for the graphics experts https://rosettacode.org/wiki/Honeycombs
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on October 30, 2021, 11:46:22 am
Quote
What is the quicksort routine that QB64 community uses?!

I've been using a recursive QuickSort, eg for Single Type:
Code: QB64: [Select]
  1. Sub QuickSort (start As Long, finish As Long, array() As Single)
  2.     Dim Hi As Long, Lo As Long, Middle As Single
  3.     Hi = finish: Lo = start
  4.     Middle = array((Lo + Hi) / 2) 'find middle of array
  5.     Do
  6.         Do While array(Lo) < Middle: Lo = Lo + 1: Loop
  7.         Do While array(Hi) > Middle: Hi = Hi - 1: Loop
  8.         If Lo <= Hi Then
  9.             Swap array(Lo), array(Hi)
  10.             Lo = Lo + 1: Hi = Hi - 1
  11.         End If
  12.     Loop Until Lo > Hi
  13.     If Hi > start Then Call QuickSort(start, Hi, array())
  14.     If Lo < finish Then Call QuickSort(Lo, finish, array())
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on October 30, 2021, 11:48:00 am
yes I agree, here's one for the graphics experts https://rosettacode.org/wiki/Honeycombs

I did that one a couple years ago in JB.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 01, 2021, 04:59:07 am
@jack
Glad that you also see the miss, will try to share rev.3 which will feature an unseen partitioning, hopefully helping in scenarios with duplicative keys almost dominating the array...

@bplus
Thanks, that's what I need, variants of QB64 community helping in refining the current fastest ones.
Since my focus is on 64bit file/string manipulations (as in the example with Wikipedia XML ~74GB having 1+billion lines), all LONG variables are obsolete i.e. 2 billion (signed, you know) are limiting dealing with big data. So, I have included your tiny (modified to be 64bit) variant as performer #3, thus we can see how my (rev.1) published on ROSETTACODE fares against yours, also as performer #2, I have put rev.2 boosting speed by just finishing with Insertionsort (nothing new), my dummy logic was to choose 7999 elements long chunks unsorted, because 7999*8<64KB, hoping the L1 data cache can house it. I have an idea to write entirely new partitioning in rev.3, we will see in practice its behavior.

Run/Performer #3 proves slower than the ROSETTACODE QB64 etude:

Code: QB64: [Select]
  1. Sub QuickSort (start As _Integer64, finish As _Integer64, array() As _Integer64)
  2.     Lo = start: Hi = finish
  3.     Middle = array((Lo + Hi) \ 2)
  4.     Do
  5.         Do While array(Lo) < Middle: Lo = Lo + 1: Loop
  6.         Do While array(Hi) > Middle: Hi = Hi - 1: Loop
  7.         If Lo <= Hi Then
  8.             Swap array(Lo), array(Hi)
  9.             Lo = Lo + 1: Hi = Hi - 1
  10.         End If
  11.     Loop Until Lo > Hi
  12.     If Hi > start Then Call QuickSort(start, Hi, array())
  13.     If Lo < finish Then Call QuickSort(Lo, finish, array())
  14.  

It would be nice fellow members to share their ideas and benchmarks, so we can pair the QuickBasic64 with QuickSort64.

Here comes the 32bit code generated by QB64 v.2.01, Core 2 Duo 2.9GHz, DDR2 266MHz:

 


Here comes the 64bit code generated by QB64 v.2.01, i5-7200U 3.1GHz, DDR4 1066MHz:

 


Wanna see modern machines running this benchmark in order to get the picture more clearly...
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 07, 2021, 08:24:10 am
Glad to share my latest refinement, source code and the two binaries (for Linux and Windows) are in the attached package.
Here comes the new Quicksort rev.3 with the new 'Magnetica' partitioning, compared side-by-side with the mainstream recursive Quicksort with 'Classica' partitioning.
Generally, we have three major scenarios:
- FEW distinct keys;
- MANY distinct keys;
- ALL distinct keys.

In first two cases, the new implementation is faster or equal to the "Standard" one:

Under Windows:

 


Under Linux:

 


Sadly, in the third case, it is somewhat slower.
Anyway, benchmarking will show the practical value of 'Magnetica', personally, I started to use it already.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 16, 2021, 03:40:05 pm
Having been "side-tracked" by tuning my old function for two weeks, resulted in writing, by chance, the FASTEST Quicksort, known to me.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Enjoy!
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 21, 2021, 07:47:54 pm
One can learn, in a lazy manner, a lot just by seeing the sort being ... animated.

Couldn't resist not to make a video showing the beautiful Magnetica train - the actual visualized sort process.

The sorting pauses for 3 seconds each time when the orange train collides with the Jndx - the right "sentinel" colored in red.

I chose for the testfile an old interview in English, ~27KB long, the window/matrix for sorting is 300 columns x 80 lines <27KB.
This type of sorts are quite useful in compression/indexing since each position demands statistics for order 1..8 bytes long Building-Blocks, inhere we sort order 1 i.e. letters.

For more fun, added Quicksort 'Classica' recursive dealing with the same array, the interesting thing here is one to compare Classica's Swaps and Comparisons versus Magnetica's ones:



Magnetica: 66,008 and 115,721
Classica: 132,663 and 355,221

Total Smackdown.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 25, 2021, 11:32:16 pm
The attached C function is the fastest quicksort I could write, so far.

Thanks to PCBoy Studios, here comes a short animated demo of Quicksort 'Magnetica' (initial release):



Now, the new function is more robust against quadratic behavior, since it was strengthened with median of 5 pivot - branchlessly on top of that!

And for all fellow members who need maximum speed in their sorting, here comes the usage of the "header" written in C, ready to go in QB64:

Code: QB64: [Select]
  1.     Sub Quicksort_QB64_v5 (ByVal QWORDS As _Offset, Byval Left As _Integer64, Byval Right As _Integer64)
  2.  
  3. Quicksort_QB64_v5 _Offset(QWORDS~&&(LBound(QWORDS~&&))), 0, UBound(QWORDS~&&) - LBound(QWORDS~&&)
  4.  

Enfun!

Oh, and  @bplus your recursive quicksort crashes (with mere 100,000 elements) without even giving an error on exit, it occurs with 'Organ Pipe' data. Your test program modified is given below in order to reproduce the crash. My advice, start using the attached QB64 "intrinsic", updated on 2021-Nov-28:

 


Code: QB64: [Select]
  1.     Sub memcpy (ByVal dest As _Offset, Byval source As _Offset, Byval bytes As Long)
  2.  
  3. _Title "Recursive Vrs NonRecursive test with Quicksort" 'b+ 2021-11-01, Sanmayce added some stuff 2021-Nov-26
  4. ArrayHigh = 2 * 50000
  5. 'ArrayHigh = 2 * 5000000
  6. ReDim Shared As _Unsigned _Integer64 n(1 To ArrayHigh), m(1 To ArrayHigh), z(1 To ArrayHigh) 'z(0 To ArrayHigh - 1)
  7.  
  8. Declare CustomType Library "qsm" ' Notice that 'CustomType' makes things work, using 'STATIC' gives errors during compilation
  9.     Sub Quicksort_QB64_v5 (ByVal QWORDS As _Offset, Byval Left As _Integer64, Byval Right As _Integer64)
  10.  
  11. 'For i = 1 To ArrayHigh
  12. '    n(i) = i '13 'i
  13. 'Next
  14. 'For i = ArrayHigh To 2 Step -1 ' Fisher Yates Shuffle
  15. '    Swap n(i), n(Int(Rnd * i) + 1)
  16. '    m(i) = n(i) ' copy m off n
  17. '    z(i) = n(i) ' copy m off n
  18. 'Next
  19.  
  20. ' Generate 'OrganPipe' data:
  21. For i = 1 To ArrayHigh
  22.     If i <= ArrayHigh \ 2 Then
  23.         n(i) = i
  24.         m(i) = n(i) ' copy m off n
  25.         z(i) = n(i) 'z(i - 1) = n(i) ' copy m off n
  26.     Else 'ArrayHigh \ 2 + 1 .. ArrayHigh
  27.         n(i) = ArrayHigh - i + 1
  28.         m(i) = n(i) ' copy m off n
  29.         z(i) = n(i) 'z(i - 1) = n(i) ' copy m off n
  30.     End If
  31. 'Print z(1), z(2)
  32. 'Print z(ArrayHigh - 1), z(ArrayHigh)
  33.  
  34.  
  35. a$ = "1234567890"
  36. b$ = "ABCDEFGHIJ"
  37.  
  38. memcpy _Offset(a$) + 1, _Offset(z(1)), 8
  39. memcpy _Offset(a$) + 1, _Offset(z(ArrayHigh)), 8
  40.  
  41. Print "Test arrays ready. Testing Recursive QuickSort first."
  42. 'n(1) = ArrayHigh
  43. 'm(1) = n(1)
  44. 'z(1) = n(1)
  45.  
  46. 'crashes with OrganPipe
  47. T# = Timer(.001)
  48. QuickSort 1, ArrayHigh
  49. QuickSortT# = Timer(.001) - T#
  50. For i = 1 To ArrayHigh - 1
  51.     If n(i) > n(i + 1) Then Print "NOT OK!": End
  52. Print "QuickSort checked, QuickSort time was"; QuickSortT#
  53. 1
  54.  
  55. T# = Timer(.001)
  56. Quicksort_QB64
  57. QuicksortQB64T# = Timer(.001) - T#
  58. For i = 1 To ArrayHigh - 1
  59.     If m(i) > m(i + 1) Then Print "NOT OK!": End
  60. Print "Quicksort_QB64 checked, Quicksort_QB64 time was"; QuicksortQB64T#
  61.  
  62.  
  63. 'T# = Timer(.001)
  64. 'Quicksort_QB64_v2
  65. 'QuicksortQB64T# = Timer(.001) - T#
  66. 'For i = 1 To ArrayHigh - 1
  67. '    If z(i) > z(i + 1) Then Print "NOT OK!": End
  68. 'Next
  69. 'Print "Quicksort_QB64_v2 checked, Quicksort_QB64_v2 time was"; QuicksortQB64T#
  70.  
  71. Print LBound(z), UBound(z), ArrayHigh
  72. 'Print _Offset(z(0))
  73. Print _Offset(z(1)), _Offset(z(LBound(z)))
  74. 'Print _Offset(z(2))
  75.  
  76. T# = Timer(.001)
  77. Quicksort_QB64_v5 _Offset(z(LBound(z))), 0, UBound(z) - LBound(z) ' with 'STATIC' library: error: invalid conversion from 'unsigned int' to 'void*' [-fpermissive] Quicksort_QB64_v4(((uptrszint)((&(((uint64*)(__ARRAY_UINTEGER64_QWORDS[0]))
  78. QuicksortQB64Tv5# = Timer(.001) - T#
  79.  
  80. Print z(1), z(2), z(3), z(4), z(5)
  81. Print z(ArrayHigh - 1), z(ArrayHigh)
  82.  
  83. For i = 1 To ArrayHigh - 1
  84.     'If z(i - 1) > z(i - 1 + 1) Then Print "NOT OK!": End
  85.     If z(i) > z(i + 1) Then Print "NOT OK!": End
  86. Print "Quicksort_QB64_v5 checked, Quicksort_QB64_v5 time was"; QuicksortQB64Tv5#
  87.  
  88. Print: Print "Verdict: On 'OrganPipe' data, QuicksortQB64v5 (in C) is "; Int(QuicksortQB64T# / QuicksortQB64Tv5#); "times faster than QuicksortQB64 (in QB64)."
  89.  
  90. ' recursive
  91. Sub QuickSort (start As _Unsigned _Integer64, finish As _Unsigned _Integer64)
  92.     Lo = start: Hi = finish
  93.     Middle = n((Lo + Hi) \ 2)
  94.     Do
  95.         Do While n(Lo) < Middle: Lo = Lo + 1: Loop
  96.         Do While n(Hi) > Middle: Hi = Hi - 1: Loop
  97.         If Lo <= Hi Then
  98.             Swap n(Lo), n(Hi)
  99.             Lo = Lo + 1: Hi = Hi - 1
  100.         End If
  101.     Loop Until Lo > Hi
  102.     If Hi > start Then QuickSort start, Hi
  103.     If Lo < finish Then QuickSort Lo, finish
  104.  
  105. ' non recursive
  106. ' ref:  https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#QB64
  107. Sub Quicksort_QB64
  108.     Left = LBound(m)
  109.     Right = UBound(m)
  110.     LeftMargin = Left
  111.     ReDim Stack&&(Left To Right)
  112.     StackPtr = 0
  113.     StackPtr = StackPtr + 1
  114.     Stack&&(StackPtr + LeftMargin) = Left
  115.     StackPtr = StackPtr + 1
  116.     Stack&&(StackPtr + LeftMargin) = Right
  117.     Do 'Until StackPtr = 0
  118.         Right = Stack&&(StackPtr + LeftMargin)
  119.         StackPtr = StackPtr - 1
  120.         Left = Stack&&(StackPtr + LeftMargin)
  121.         StackPtr = StackPtr - 1
  122.         Do 'Until Left >= Right
  123.             Pivot~&& = m((Left + Right) \ 2)
  124.             Indx = Left
  125.             Jndx = Right
  126.             Do
  127.                 Do While (m(Indx) < Pivot~&&)
  128.                     Indx = Indx + 1
  129.                 Loop
  130.                 Do While (m(Jndx) > Pivot~&&)
  131.                     Jndx = Jndx - 1
  132.                 Loop
  133.                 If Indx <= Jndx Then
  134.                     If Indx < Jndx Then Swap m(Indx), m(Jndx)
  135.                     Indx = Indx + 1
  136.                     Jndx = Jndx - 1
  137.                 End If
  138.             Loop While Indx <= Jndx
  139.             If Indx < Right Then
  140.                 StackPtr = StackPtr + 1
  141.                 Stack&&(StackPtr + LeftMargin) = Indx
  142.                 StackPtr = StackPtr + 1
  143.                 Stack&&(StackPtr + LeftMargin) = Right
  144.             End If
  145.             Right = Jndx
  146.         Loop Until Left >= Right
  147.     Loop Until StackPtr = 0
  148.  
  149.  
  150. Sub Quicksort_QB64_v2
  151.  
  152.     InsertionsortTHRESHOLD = 0 '19
  153.     Left = LBound(z)
  154.     Right = UBound(z)
  155.     ReDim Stack&&(Left To Right)
  156.     StackPtr = 0
  157.     StackPtr = StackPtr + 1
  158.     Stack&&(StackPtr + LeftMargin) = Left
  159.     StackPtr = StackPtr + 1
  160.     Stack&&(StackPtr + LeftMargin) = Right
  161.     Do 'Until StackPtr = 0
  162.         Right = Stack&&(StackPtr)
  163.         Left = Stack&&(StackPtr - 1)
  164.         StackPtr = StackPtr - 2
  165.         Do 'Until Left >= Right
  166.  
  167.             ''Classica' partitioning [
  168.             'Pivot~&& = z((Left + Right) \ 2)
  169.             'Indx = Left
  170.             'Jndx = Right
  171.             'Do
  172.             '    Do While (z(Indx) < Pivot~&&)
  173.             '        Indx = Indx + 1
  174.             '    Loop
  175.             '    Do While (z(Jndx) > Pivot~&&)
  176.             '        Jndx = Jndx - 1
  177.             '    Loop
  178.             '    If Indx <= Jndx Then
  179.             '        If Indx < Jndx Then Swap z(Indx), z(Jndx)
  180.             '        Indx = Indx + 1
  181.             '        Jndx = Jndx - 1
  182.             '    End If
  183.             'Loop While Indx <= Jndx
  184.             ''Classica' partitioning ]
  185.  
  186.             ' 'Magnetica' partitioning [
  187.             Jndx = Right
  188.             PL = Left
  189.             PR = Left
  190.             Swap z((Left + Right) \ 2), z(PR) 'Swap z(Left + (Right - Left) \ 4), z(PR)
  191.             Pivot~&& = z(PR)
  192.             Do While PR < Jndx
  193.                 If Pivot~&& > z(PR + 1) Then
  194.                     Swap z(PL), z(PR + 1)
  195.                     PL = PL + 1
  196.                     PR = PR + 1
  197.                 ElseIf Pivot~&& = z(PR + 1) Then
  198.                     PR = PR + 1
  199.                 Else ' < i.e. Pivot~&& < z(PR + 1)
  200.                     Do While Pivot~&& < z(Jndx)
  201.                         Jndx = Jndx - 1
  202.                     Loop
  203.                     If PR + 1 < Jndx Then Swap z(PR + 1), z(Jndx)
  204.                     Jndx = Jndx - 1
  205.                 End If
  206.             Loop
  207.             Jndx = PL - 1
  208.             Indx = PR + 1
  209.             ' 'Magnetica' partitioning ]
  210.  
  211.             If Indx + InsertionsortTHRESHOLD < Right Then 'if the remaining chunk is bigger than 'InsertionsortTHRESHOLD' push it to stack, otherwise leave all such chunks unsorted
  212.                 StackPtr = StackPtr + 2
  213.                 Stack&&(StackPtr - 1) = Indx
  214.                 Stack&&(StackPtr) = Right
  215.             End If
  216.             Right = Jndx
  217.         Loop Until Left >= Right
  218.     Loop Until StackPtr = 0
  219.     'Left = LBound(z)
  220.     'Right = UBound(z)
  221.     'For i = Left + 1 To Right ' i.e. 1 to size-1 omitting the first (which is 0)
  222.     '    j = i
  223.     '    Do While j >= 1 'Nah, start using a sentinel
  224.     '        If z(j - 1) > z(j) Then Swap z(j - 1), z(j) Else Exit Do
  225.     '        j = j - 1
  226.     '    Loop
  227.     'Next i
  228.  

Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: bplus on November 26, 2021, 12:21:35 pm
Quote
Oh, and  @bplus your recursive quicksort crashes (with mere 100,000 elements) without even giving an error on exit,

Did 100,000,000 items for me without mods:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on November 28, 2021, 05:44:30 pm
Did 100,000,000 items for me without mods:

You didn't notice what the QB64 snippet holds, in above post. It is your test, but modified to sort 'Organ Pipe' instead of 'Random' dataset. It crashes with 100,000 using QB64 32bit. It is interesting to see how much QB64 64bit can handle before crashing. Beside this, qsm.h is from 11x to 2x faster, that's why I recommend it. In the screenshot below, Run #1 is your QB64 code, whereas Run #2 is qsm.h:

 


Code: QB64: [Select]
  1. Laptop Intel i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
  2. +--------------------+---------------------------+---------------------------+---------------------------+
  3. | Performer/Keys     | FEW distinct              | MANY distinct             | ~ALL distinct             |
  4. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  5. |  Operating System, | Windows 10, | Fedora 33,  | Windows 10, | Fedora 33,  | Windows 10, | Fedora 33,  |
  6. |      Compiler, -O3 | Intel v15.0 | GCC 10.2.1  | Intel v15.0 | GCC 10.2.1  | Intel v15.0 | GCC 10.2.1  |
  7. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  8. | qsort              |  58 seconds | 360 seconds | 343 seconds | 535 seconds | 444 seconds | 519 seconds |
  9. | Magnetica r.2      |  35 seconds |  35 seconds | 214 seconds | 222 seconds | 271 seconds | 286 seconds |
  10. | Bentley-McIlroy    |  39 seconds |  41 seconds | 203 seconds | 230 seconds | 275 seconds | 313 seconds |
  11. +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+
  12. Legend (The time is exactly the Sort process time):
  13. FEW = 2,233,861,800 keys, of them distinct = 10;
  14. MANY = 2,482,300,900 keys, of them distinct = 2,847,531;
  15. ~ALL = 2,009,333,753 keys, of them distinct = 1,912,608,132
  16.  

Quick highlights:
- GLIBC's qsort is just trash;
- Intel's qsort is trashy;
- Bentley-McIlroy is good, however the disassembly (-O3) shows many weird vector instructions used, not good for a scalar code;
- Magnetica r.2 is nice, the disassembly (-O3) gladdens the eyes.

Finally, wanted all fellow members, interested in writing their own "intrinsics" (in its original sense - "essential"), to have one booklet showing how much C code can reinforce the QB64 muscle flexing:

 


With this my Quicksort detour is completed.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 07, 2021, 10:13:37 pm
With Quicksort 'Magnetica' in our toolbox, now Masakari r.8.1++ has been enriched with an unseen functionality, namely, sorting by linesize!

Sometimes, the need to view broken/long lines arises, then Masakari comes sorting them, FAST!

Looking what the most powerful editor UltraEdit v28.20 (latest version) can do with loaded file:
https://www.ultraedit.com/wiki/images/2/25/Ultraedit_sort.png (https://www.ultraedit.com/wiki/images/2/25/Ultraedit_sort.png)

I see only the basic functionality, but when comes to spotting/browsing longest lines in huge files UE is not ultra enough, to fill the gap, here comes the fastest sorter combined with the fastest scheme of representing the lines - a pair of QWORDS: Offset:Length, naturally the sorting is simplified down to sorting all those pairs without accessing external RAM nor computing length of lines.

Again the longest XML file (English Wikipedia) is our testdataset:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

The shortcut 'Shift+1' sorts by Length, the longest line is at the bottom:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

The shortcut 'Shift+2' sorts by Offset, in fact, it returns the original file (instead of reloading it) i.e. REVERT.

As far as I know, there is still no tool/editor capable to sort 1+ billion lines in  (5:01:02 - 4:59:15) = 107 seconds and allow to browse all the longest lines.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 09, 2021, 09:37:31 am
Being a nasty bottleneck in Case-Insensitive searching, UCASE$() function needs a overhaul.

Glad to share another superfast function - UCASE_XMM, it replaces the superslow UCASE$() built-in.
Vectorization using XMM registers trumps bigtime the scalar variant.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

My intent is to include more superfast functions in next edition of my "manatarka" custom library, QB64 deserves some boost in textual department, as:

- a replacement for INSTR() built-in, memmem(), the FASTEST variant (to my knowledge) - Railgun();
- 128bit hasher, the FASTEST variant (to my knowledge) - Gumbotron();
- UCASE_YMM, the AVX variant.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 10, 2021, 02:26:35 am
Did some comparisons, INSTR() vs my SCALAR and VECTOR Railgun() functions, the bottomline is INSTR() is no match to the monstrously optimized memmem() variants of mine.

Okay, the testmachine is my laptop with i5-7200U, 36GB DDR4, the testdatafile is the ~4MB King James Bible.

The speedup is awesome, keep in mind the longer the Needle/Pattern the bigger the speedup becomes, short needles in range 2..6 are not that indicative of how superfast Railgun() is:

My SCALAR memmem(), called Railgun_Trolldom, is 2543/1413= 1.79x faster than INSTR() when the Needle is "gods".
My VECTOR memmem(), called Railgun_Nyotengu, is 6359/1413= 4.50x faster than INSTR() when the Needle is "gods".

As for the UCASE_XMM, the speedup is 30x to 60x:

 


In the future, UCASE_XMM is to be incorporated into NyoTengu_XMM - then we will have the FASTEST Case-Insensitive INSTR() counterpart!

The manatarka.h housing the UCASE_XMM, Railgun_Trolldom and Railgun_Nyotengu is attached along with the QB64 test program.
Enjoy!
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: SMcNeill on December 10, 2021, 02:52:27 am
Try https://www.qb64.org/wiki/STRICMP when you don't care about case while comparing strings.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 10, 2021, 03:06:46 am
Try https://www.qb64.org/wiki/STRICMP when you don't care about case while comparing strings.

This is good to have as well, but I am not aware of INSTR() that is Case-Insensitive, let alone superfast.
If we are forced to search for "gods" in the Project Gutenberg KJV Bible, case-insensitively then we have 2 more hits i.e. "Gods".
The idea is QB64 community to have even faster functions than GLIBC.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 11, 2021, 01:10:13 am
AFAIK, until now, QB64 lacks a general purpose hash function, my long experience with hashing (mostly for look-up tables) comes in handy in form of Gumbotron().

My Gumbotron hash function (more in Reply #47 in this thread) is the fastest 128bit hasher, it comes in XMM and YMM variants i.e. for SSE4.1 and AVX2, while generating the same hash. The screenshot shows the Gumbotron_YMM giving the correct hash (as it should be, given in the orange console by Nakamichi):

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

It returns a pair of QWORDS, so if the usecase demands 64bit hash you can use either loPart or HiPart.
It is nearly as fast as the fastest 64bit hashers, but much stronger. In practice, 64bit hashers generate a lot of collisions even for casual tasks dealing with few million (try 7 billion - e.g. the names of all people) keys, nah, Gumbotron's 2x64bit scheme proves supereffective, my latest compressor Nakamichi uses this very hash without any problems - heavily tested hasher - battle-tested it is.
Imagine a search scenario where you have many keys/elements (different in length, or not), then by hashing them you can tighten them down to 16 bytes, after that you can use Quicksort 'Magnetica' to sort those hashes, and "finalize" with goodold Binary-Search.
In Nakamichi, I exploit Gumbotron even better, due to its superior 128bit-ness, it is used as a lossy compressor - shrinking all kind of keys 16+ in size (18, ... 256) down to 16 bytes. If there was a single collision then big problems would ensue, but the linear mixer provided by AES is doing great job, so, no problema.

The full source (and Windows binary) is attached.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on December 26, 2021, 11:48:14 pm
I was able to speed up a little (~300ms, down to 1,677 ms) the spell-check rate by checking only the words with equal length.
That is, the previous stupid checking of each word against the whole 1,000,000+ Binary-Search pool now was limited only to THE fraction of the pool where the corresponding length is located - which lowers the number of seeks/comparisons.

Additionally, all the UNFAMILIAR words, now, are dumped as an index, but placed in the very beginning, in order of appearance.
Thanks to that feature, one is allowed quickly to spot misspelled words, as I did only with a few glances, 2 buggy "daughters" found:
daughers
daughers


Project Gutenberg failed to deliver quality, obviously the correctors still rely on non-automatic methods.

Finally, we have a decent benchmark utilizing the Binary-Search in a speedy manner, it is a good start for all kind of experiments since it is creating as a result the .HTM counterpart (with all unfamiliar words in BOLD, all OED distinct words are used as a spell-check wordlist) of our .TXT file:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

It throws all the words of KJV Bible at OED 2nd edition, which is 700,000+ words against the 1,000,000+ OED words:

  [ This attachment cannot be displayed inline in 'Print Page' view ]

The spotted errors are to go along with the entire .HTM into .DOC|.PDF file for hardcopy i.e. paper reviewing, with good old pencils:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Spell-checking KJV Bible in 1.677 seconds, can we do better?

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

On Linux, the newer GCC (v10.2.1) generates 100ms faster code, lowering the conversion down to:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Anyway, this TXT2HTM code will be part of incoming Masakari r.9, enabling having spell-checked .HTMs only a key and few seconds away...

The source code and binaries for Linux and Windows (also the OED wordlist) are in the attached package.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on February 22, 2022, 03:52:53 am
Glad to share the latest-n-fastest Quicksort around - Magnetica r.5 - the source code is attached.

 


I spotted a conditional swap within the mainloop, now, in r.5 this branch is removed and put outside the hottest loop.

So, r.5 is algorithmically superior compared to r.4, the performance varies between AMD and Intel, between ICL and GCC, overall it pushes the limits once more.

Behold the simplicity itself:
Code: QB64: [Select]
  1. // Magnetica r.5BB:
  2. /*
  3. ; mark_description "Intel(R) C++ Compiler XE for applications running on Intel(R) 64, Version 15.0.0.108 Build 20140726";
  4. ; mark_description "-S -O3 -D_N_HIGH_PRIORITY";
  5.  
  6. Quicksort_QB64_v9       PROC
  7. ; parameter 1: rcx
  8. ; parameter 2: rdx
  9. ; parameter 3: r8
  10. .B12.1::                        ; Preds .B12.0
  11.         push      r13                                           ;1172.72
  12.         push      r14                                           ;1172.72
  13.         push      r15                                           ;1172.72
  14.         push      rbp                                           ;1172.72
  15.         mov       eax, 800024                                   ;1172.72
  16.         call      __chkstk                                      ;1172.72
  17.         sub       rsp, 800024                                   ;1172.72
  18.         mov       eax, 2                                        ;1191.5
  19.         mov       QWORD PTR [40+rsp], rdx                       ;1190.17
  20.         mov       QWORD PTR [48+rsp], r8                        ;1191.17
  21.                                
  22. .B12.2::                        ; Preds .B12.20 .B12.1
  23.         mov       rdx, QWORD PTR [32+rsp+rax*8]                 ;1193.17
  24.         mov       r13, QWORD PTR [24+rsp+rax*8]                 ;1194.16
  25.         add       rax, -2                                       ;1195.31
  26.         cmp       r13, rdx                                      ;1197.47
  27.         jge       .B12.20       ; Prob 10%                      ;1197.47
  28.                                
  29. .B12.3::                        ; Preds .B12.2
  30.         mov       r9, r13                                       ;1199.13
  31.                                
  32. .B12.4::                        ; Preds .B12.18 .B12.3
  33.         mov       r10, QWORD PTR [rcx+r13*8]                    ;1229.13
  34.         lea       r15, QWORD PTR [r13+rdx]                      ;1229.48
  35.         sar       r15, 1                                        ;1229.56
  36.         mov       r14, r13                                      ;1200.13
  37.         mov       r11, rdx                                      ;1198.13
  38.         mov       rbp, r9                                       ;1199.13
  39.         mov       r9, r14                                       ;1200.13
  40.         mov       r8, QWORD PTR [rcx+r15*8]                     ;1229.13
  41.         mov       QWORD PTR [rcx+r15*8], r10                    ;1229.13
  42.         mov       QWORD PTR [rcx+r13*8], r8                     ;1229.13
  43.                                
  44. .B12.5::                        ; Preds .B12.4 .B12.13
  45.         inc       r14                                           ;1282.27
  46.         mov       r10, QWORD PTR [rcx+r14*8]                    ;1283.29
  47.         cmp       r8, r10                                       ;1283.29
  48.         ja        .B12.12       ; Prob 22%                      ;1283.29
  49.                                
  50. .B12.6::                        ; Preds .B12.5
  51.         jae       .B12.13       ; Prob 50%                      ;1287.36
  52.                                
  53. .B12.7::                        ; Preds .B12.6
  54.         mov       r15, QWORD PTR [rcx+r11*8]                    ;1288.35
  55.         cmp       r8, r15                                       ;1288.35
  56.         jae       .B12.11       ; Prob 10%                      ;1288.35
  57.                                
  58. .B12.9::                        ; Preds .B12.7 .B12.9
  59.         dec       r11                                           ;1289.39
  60.         mov       r15, QWORD PTR [rcx+r11*8]                    ;1288.35
  61.         cmp       r8, r15                                       ;1288.35
  62.         jb        .B12.9        ; Prob 82%                      ;1288.35
  63.                                
  64. .B12.11::                       ; Preds .B12.9 .B12.7
  65.         mov       QWORD PTR [rcx+r14*8], r15                    ;1291.21
  66.         dec       r14                                           ;1296.31
  67.         mov       QWORD PTR [rcx+r11*8], r10                    ;1291.21
  68.         dec       r11                                           ;1295.35
  69.         jmp       .B12.13       ; Prob 100%                     ;1295.35
  70.                                
  71. .B12.12::                       ; Preds .B12.5
  72.         mov       r15, QWORD PTR [rcx+rbp*8]                    ;1284.21
  73.         mov       QWORD PTR [rcx+rbp*8], r10                    ;1284.21
  74.         inc       rbp                                           ;1285.31
  75.         mov       QWORD PTR [rcx+r14*8], r15                    ;1284.21
  76.                                
  77. .B12.13::                       ; Preds .B12.12 .B12.11 .B12.6
  78.         cmp       r14, r11                                      ;1281.24
  79.         jl        .B12.5        ; Prob 82%                      ;1281.24
  80.                                
  81. .B12.14::                       ; Preds .B12.13
  82.         jle       .B12.16       ; Prob 78%                      ;1299.22
  83.                                
  84. .B12.15::                       ; Preds .B12.14
  85.         mov       r8, QWORD PTR [8+rcx+r11*8]                   ;1300.21
  86.         mov       r10, QWORD PTR [8+rcx+r14*8]                  ;1300.21
  87.         mov       QWORD PTR [8+rcx+r14*8], r8                   ;1300.21
  88.         mov       QWORD PTR [8+rcx+r11*8], r10                  ;1300.21
  89.                                
  90. .B12.16::                       ; Preds .B12.14 .B12.15
  91.         inc       r14                                           ;1655.25
  92.         cmp       rdx, r14                                      ;1730.49
  93.         jle       .B12.18       ; Prob 62%                      ;1730.49
  94.                                
  95. .B12.17::                       ; Preds .B12.16
  96.         add       rax, 2                                        ;1731.39
  97.         mov       QWORD PTR [24+rsp+rax*8], r14                 ;1732.17
  98.         mov       QWORD PTR [32+rsp+rax*8], rdx                 ;1733.17
  99.                                
  100. .B12.18::                       ; Preds .B12.17 .B12.16
  101.         lea       rdx, QWORD PTR [-1+rbp]                       ;1654.25
  102.         cmp       r13, rdx                                      ;1197.47
  103.         jl        .B12.4        ; Prob 82%                      ;1197.47
  104.                                
  105. .B12.20::                       ; Preds .B12.18 .B12.2
  106.         DB        15                                            ;1743.28
  107.         DB        31                                            ;1743.28
  108.         DB        64                                            ;1743.28
  109.         DB        0                                             ;1743.28
  110.         DB        15                                            ;1743.28
  111.         DB        31                                            ;1743.28
  112.         DB        128                                           ;1743.28
  113.         DB        0                                             ;1743.28
  114.         DB        0                                             ;1743.28
  115.         DB        0                                             ;1743.28
  116.         DB        0                                             ;1743.28
  117.         test      rax, rax                                      ;1743.28
  118.         jne       .B12.2        ; Prob 99%                      ;1743.28
  119.                                
  120. .B12.21::                       ; Preds .B12.20
  121.         add       rsp, 800024                                   ;1753.1
  122.         pop       rbp                                           ;1753.1
  123.         pop       r15                                           ;1753.1
  124.         pop       r14                                           ;1753.1
  125.         pop       r13                                           ;1753.1
  126.         ret                                                     ;1753.1
  127.         ALIGN     16
  128.                                
  129. .B12.22::
  130. ; mark_end;
  131. Quicksort_QB64_v9 ENDP
  132. */

In order gladly to say QB64 stands for "Quickness" once again, my wish is QB64 community to have the qsm.h header (built-in function to QB64 library) outperforming both qsort() C implementations of Intel and GNU, enjoy.
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on March 08, 2022, 05:10:05 pm
A week ago, Scandum released a killer, the current BEST Quicksort, named Crumsort, being the FASTEST unstable, in-place, Quicksort in my tests.

As I see it, he did dive deep in sorting, achieving outstanding results.

Yet, intuitively, I see different approach, which potentially can reach and even surpass his awesome speeds, to be seen...

Currently, the picture of hi-speed sorting is this (in order to reproduce the results, the benchmark package is attached):

Code: [Select]
// Test run: 2022-Mar-08:
// Laptop "Compressionette", Intel 'Kaby Lake' i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | Performer/Keys     | #1, FEW distinct          | #2, MANY distinct         | #3, MANYmore distinct     | #4, ALL distinct          | #5, ALLmore distinct       | #6, ALLmax distinct         |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// |  Operating System, | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,  | Windows 10, | Fedora 35,   | Windows 10,  | Fedora 35,   |
// |      Compiler, -O3 | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1   | Intel v15.0  | GCC 11.2.1   |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | qsort              |  59 seconds | 377 seconds | 336 seconds | 541 seconds | 157 seconds | 195 seconds | 435 seconds | 534 seconds | 851 seconds | 1036 seconds |         N.A. |         N.A. |
// | Magnetica v.13     |  31 seconds |  30 seconds | 202 seconds | 196 seconds |  88 seconds |  85 seconds | 259 seconds | 250 seconds | 506 seconds |  493 seconds |         N.A. |         N.A. |
// | Bentley-McIlroy    |  38 seconds |  36 seconds | 205 seconds | 208 seconds |  92 seconds |  94 seconds | 279 seconds | 281 seconds | 544 seconds |  553 seconds |         N.A. |         N.A. |
// | Crumsort           |  30 seconds |  32 seconds | 132 seconds | 150 seconds |  64 seconds |  70 seconds | 184 seconds | 192 seconds | 357 seconds |  376 seconds |         N.A. |         N.A. |
// +--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
// | Best Time (bare    |                           |                           |                           |                           |                            |                             |
// | bone in-place QS): |  30s PARITY               | 132s for Crumsort         |  64s for Crumsort         | 184s for Crumsort         | 357s for Crumsort          | N.A.                        |
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
Code: [Select]
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | Performer/Keys     | #1, FEW distinct          | #2, MANY distinct         | #3, MANYmore distinct     | #4, ALL distinct          | #5, ALLmore distinct       | #6, ALLmax distinct         |
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// |  Operating System, | Fedora 35, GCC 11.2.1     | Fedora 35, GCC 11.2.1     | Fedora 35, GCC 11.2.1     | Fedora 35, GCC 11.2.1     | Fedora 35, GCC 11.2.1      | Fedora 35, GCC 11.2.1       |
// |      Compiler, -O3 | instructions; IPC         | instructions; IPC         | instructions; IPC         | instructions; IPC         | instructions; IPC          | instructions; IPC           |
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
// | qsort              |   3,302,993,934,921; 2.75 |   2,983,579,082,155; 1.75 |     886,263,153,476; 1.41 |   2,352,769,705,563; 1.38 |    4,527,367,288,814; 1.39 |                        N.A. |
// | Magnetica v.13     |     131,873,917,282; 1.00 |     658,478,895,600; 1.02 |     309,149,594,748; 1.08 |     884,297,729,161; 1.06 |    1,726,931,029,634; 1.08 |                        N.A. |
// | Bentley-McIlroy    |     164,915,835,204; 1.09 |     681,956,155,364; 1.00 |     322,584,009,352; 1.04 |     944,038,959,690; 1.02 |    1,719,825,062,847; 0.97 |                        N.A. |
// | Crumsort           |     312,328,497,447; 2.29 |   1,295,551,817,497; 2.57 |     603,276,911,007; 2.53 |   1,597,685,291,532; 2.46 |    3,091,001,982,856; 2.51 |                        N.A. |
// +--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+

Code: [Select]
// Speed Roster, (the base speed 1.00x is GLIBC's qsort):
// Rank #1: 2683/820=  3.27x =  32+150+ 70+192+ 376=  820 seconds for Crumsort
// Rank #2: 2683/1054= 2.54x =  30+196+ 85+250+ 493= 1054 seconds for Magnetica v.13
// Rank #3: 2683/1172= 2.28x =  36+208+ 94+281+ 553= 1172 seconds for Bentley-McIlroy
// Rank #4: 2683/2683= 1.00x = 377+541+195+534+1036= 2683 seconds for GLIBC's qsort
//
// Legend (The time is exactly the Sort process time):
// #1,FEW = 2,233,861,800 keys, of them distinct = 10; 178,708,944 bytes 22338618_QWORDS.bin; elements = 178,708,944/8 *100; // Keys are 100 times duplicated
// #2,MANY = 2,482,300,900 keys, of them distinct = 2,847,531; 24,823,016 bytes mobythesaurus.txt; elements = 24823016 -8+1; // BuildingBlocks are size-order+1, they are 100 times duplicated
// #3,MANYmore = 1,137,582,073 keys, of them distinct = 77,275,994; 1,137,582,080 bytes linux-5.15.25.tar; elements = 1137582080 -8+1; // BuildingBlocks are size-order+1
// #4,ALL = 2,009,333,753 keys, of them distinct = 1,912,608,132; 2,009,333,760 bytes Fedora-Workstation-Live-x86_64-35-1.2.iso; elements = 2009333760 -8+1; // BuildingBlocks are size-order+1
// #5,ALLmore = 3,803,483,825 keys, of them distinct = 3,346,259,533; 3,803,483,832 bytes Fedora-Workstation-35-1.2.aarch64.raw.xz; elements = 3803483832 -8+1; // BuildingBlocks are size-order+1
// #6,ALLmax = 7,798,235,435 keys, of them distinct = 6,770,144,405; 7,798,235,442 bytes math.stackexchange.com_en_all_2019-02.zim; elements = 7798235442 -8+1; // BuildingBlocks are size-order+1
Code: [Select]
// Notes:
// - Scandum's Crumsort is the FASTEST in-place sorter, known to me, hail Scandum!
// - All the runs were in "Current priority class is REALTIME_PRIORITY_CLASS" for Windows and "Current priority is -20." for Linux;
// To see more stats (the tables were deriving from) see 'log_i5-7200U_MAR08.txt';
// - Benchmark needs 32GB RAM, and 64GB for the 6th testset;
// - The whole package (except the 3rd, 4th, 5th and 6th datasets) is downloadable at:
//   www.sanmayce.com/QS_showdown_r13.zip
// - To reproduce the roster, run on Windows or Linux:
//   - BENCH_ICL32GB.BAT
//   - BENCH_ICL64GB.BAT
//   - sh bench_gcc32GB.sh
//   - sh bench_gcc64GB.sh
// - 3rd dataset is downloadable at:
// https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.25.tar.xz
// - 4th dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-35-1.2.iso
// - 5th dataset is downloadable at:
// https://download.fedoraproject.org/pub/fedora/linux/releases/35/Workstation/aarch64/images/Fedora-Workstation-35-1.2.aarch64.raw.xz
// - 6th dataset is downloadable at:
// https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2019-02.zim
// - Managed to reduce the mainloop down to 68 bytes (from 71 in r.12), the gain comes from switching to pointers, had to do that long time ago, wanted to keep the etude ARRAY-syntax friendly. Now, r.12 uses arrays, whereas r.13 uses pointers. Another turning point, GCC now beats ICL in all tests.

The current best is at:
https://github.com/scandum/crumsort

Here comes Magnetica v13, a view from the kitchen, this time around, GCC v11.2.1 proves superior to ICL v15.0, generating faster code in all tests:
Code: [Select]
// And the Assembly code generated by GCC 11.2.1 for Magnetica_v13:
// 001 Quicksort_QB64_v13:
// 002 .LFB214:
// 003 .cfi_startproc
// 004 pushq %r15
// 005 .cfi_def_cfa_offset 16
// 006 .cfi_offset 15, -16
// 007 leaq -8(%rdi,%rsi,8), %r10
// 008 movq %rdi, %xmm0
// 009 movq %rdi, %rax
// 010 pushq %r14
// 011 .cfi_def_cfa_offset 24
// 012 .cfi_offset 14, -24
// 013 movq %r10, %xmm2
// 014 movl $2, %r15d
// 015 pushq %r13
// 016 .cfi_def_cfa_offset 32
// 017 .cfi_offset 13, -32
// 018 punpcklqdq %xmm2, %xmm0
// 019 pushq %r12
// 020 .cfi_def_cfa_offset 40
// 021 .cfi_offset 12, -40
// 022 pushq %rbp
// 023 .cfi_def_cfa_offset 48
// 024 .cfi_offset 6, -48
// 025 pushq %rbx
// 026 .cfi_def_cfa_offset 56
// 027 .cfi_offset 3, -56
// 028 subq $143920, %rsp
// 029 .cfi_def_cfa_offset 143976
// 030 movups %xmm0, -96(%rsp)
// 031 .p2align 4,,10
// 032 .p2align 3
// 033 .L5115:
// 034 movq %r10, %rcx
// 035 subq $2, %r15
// 036 subq %rax, %rcx
// 037 testq %rcx, %rcx
// 038 jle .L5096
// 039 leaq 8(%rax), %rbx
// 040 .L5113:
// 041 movq %rcx, %rsi
// 042 movq (%rax), %rdx
// 043 sarq $3, %rsi
// 044 cmpq $55, %rcx
// 045 ja .L5097
// 046 jmp *.L5099(,%rsi,8)
// 047 .section .rodata
// 048 .align 8
// 049 .align 4
// 050 .L5099:
// 051 .quad .L5097
// 052 .quad .L5104
// 053 .quad .L5103
// 054 .quad .L5102
// 055 .quad .L5101
// 056 .quad .L5100
// 057 .quad .L5098
// 058 .text
// 059 .p2align 4,,10
// 060 .p2align 3
// 061 .L5098:
// 062 movq 8(%rax), %rbp
// 063 movq 16(%rax), %rbx
// 064 xorl %ecx, %ecx
// 065 movq 24(%rax), %r11
// 066 movq 32(%rax), %r10
// 067 cmpq %rdx, %rbp
// 068 movq 40(%rax), %r9
// 069 movq 48(%rax), %r12
// 070 setb %cl
// 071 cmpq %rdx, %rbx
// 072 adcl $0, %ecx
// 073 cmpq %rdx, %r11
// 074 adcl $0, %ecx
// 075 cmpq %rdx, %r10
// 076 adcl $0, %ecx
// 077 cmpq %rdx, %r9
// 078 adcl $0, %ecx
// 079 cmpq %rdx, %r12
// 080 adcl $0, %ecx
// 081 xorl %r8d, %r8d
// 082 cmpq %rdx, %rbp
// 083 movl %ecx, -108(%rsp)
// 084 setnb %r8b
// 085 xorl %ecx, %ecx
// 086 cmpq %rbx, %rbp
// 087 seta %cl
// 088 addl %ecx, %r8d
// 089 xorl %ecx, %ecx
// 090 cmpq %r11, %rbp
// 091 seta %cl
// 092 addl %ecx, %r8d
// 093 xorl %ecx, %ecx
// 094 cmpq %r10, %rbp
// 095 seta %cl
// 096 addl %ecx, %r8d
// 097 xorl %ecx, %ecx
// 098 cmpq %r9, %rbp
// 099 seta %cl
// 100 addl %ecx, %r8d
// 101 xorl %ecx, %ecx
// 102 cmpq %r12, %rbp
// 103 seta %cl
// 104 xorl %edi, %edi
// 105 addl %ecx, %r8d
// 106 cmpq %rdx, %rbx
// 107 setnb %dil
// 108 xorl %ecx, %ecx
// 109 cmpq %rbx, %rbp
// 110 setbe %cl
// 111 addl %ecx, %edi
// 112 xorl %ecx, %ecx
// 113 cmpq %r11, %rbx
// 114 seta %cl
// 115 addl %ecx, %edi
// 116 xorl %ecx, %ecx
// 117 cmpq %r10, %rbx
// 118 seta %cl
// 119 addl %ecx, %edi
// 120 xorl %ecx, %ecx
// 121 cmpq %r9, %rbx
// 122 seta %cl
// 123 addl %ecx, %edi
// 124 xorl %ecx, %ecx
// 125 cmpq %r12, %rbx
// 126 seta %cl
// 127 xorl %esi, %esi
// 128 addl %ecx, %edi
// 129 cmpq %rdx, %r11
// 130 setnb %sil
// 131 xorl %ecx, %ecx
// 132 cmpq %r11, %rbp
// 133 setbe %cl
// 134 addl %ecx, %esi
// 135 xorl %ecx, %ecx
// 136 cmpq %r11, %rbx
// 137 setbe %cl
// 138 addl %ecx, %esi
// 139 xorl %ecx, %ecx
// 140 cmpq %r10, %r11
// 141 seta %cl
// 142 addl %ecx, %esi
// 143 xorl %ecx, %ecx
// 144 cmpq %r9, %r11
// 145 seta %cl
// 146 addl %ecx, %esi
// 147 xorl %ecx, %ecx
// 148 cmpq %r12, %r11
// 149 seta %cl
// 150 addl %ecx, %esi
// 151 xorl %ecx, %ecx
// 152 cmpq %rdx, %r10
// 153 setnb %cl
// 154 xorl %r13d, %r13d
// 155 cmpq %r10, %rbp
// 156 setbe %r13b
// 157 addl %r13d, %ecx
// 158 xorl %r13d, %r13d
// 159 cmpq %r10, %rbx
// 160 setbe %r13b
// 161 addl %r13d, %ecx
// 162 xorl %r13d, %r13d
// 163 cmpq %r10, %r11
// 164 setbe %r13b
// 165 addl %r13d, %ecx
// 166 xorl %r13d, %r13d
// 167 cmpq %r9, %r10
// 168 seta %r13b
// 169 addl %r13d, %ecx
// 170 xorl %r13d, %r13d
// 171 cmpq %r12, %r10
// 172 seta %r13b
// 173 xorl %r14d, %r14d
// 174 addl %r13d, %ecx
// 175 cmpq %rdx, %r9
// 176 setnb %r14b
// 177 xorl %r13d, %r13d
// 178 cmpq %r9, %rbp
// 179 setbe %r13b
// 180 addl %r14d, %r13d
// 181 xorl %r14d, %r14d
// 182 cmpq %r9, %rbx
// 183 setbe %r14b
// 184 addl %r13d, %r14d
// 185 xorl %r13d, %r13d
// 186 cmpq %r9, %r11
// 187 setbe %r13b
// 188 addl %r14d, %r13d
// 189 xorl %r14d, %r14d
// 190 cmpq %r9, %r10
// 191 setbe %r14b
// 192 addl %r13d, %r14d
// 193 xorl %r13d, %r13d
// 194 cmpq %r12, %r9
// 195 seta %r13b
// 196 addl %r14d, %r13d
// 197 movslq -108(%rsp), %r14
// 198 movq %rdx, (%rax,%r14,8)
// 199 movslq %r8d, %rdx
// 200 movl -108(%rsp), %r14d
// 201 movq %rbp, (%rax,%rdx,8)
// 202 movslq %edi, %rdx
// 203 movq %rbx, (%rax,%rdx,8)
// 204 movslq %esi, %rdx
// 205 movq %r11, (%rax,%rdx,8)
// 206 movslq %ecx, %rdx
// 207 movq %r10, (%rax,%rdx,8)
// 208 movslq %r13d, %rdx
// 209 movq %r9, (%rax,%rdx,8)
// 210 leal (%r14,%r8), %edx
// 211 addl %edi, %edx
// 212 addl %esi, %edx
// 213 addl %ecx, %edx
// 214 movl $21, %ecx
// 215 addl %r13d, %edx
// 216 subl %edx, %ecx
// 217 movslq %ecx, %rdx
// 218 movq %r12, (%rax,%rdx,8)
// 219 .p2align 4,,10
// 220 .p2align 3
// 221 .L5096:
// 222 testq %r15, %r15
// 223 je .L5095
// 224 .L5121:
// 225 movq -104(%rsp,%r15,8), %r10
// 226 movq -112(%rsp,%r15,8), %rax
// 227 jmp .L5115
// 228 .p2align 4,,10
// 229 .p2align 3
// 230 .L5103:
// 231 movq 8(%rax), %rdi
// 232 movq 16(%rax), %r8
// 233 xorl %ecx, %ecx
// 234 cmpq %rdx, %rdi
// 235 setb %cl
// 236 cmpq %rdx, %r8
// 237 adcl $0, %ecx
// 238 xorl %esi, %esi
// 239 cmpq %rdx, %rdi
// 240 setnb %sil
// 241 xorl %r9d, %r9d
// 242 cmpq %r8, %rdi
// 243 seta %r9b
// 244 addl %r9d, %esi
// 245 movslq %ecx, %r9
// 246 movq %rdx, (%rax,%r9,8)
// 247 movslq %esi, %rdx
// 248 addl %esi, %ecx
// 249 movq %rdi, (%rax,%rdx,8)
// 250 movl $3, %edx
// 251 subl %ecx, %edx
// 252 movslq %edx, %rdx
// 253 movq %r8, (%rax,%rdx,8)
// 254 testq %r15, %r15
// 255 jne .L5121
// 256 .L5095:
// 257 addq $143920, %rsp
// 258 .cfi_remember_state
// 259 .cfi_def_cfa_offset 56
// 260 popq %rbx
// 261 .cfi_def_cfa_offset 48
// 262 popq %rbp
// 263 .cfi_def_cfa_offset 40
// 264 popq %r12
// 265 .cfi_def_cfa_offset 32
// 266 popq %r13
// 267 .cfi_def_cfa_offset 24
// 268 popq %r14
// 269 .cfi_def_cfa_offset 16
// 270 popq %r15
// 271 .cfi_def_cfa_offset 8
// 272 ret
// 273 .p2align 4,,10
// 274 .p2align 3
// 275 .L5104:
// 276 .cfi_restore_state
// 277 movq 8(%rax), %rcx
// 278 cmpq %rdx, %rcx
// 279 sbbq %rsi, %rsi
// 280 andl $8, %esi
// 281 cmpq %rdx, %rcx
// 282 movq %rdx, (%rax,%rsi)
// 283 movl $1, %edx
// 284 sbbl $0, %edx
// 285 movslq %edx, %rdx
// 286 movq %rcx, (%rax,%rdx,8)
// 287 jmp .L5096
// 288 .p2align 4,,10
// 289 .p2align 3
// 290 .L5101:
// 291 movq 8(%rax), %r10
// 292 movq 16(%rax), %r9
// 293 xorl %ecx, %ecx
// 294 movq 24(%rax), %r8
// 295 movq 32(%rax), %rdi
// 296 cmpq %rdx, %r10
// 297 setb %cl
// 298 cmpq %rdx, %r9
// 299 adcl $0, %ecx
// 300 cmpq %rdx, %r8
// 301 adcl $0, %ecx
// 302 cmpq %rdx, %rdi
// 303 adcl $0, %ecx
// 304 xorl %esi, %esi
// 305 cmpq %rdx, %r10
// 306 setnb %sil
// 307 xorl %r11d, %r11d
// 308 cmpq %r9, %r10
// 309 seta %r11b
// 310 addl %r11d, %esi
// 311 xorl %r11d, %r11d
// 312 cmpq %r8, %r10
// 313 seta %r11b
// 314 addl %r11d, %esi
// 315 xorl %r11d, %r11d
// 316 cmpq %rdi, %r10
// 317 seta %r11b
// 318 addl %esi, %r11d
// 319 xorl %esi, %esi
// 320 cmpq %rdx, %r9
// 321 setnb %sil
// 322 xorl %ebx, %ebx
// 323 cmpq %r9, %r10
// 324 setbe %bl
// 325 addl %ebx, %esi
// 326 xorl %ebx, %ebx
// 327 cmpq %r8, %r9
// 328 seta %bl
// 329 addl %ebx, %esi
// 330 xorl %ebx, %ebx
// 331 cmpq %rdi, %r9
// 332 seta %bl
// 333 addl %esi, %ebx
// 334 xorl %esi, %esi
// 335 cmpq %rdx, %r8
// 336 setnb %sil
// 337 xorl %ebp, %ebp
// 338 cmpq %r8, %r10
// 339 setbe %bpl
// 340 addl %ebp, %esi
// 341 xorl %ebp, %ebp
// 342 cmpq %r8, %r9
// 343 setbe %bpl
// 344 addl %ebp, %esi
// 345 xorl %ebp, %ebp
// 346 cmpq %rdi, %r8
// 347 seta %bpl
// 348 addl %ebp, %esi
// 349 movslq %ecx, %rbp
// 350 addl %r11d, %ecx
// 351 movq %rdx, (%rax,%rbp,8)
// 352 movslq %r11d, %rdx
// 353 addl %ebx, %ecx
// 354 movq %r10, (%rax,%rdx,8)
// 355 movslq %ebx, %rdx
// 356 addl %esi, %ecx
// 357 movq %r9, (%rax,%rdx,8)
// 358 movslq %esi, %rdx
// 359 movq %r8, (%rax,%rdx,8)
// 360 movl $10, %edx
// 361 subl %ecx, %edx
// 362 movslq %edx, %rdx
// 363 movq %rdi, (%rax,%rdx,8)
// 364 jmp .L5096
// 365 .p2align 4,,10
// 366 .p2align 3
// 367 .L5102:
// 368 movq 8(%rax), %r10
// 369 movq 16(%rax), %r9
// 370 xorl %ecx, %ecx
// 371 movq 24(%rax), %r8
// 372 cmpq %rdx, %r10
// 373 setb %cl
// 374 cmpq %rdx, %r9
// 375 adcl $0, %ecx
// 376 cmpq %rdx, %r8
// 377 adcl $0, %ecx
// 378 xorl %edi, %edi
// 379 cmpq %rdx, %r10
// 380 setnb %dil
// 381 xorl %esi, %esi
// 382 cmpq %r9, %r10
// 383 seta %sil
// 384 addl %esi, %edi
// 385 xorl %esi, %esi
// 386 cmpq %r8, %r10
// 387 seta %sil
// 388 addl %esi, %edi
// 389 xorl %esi, %esi
// 390 cmpq %rdx, %r9
// 391 setnb %sil
// 392 xorl %r11d, %r11d
// 393 cmpq %r9, %r10
// 394 setbe %r11b
// 395 addl %r11d, %esi
// 396 xorl %r11d, %r11d
// 397 cmpq %r8, %r9
// 398 seta %r11b
// 399 addl %r11d, %esi
// 400 movslq %ecx, %r11
// 401 addl %edi, %ecx
// 402 movq %rdx, (%rax,%r11,8)
// 403 movslq %edi, %rdx
// 404 addl %esi, %ecx
// 405 movq %r10, (%rax,%rdx,8)
// 406 movslq %esi, %rdx
// 407 movq %r9, (%rax,%rdx,8)
// 408 movl $6, %edx
// 409 subl %ecx, %edx
// 410 movslq %edx, %rdx
// 411 movq %r8, (%rax,%rdx,8)
// 412 jmp .L5096
// 413 .p2align 4,,10
// 414 .p2align 3
// 415 .L5100:
// 416 movq 8(%rax), %r12
// 417 movq 16(%rax), %rbp
// 418 xorl %ecx, %ecx
// 419 movq 24(%rax), %r11
// 420 movq 32(%rax), %r10
// 421 cmpq %rdx, %r12
// 422 movq 40(%rax), %rbx
// 423 setb %cl
// 424 cmpq %rdx, %rbp
// 425 adcl $0, %ecx
// 426 cmpq %rdx, %r11
// 427 adcl $0, %ecx
// 428 cmpq %rdx, %r10
// 429 adcl $0, %ecx
// 430 cmpq %rdx, %rbx
// 431 adcl $0, %ecx
// 432 xorl %r9d, %r9d
// 433 cmpq %rdx, %r12
// 434 setnb %r9b
// 435 xorl %esi, %esi
// 436 cmpq %rbp, %r12
// 437 seta %sil
// 438 addl %esi, %r9d
// 439 xorl %esi, %esi
// 440 cmpq %r11, %r12
// 441 seta %sil
// 442 addl %esi, %r9d
// 443 xorl %esi, %esi
// 444 cmpq %r10, %r12
// 445 seta %sil
// 446 addl %esi, %r9d
// 447 xorl %esi, %esi
// 448 cmpq %rbx, %r12
// 449 seta %sil
// 450 xorl %r8d, %r8d
// 451 addl %esi, %r9d
// 452 cmpq %rdx, %rbp
// 453 setnb %r8b
// 454 xorl %esi, %esi
// 455 cmpq %rbp, %r12
// 456 setbe %sil
// 457 addl %esi, %r8d
// 458 xorl %esi, %esi
// 459 cmpq %r11, %rbp
// 460 seta %sil
// 461 addl %esi, %r8d
// 462 xorl %esi, %esi
// 463 cmpq %r10, %rbp
// 464 seta %sil
// 465 addl %esi, %r8d
// 466 xorl %esi, %esi
// 467 cmpq %rbx, %rbp
// 468 seta %sil
// 469 xorl %edi, %edi
// 470 addl %esi, %r8d
// 471 cmpq %rdx, %r11
// 472 setnb %dil
// 473 xorl %esi, %esi
// 474 cmpq %r11, %r12
// 475 setbe %sil
// 476 addl %esi, %edi
// 477 xorl %esi, %esi
// 478 cmpq %r11, %rbp
// 479 setbe %sil
// 480 addl %esi, %edi
// 481 xorl %esi, %esi
// 482 cmpq %r10, %r11
// 483 seta %sil
// 484 addl %esi, %edi
// 485 xorl %esi, %esi
// 486 cmpq %rbx, %r11
// 487 seta %sil
// 488 addl %esi, %edi
// 489 xorl %esi, %esi
// 490 cmpq %rdx, %r10
// 491 setnb %sil
// 492 xorl %r13d, %r13d
// 493 cmpq %r10, %r12
// 494 setbe %r13b
// 495 addl %r13d, %esi
// 496 xorl %r13d, %r13d
// 497 cmpq %r10, %rbp
// 498 setbe %r13b
// 499 addl %r13d, %esi
// 500 xorl %r13d, %r13d
// 501 cmpq %r10, %r11
// 502 setbe %r13b
// 503 addl %r13d, %esi
// 504 xorl %r13d, %r13d
// 505 cmpq %rbx, %r10
// 506 seta %r13b
// 507 addl %r13d, %esi
// 508 movslq %ecx, %r13
// 509 movq %rdx, (%rax,%r13,8)
// 510 movslq %r9d, %rdx
// 511 movq %r12, (%rax,%rdx,8)
// 512 movslq %r8d, %rdx
// 513 movq %rbp, (%rax,%rdx,8)
// 514 movslq %edi, %rdx
// 515 movq %r11, (%rax,%rdx,8)
// 516 movslq %esi, %rdx
// 517 movq %r10, (%rax,%rdx,8)
// 518 leal (%rcx,%r9), %edx
// 519 movl $15, %ecx
// 520 addl %r8d, %edx
// 521 addl %edi, %edx
// 522 addl %esi, %edx
// 523 subl %edx, %ecx
// 524 movslq %ecx, %rdx
// 525 movq %rbx, (%rax,%rdx,8)
// 526 jmp .L5096
// 527 .L5097:
// 528 sarq $2, %rsi
// 529 leaq (%rax,%rsi,8), %rcx
// 530 movq (%rcx), %r8
// 531 movq %rdx, (%rcx)
// 532 movq %r8, (%rax)
// 533 cmpq %rax, %r10
// 534 jbe .L5105
// 535 movq %rax, %rdx
// 536 movq %rax, %r9
// 537 movq %r10, %rcx
// 538 jmp .L5111
// 539 .p2align 4,,10
// 540 .p2align 3
// 541 .L5122:
// 542 movq (%r9), %rdi
// 543 movq %rsi, (%r9)
// 544 leaq 16(%rdx), %rsi
// 545 addq $8, %r9
// 546 movq %rdi, 8(%rdx)
// 547 movq %r11, %rdx
// 548 .L5107:
// 549 cmpq %rdx, %rcx
// 550 jbe .L5112
// 551 .L5111:
// 552 movq 8(%rdx), %rsi
// 553 leaq 8(%rdx), %r11
// 554 cmpq %r8, %rsi
// 555 jb .L5122
// 556 ja .L5120
// 557 leaq 16(%rdx), %rsi
// 558 movq %r11, %rdx
// 559 cmpq %rdx, %rcx
// 560 ja .L5111
// 561 .L5112:
// 562 movq 8(%rdx), %rdi
// 563 movq %rsi, %xmm0
// 564 movq %rcx, %rsi
// 565 movq %r10, %xmm1
// 566 subq %rdx, %rsi
// 567 leaq -8(%r9), %r10
// 568 punpcklqdq %xmm1, %xmm0
// 569 addq $2, %r15
// 570 movq %rdi, %r8
// 571 sarq $63, %rsi
// 572 subq 8(%rcx), %r8
// 573 movups %xmm0, -112(%rsp,%r15,8)
// 574 andq %r8, %rsi
// 575 subq %rsi, %rdi
// 576 movq %rdi, 8(%rdx)
// 577 addq %rsi, 8(%rcx)
// 578 movq %r10, %rcx
// 579 subq %rax, %rcx
// 580 testq %rcx, %rcx
// 581 jg .L5113
// 582 jmp .L5096
// 583 .p2align 4,,10
// 584 .p2align 3
// 585 .L5110:
// 586 subq $8, %rcx
// 587 .L5120:
// 588 movq (%rcx), %rdi
// 589 cmpq %r8, %rdi
// 590 ja .L5110
// 591 movq %rdi, 8(%rdx)
// 592 subq $8, %rcx
// 593 movq %rsi, 8(%rcx)
// 594 movq %r11, %rsi
// 595 jmp .L5107
// 596 .p2align 4,,10
// 597 .p2align 3
// 598 .L5105:
// 599 movq %rbx, %rsi
// 600 movq %rax, %rdx
// 601 movq %rax, %r9
// 602 movq %r10, %rcx
// 603 jmp .L5112
// 604 .cfi_endproc

Tomorrow night, will run the GCC and ICL executables on Windows 10, the testmachine will be 'Brutalitto' - the mini-monster with Zen 2 4800H and 64GB DDR4 - running the heaviest sort benchmark on Internet - 7+ billion QWORDS...

Add-on:
Code: [Select]
Test run: 2022-Mar-09:
Laptop "Brutalitto", AMD 'Renoir' 4800H 4.3GHz max turbo, 64GB DDR4 3200MHz:
+--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+
| Performer/Keys     | #1, FEW distinct          | #2, MANY distinct         | #3, MANYmore distinct     | #4, ALL distinct          | #5, ALLmore distinct       | #6, ALLmax distinct         |
+--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
|  Operating System, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10, | Windows 10,  | Windows 10,  | Windows 10,  |
|      Compiler, -O3 | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1  | Intel v15.0 | GCC 11.2.1   | Intel v15.0  | GCC 11.2.1   |
+--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
| qsort              |  42 seconds |  45 seconds | 242 seconds | 280 seconds | 113 seconds | 131 seconds | 319 seconds | 354 seconds | 620 seconds |  695 seconds | 1282 seconds | 1438 seconds |
| Magnetica v.13     |  22 seconds |  21 seconds | 135 seconds | 134 seconds |  60 seconds |  59 seconds | 177 seconds | 177 seconds | 350 seconds |  349 seconds |  724 seconds |  722 seconds |
| Bentley-McIlroy    |  24 seconds |  24 seconds | 146 seconds | 142 seconds |  66 seconds |  64 seconds | 200 seconds | 193 seconds | 391 seconds |  376 seconds |  850 seconds |  803 seconds |
| Crumsort           |  20 seconds |  19 seconds |  91 seconds |  81 seconds |  44 seconds |  38 seconds | 126 seconds | 109 seconds | 246 seconds |  211 seconds |  567 seconds |  479 seconds |
+--------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+--------------+--------------+--------------+
| Best Time (bare    |                           |                           |                           |                           |                            |                             |
| bone in-place QS): |  19s for Crumsort         |  81s for Crumsort         |  38s for Crumsort         | 109s for Crumsort         | 211s for Crumsort          | 479s for Crumsort           |
+--------------------+---------------------------+---------------------------+---------------------------+---------------------------+----------------------------+-----------------------------+

Code: [Select]
Speed Roster, (the base speed 1.00x is GLIBC's qsort):
Rank #1: 2943/937=  3.14x = 19+ 81+ 38+109+211+ 479=  937 seconds for Crumsort
Rank #2: 2943/1462= 2.01x = 21+134+ 59+177+349+ 722= 1462 seconds for Magnetica v.13
Rank #3: 2943/1602= 1.83x = 24+142+ 64+193+376+ 803= 1602 seconds for Bentley-McIlroy
Rank #4: 2943/2943= 1.00x = 45+280+131+354+695+1438= 2943 seconds for GLIBC's qsort
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on March 13, 2022, 08:54:21 pm
A new showdown is ready - Scandum's crumsort v1.1.5.3 vs Magnetica r.14:

Test run: 2022-Mar-14:
Laptop "Compressionette", Intel 'Kaby Lake' i5-7200U 3.1GHz max turbo, 36GB DDR4 2133MHz:
Code: [Select]
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+
| Performer/Keys     | #1, FEW distinct        | #2, MANY distinct        | #3, MANYmore distinct    | #4, ALL distinct          | #5, ALLmore distinct      | #6, ALLmax distinct         |
+--------------------+-------------------------+--------------------------+--------------------------+-------------+-------------+---------------------------+--------------+--------------+
|  Operating System, |   Fedora 35, GCC 11.2.1 |    Fedora 35, GCC 11.2.1 |    Fedora 35, GCC 11.2.1 |     Fedora 35, GCC 11.2.1 |     Fedora 35, GCC 11.2.1 |       Fedora 35, GCC 11.2.1 |
|      Compiler, -O3 |       instructions; IPC |        instructions; IPC |        instructions; IPC |         instructions; IPC |         instructions; IPC |           instructions; IPC |
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+
| qsort              |         385/342 seconds |          527/234 seconds |           165/55 seconds |           516/128 seconds |           999/252 seconds |                        N.A. |
|                    | 6,448,450,744,497; 2.82 |  4,921,980,445,033; 2.06 |  1,369,822,972,984; 1.94 |   3,250,596,357,540; 1.58 |   6,250,299,799,611; 1.59 |                        N.A. |
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+
| Magnetica v.14     |            29/6 seconds |           198/47 seconds |            86/22 seconds |            241/66 seconds |           472/134 seconds |                        N.A. |
|                    |   171,452,642,615; 1.14 |    936,751,248,598; 1.17 |    443,844,553,192; 1.25 |   1,291,624,832,269; 1.28 |   2,503,942,225,085; 1.28 |                        N.A. |
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+
| Bentley-McIlroy    |           38/13 seconds |           223/47 seconds |           100/26 seconds |            304/65 seconds |           597/139 seconds |                        N.A. |
|                    |   246,587,334,436; 1.23 |  1,105,253,285,645; 1.25 |    507,140,963,617; 1.23 |   1,460,132,564,676; 1.22 |   2,848,210,143,410; 1.22 |                        N.A. |
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+
| Crumsort 1.1.5.3   |            29/4 seconds |            129/4 seconds |             61/2 seconds |            173/3  seconds |             339/7 seconds |                        N.A. |
|                    |   351,332,884,902; 2.43 |  1,284,147,329,900; 2.80 |    603,065,127,518; 2.77 |   1,605,371,408,284; 2.64 |   3,102,283,088,926; 2.71 |                        N.A. |
+--------------------+-------------------------+--------------------------+--------------------------+---------------------------+---------------------------+-----------------------------+

Legend (The time is exactly the Sort process time, first value is for unsorted, second one is for sorted).
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: mdijkens on March 14, 2022, 04:45:19 am
Very interesting thread! Thank you!

I am regularly working with really big files (some over to 100GB) and have been optimizing 2 functions to read/process big files very fast.

I thought I'd add them here for information:

Code: QB64: [Select]
  1. Function readBigFile~&& (file$) '1.5GB/sec
  2.   Const BLOCKSIZE = 4194304 '=64*65536 = 4 MB
  3.   fsize~&& = fileSize(file$)
  4.   Dim mem As _MEM: mem = _MemNew(fsize~&& + BLOCKSIZE)
  5.   Dim block As String * BLOCKSIZE '=64*65536
  6.   filenum% = FreeFile
  7.   Open file$ For Random Access Read As filenum% Len = BLOCKSIZE
  8.   blocks~& = .5 + (fsize~&& / BLOCKSIZE)
  9.   For blck~& = 1 To blocks~&
  10.     Get filenum%, , block
  11.     _MemPut mem, mem.OFFSET + mpos~&&, block
  12.     mpos~&& = mpos~&& + BLOCKSIZE
  13.   Next blck~&
  14.   Close filenum%
  15.         ' Process mem
  16.   _MemFree mem
  17.   readBigFile~&& = fsize~&&
  18.  
  19. Function fileSize~&& (file$)
  20.   If Not _FileExists(file$) Then fileSize~&& = 0: Exit Function
  21.   filenum% = FreeFile
  22.   Open file$ For Binary Access Read As filenum%
  23.   fileSize~&& = LOF(filenum%)
  24.   Close filenum%
  25.  

and for csv's:
Code: QB64: [Select]
  1. Function CSV.read& (fileName$, eol$) ' 4M lines/sec
  2.   Const BLOCKSIZE = 4194304 '=64*65536 = 4 MB
  3.   If Not _FileExists(fileName$) Then CSV.read& = 0: Exit Function
  4.   'Print "Reading lines from "; fileName$; " ";: cpos% = Pos(0) '@@ progress info
  5.   eoll% = Len(eol$)
  6.   Dim block As String * BLOCKSIZE
  7.   ff% = FreeFile
  8.   Open fileName$ For Binary Access Read As #ff%
  9.   blocks& = .5 + LOF(ff%) / Len(block)
  10.   sep& = 0
  11.   lines& = -1
  12.   For curblock& = 1 To blocks&
  13.     Get #ff%, , block
  14.     If curblock& > 1 Then
  15.       buf$ = Mid$(buf$, sep&) + block
  16.       r0& = InStr(buf$, eol$) + eoll%
  17.     Else
  18.       buf$ = block 'Mid$(block, InStr(block, Chr$(10)) + 1)
  19.       r0& = 1
  20.     End If
  21.     r1& = InStr(r0&, buf$, eol$)
  22.     Do While r1& >= r0& And r0& > 0
  23.       lin$ = Mid$(buf$, r0&, r1& - r0& + eoll%)
  24.       ' Process lin$
  25.       lines& = lines& + 1
  26.       sep& = r1&: r0& = r1& + eoll%: r1& = InStr(r0&, buf$, eol$)
  27.     Loop
  28.     'Locate , cpos%, 0: Print lines&; '@@ progress info
  29.   Next curblock&
  30.   Close #ff%
  31.   buf$ = ""
  32.   'Locate , cpos%, 0 '@@ progress info
  33.   CSV.read& = lines&
  34.  
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: Sanmayce on March 14, 2022, 06:12:56 am
Very interesting thread! Thank you!

I am regularly working with really big files (some over to 100GB) and have been optimizing 2 functions to read/process big files very fast.

I thought I'd add them here for information:
...

You are welcome, at the moment have no time to make some dedicated example of sorting (fixed-length or/and variable-length i.e. string (LF instead of NULL) type) tool.
Let me know what interests you most, what is the main bottleneck you encounter in your processings - the parsing, the sorting, the searching...
This thread is all about these BASIC things, but optimized, my wish is to share and thus show the power of QB64 (as in the old days when pairing QB and ASM was, resembles QB64 and C duo, now).

All these micro-projects contribute to the Masakari project, the idea being, we all to have powerful and fast text-oriented routines. If you haven't looked up the Masakari text loading (somewhat similar to yours), it allows sorting lines per size or by their offset in memory (i.e. returning to the original state), the quick usage being:

Code: QB64: [Select]
  1. Declare CustomType Library "qsm_linesize" ' Notice that 'CustomType' makes things work, using 'STATIC' gives errors during compilation
  2.     Sub Quicksort_QB64_v7_linesize (ByVal QWORDSoff As _Offset, Byval QWORDSlen As _Offset, Byval Left As _Integer64, Byval Right As _Integer64)
  3. 'Quicksort_QB64_v7_linesize MhandleOFF.OFFSET, MhandleLEN.OFFSET, 0, ElementsMinusOne
  4.  

For example, do you have a ... nifty (for Linux, Windows) filename parser? A month ago I was tired of not having such a function, and wrote DIRWALKER (the skeleton at the moment, listing AS IT SHOULD the current folder), wanted to write a tiny tool, but the most important work is done, the rest is just gluing into your code. See the  BAS+C source code in the attached archive. Wanna have the HEAVY-DUTY functionality of sorting FILESIZE, NAME, MODIFIED TIME fields/columns... for millions of files, FAST!

 
Title: Re: A skeleton code for Text Scroller via Drag-and-Drop
Post by: mdijkens on March 14, 2022, 06:45:10 am
For DIR-walking, I use my routine below.
If I need sorting I add a custom QuickSort for the specific column

Code: QB64: [Select]
  1. $VersionInfo:FILEVERSION#=22,02,28,2
  2. $VersionInfo:FileDescription=mdDir
  3. $VersionInfo:CompanyName=dijkens.com
  4. $VersionInfo:ProductName=mdDir
  5. $VersionInfo:InternalName=mdDir
  6. $VersionInfo:OriginalFilename=mdDir
  7. $VersionInfo:LegalCopyright=dijkens.com
  8. $VersionInfo:LegalTrademarks=dijkens.com
  9. $VersionInfo:Comments=dijkens.com
  10. $VersionInfo:Web=www.dijkens.com
  11.  
  12. '$Let DEVTEST = 1
  13.  
  14. Type parmType
  15.   fspec As String 'fpsec
  16.   subs As Integer 'include subs
  17.   search As Integer 'search terms
  18.   icase As Integer 'ignore case
  19. Dim Shared parm As parmType
  20. Dim Shared stext(10) As String
  21. Const FALSE = 0, TRUE = Not FALSE
  22.  
  23. init
  24. f& = Dir(parm.fspec)
  25. $If DEVTEST = DEFINED Then
  26.  
  27. '$include: 'DIR.BI'
  28.  
  29. Sub init
  30.   Print "mdDir.exe v"; getVersion$
  31.   getParams
  32.   $If DEVTEST = DEFINED Then
  33.     ChDir "E:\_todo\qb64dev"
  34.   $End If
  35.  
  36. Sub getParams
  37.   'd:\dev\qb64\*.bas /t console:only /c
  38.   For ccount% = 1 To Val(getCommand$(-1))
  39.     cmd$ = getCommand$(ccount%)
  40.     If InStr("-/", Left$(cmd$, 1)) > 0 Then
  41.       Select Case UCase$(Mid$(cmd$, 2, 1))
  42.         Case "S"
  43.           parm.subs = TRUE
  44.         Case "T"
  45.           stext(0) = "sinit"
  46.         Case "C"
  47.           parm.icase = TRUE
  48.         Case Else
  49.           Print " mdDIR [fspec] [/s] [/t search1 [...] [/c]]"
  50.           Print "    fspec           = [d:][path\][filespec] e.g. 'd:\data\*.txt'"
  51.           Print "   /s               = Include sub-directories"
  52.           Print "   /t search1 [...] = Search content for 'search1' (and '...')"
  53.           Print "   /c               = Ignore case in search"
  54.           $If DEVTEST = DEFINED Then
  55.             Sleep
  56.           $End If
  57.           System
  58.       End Select
  59.     ElseIf stext(0) = "" Then
  60.       parm.fspec = cmd$
  61.     Else
  62.       parm.search = parm.search + 1
  63.       stext$(parm.search) = cmd$
  64.     End If
  65.   Next ccount%
  66.   If parm.fspec = "" Then
  67.     parm.fspec = "*.*"
  68.   End If
  69.  
  70. Function Dir& (p$)
  71.   b% = DIR.CheckPath(p$)
  72.   If b% > 0 Then
  73.     ddcount& = 0
  74.     If Mid$(p$, b%) = "\*.*" Then
  75.       Print Left$(p$, b%)
  76.       f& = DIR.GetFiles(p$)
  77.       DIR.SortFiles
  78.       If parm.search = 0 Then PrintDirs
  79.       PrintFiles Left$(p$, b%)
  80.       If DIR.Dcount > 0 Then
  81.         ddcount& = DIR.Dcount
  82.         subdir$ = "|"
  83.         For i& = 1 To ddcount&
  84.           subdir$ = subdir$ + DIR.Dname(i&) + "|"
  85.         Next i&
  86.       End If
  87.     Else
  88.       d& = DIR.GetFiles(Left$(p$, b%) + "*")
  89.       If DIR.Dcount > 0 Then
  90.         DIR.SortFiles
  91.         ddcount& = DIR.Dcount
  92.         subdir$ = "|"
  93.         For i& = 1 To ddcount&
  94.           subdir$ = subdir$ + DIR.Dname(i&) + "|"
  95.         Next i&
  96.       End If
  97.       f& = DIR.GetFiles(p$)
  98.       If DIR.Fcount > 0 Then
  99.         DIR.SortFiles
  100.         Print Left$(p$, b%)
  101.         PrintFiles Left$(p$, b%)
  102.       End If
  103.     End If
  104.     If parm.subs Then
  105.       For i& = 1 To ddcount&
  106.         sp& = 0
  107.         For s& = 1 To i&
  108.           sp& = InStr(sp& + 1, subdir$, "|")
  109.         Next s&
  110.         sd$ = Mid$(subdir$, sp& + 1, InStr(sp& + 1, subdir$, "|") - sp& - 1)
  111.         x& = Dir(Left$(p$, b%) + sd$ + Mid$(p$, b%))
  112.       Next i&
  113.     End If
  114.   Else
  115.     f& = 0
  116.   End If
  117.   Dir& = f&
  118.  
  119. Sub PrintFiles (path$)
  120.   q$ = Chr$(34)
  121.   For i& = 1 To DIR.Fcount
  122.     If textSearch(path$ + DIR.Fname(i&)) Then
  123.       a = DIR.Fattr(i&)
  124.       Attr$ = Space$(4)
  125.       If (a And &H20) = &H20 Then
  126.         Mid$(Attr$, 1, 1) = "A" ' archive
  127.       End If
  128.       If (a And &H4) = &H4 Then
  129.         Mid$(Attr$, 2, 1) = "S" ' system
  130.       End If
  131.       If (a And &H2) = &H2 Then
  132.         Mid$(Attr$, 3, 1) = "H" ' hidden
  133.       End If
  134.       If (a And &H1) = &H1 Then
  135.         Mid$(Attr$, 4, 1) = "R" ' read-only
  136.       End If
  137.       Print Using "\          \##,###,###,### \  \ \                 \ "; DIR.Fshort(i&); DIR.Fsize(i&); Attr$; DIR.Ftime(i&);
  138.       Print DIR.Fname(i&)
  139.     End If
  140.   Next i&
  141.  
  142. Function textSearch (fileName$)
  143.   If parm.search = 0 Then textSearch = TRUE: Exit Function
  144.   If Not _FileExists(fileName$) Then textSearch = TRUE: Exit Function
  145.   Dim content As String, block As String * 4194304 '=64*65536
  146.   Dim blocks As _Unsigned Long, curblock As _Unsigned Long
  147.   bsize = Len(block)
  148.   ff% = FreeFile: Open fileName$ For Random Access Read As #ff% Len = bsize
  149.   fsize = LOF(ff%): content = Space$(fsize): blocks = .5 + fsize / bsize: cpos = 1
  150.   For curblock = 1 To blocks
  151.     Get #ff%, curblock, block
  152.     Mid$(content, cpos, bsize) = block
  153.     cpos = cpos + bsize
  154.   Next curblock
  155.   Close #ff%
  156.   If parm.icase Then content = LCase$(content)
  157.   For s% = 1 To parm.search
  158.     If InStr(content, LCase$(stext(s%))) = 0 Then Exit For
  159.   Next s%
  160.   content = ""
  161.   If s% > parm.search Then
  162.     textSearch = TRUE
  163.   Else
  164.     textSearch = FALSE
  165.   End If
  166.  
  167. Sub PrintDirs
  168.   For i& = 1 To DIR.Dcount
  169.     a = DIR.Dattr(i&)
  170.     Attr$ = Space$(4)
  171.     If (a And &H20) = &H20 Then
  172.       Mid$(Attr$, 1, 1) = "A" ' archive
  173.     End If
  174.     If (a And &H4) = &H4 Then
  175.       Mid$(Attr$, 2, 1) = "S" ' system
  176.     End If
  177.     If (a And &H2) = &H2 Then
  178.       Mid$(Attr$, 3, 1) = "H" ' hidden
  179.     End If
  180.     If (a And &H1) = &H1 Then
  181.       Mid$(Attr$, 4, 1) = "R" ' read-only
  182.     End If
  183.   PRINT USING "\          \     <DIR>     \  \ \                 \ "; _
  184.   DIR.Dshort(i&); Attr$; DIR.Dtime(i&);
  185.     Print DIR.Dname(i&)
  186.   Next i&
  187.  
  188. Function getCommand$ (n%)
  189.   Static cmd$(100), ccount As Integer
  190.   If cmd$(0) = "" Then
  191.       Function GetCommandLineA%& ()
  192.     End Declare
  193.     Dim m As _MEM, ms As String * 1000
  194.     a%& = GetCommandLineA: m = _Mem(a%&, Len(ms)): ms = _MemGet(m, m.OFFSET, String * 1000)
  195.     ccount = 0: sp0% = 1: sp1% = InStr(ms, " ")
  196.     Do While sp1% > 0
  197.       cmd$(ccount) = _Trim$(Mid$(ms, sp0%, sp1% - sp0%))
  198.       If cmd$(ccount) <> "" Then ccount = ccount + 1
  199.       sp0% = sp1% + 1: sp1% = InStr(sp1% + 1, ms, " ")
  200.     Loop
  201.     cmd$(ccount) = _Trim$(Mid$(ms, sp0%)): If Left$(cmd$(ccount), 1) = Chr$(0) Then ccount = ccount - 1
  202.     _MemFree m
  203.   End If
  204.   If n% < 0 Then
  205.     getCommand$ = _Trim$(Str$(ccount))
  206.   ElseIf n% <= ccount Then
  207.     getCommand$ = cmd$(n%)
  208.   Else
  209.     getCommand$ = ""
  210.   End If
  211.  
  212. Function getVersion$
  213.   Declare Library 'Directory Information using KERNEL32
  214.     Function GetModuleFileNameA (ByVal hModule As Long, lpFileName As String, Byval nSize As Long)
  215.   Declare Dynamic Library "version"
  216.     Function GetFileVersionInfoA (lptstrFilename As String, Byval dwHandle As Long, Byval dwLen As Long, lpData As String)
  217.   FileName$ = Space$(256): res = GetModuleFileNameA(0, FileName$, Len(FileName$))
  218.   lpData$ = Space$(1024): res = GetFileVersionInfoA(FileName$, 0, Len(lpData$), lpData$)
  219.   offset% = Asc(Mid$(lpData$, 3, 1))
  220.   getVersion$ = LTrim$(Str$(Asc(Mid$(lpData$, offset%-1, 1)))) + "." + _
  221.   LTrim$(Str$(Asc(Mid$(lpData$, offset%-3, 1)))) + "." + _
  222.   LTrim$(Str$(Asc(Mid$(lpData$, offset%+3, 1)))) + "." + _
  223.   LTrim$(Str$(Asc(Mid$(lpData$, offset%+1, 1))))
  224.  

DIR.BI:
Code: QB64: [Select]
  1. '   ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
  2. '   º      DIR.BI  v1.22 (20200815)     maurits@dijkens.com       º
  3. '   ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ
  4. '   º                                                             º
  5. '   º ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º
  6. '   º ³                                                         ³ º
  7. '   º ³ FUNCTION DIR.CheckPath (dfspec$)                        ³ º
  8. '   º ³ FUNCTION DIR.GetFiles& (dfspec$)                        ³ º
  9. '   º ³ SUB DIR.SortFiles ()                                    ³ º
  10. '   º ³ SUB DIR.QSortFiles (leftN AS LONG, rightN AS LONG)      ³ º
  11. '   º ³ SUB DIR.QSortDirs (leftN AS INTEGER, rightN AS INTEGER) ³ º
  12. '   º ³                                                         ³ º
  13. '   º ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º
  14. '   º                                                             º
  15. '   ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
  16. Const __DIR_MAX_PATH = 260
  17. Const __INVALID_HANDLE_VALUE = -1
  18.  
  19. Const DIR.READONLY = &H1
  20. Const DIR.HIDDEN = &H2
  21. Const DIR.SYSTEM = &H4
  22. Const DIR.DIRECTORY = &H10
  23. Const DIR.ARCHIVE = &H20
  24. Const DIR.NORMAL = &H80
  25. Const DIR.TEMPORARY = &H100
  26. Const DIR.SYMBOLICLINK = &H400
  27. Const DIR.COMPRESSED = &H800
  28. Const DIR.NOTINDEXED = &H2000
  29. Const DIR.ENCRYPTED = &H4000
  30.  
  31.  
  32. Type __DIR_FILETIME_TYPE
  33.   dwLowDateTime As _Unsigned Long
  34.   dwHighDateTime As _Unsigned Long
  35.  
  36. Type __DIR_SYSTEMTIME_TYPE
  37.   wYear As Integer
  38.   wMonth As Integer
  39.   wDayOfWeek As Integer
  40.   wDay As Integer
  41.   wHour As Integer
  42.   wMinute As Integer
  43.   wSecond As Integer
  44.   wMilliseconds As Integer
  45.  
  46. Type WIN32_FIND_DATAA
  47.   dwFileAttributes As _Unsigned Long
  48.   ftCreationTime As __DIR_FILETIME_TYPE
  49.   ftLastAccessTime As __DIR_FILETIME_TYPE
  50.   ftLastWriteTime As __DIR_FILETIME_TYPE
  51.   nFileSizeHigh As _Unsigned Long
  52.   nFileSizeLow As _Unsigned Long
  53.   dwReserved0 As _Unsigned Long
  54.   dwReserved1 As _Unsigned Long
  55.   cFileName As String * __Dir_max_path
  56.   cAlternateFileName As String * 14
  57.  
  58.   Function FindFirstFileA~%& (ByVal lpFileName~%&, Byval lpFindFileData~%&)
  59.   Function FindNextFileA& (ByVal hFindFile~%&, Byval lpFindFileData~%&)
  60.   Function FindClose& (ByVal hFindFile~%&)
  61.   Function FileTimeToSystemTime& (lpFileTime As __DIR_FILETIME_TYPE, lpSystemTime As __DIR_SYSTEMTIME_TYPE)
  62.   Function FileTimeToLocalFileTime& (lpFileTime As __DIR_FILETIME_TYPE, lpLocalFileTime As __DIR_FILETIME_TYPE)
  63.  
  64. Dim Shared DIR.Fname(1) As String
  65. Dim Shared DIR.Dname(1) As String
  66. Dim Shared DIR.Fcount As Long
  67. Dim Shared DIR.Dcount As Long
  68. Dim Shared DIR.Fsize(1) As _Integer64
  69. Dim Shared DIR.Dtime(1) As String * 19 ' mm-dd-yyyy hh:mm:ss
  70. Dim Shared DIR.Ftime(1) As String * 19 ' mm-dd-yyyy hh:mm:ss
  71. Dim Shared DIR.Dattr(1) As _Unsigned Long
  72. Dim Shared DIR.Fattr(1) As _Unsigned Long
  73. Dim Shared DIR.Dshort(1) As String
  74. Dim Shared DIR.Fshort(1) As String
  75.  
  76. DIR.err:
  77. DIR.Error = Err
  78.  
  79. Function DIR.CheckPath% (dfspec$)
  80.   dfspec$ = _Trim$(dfspec$)
  81.   If dfspec$ = "" Or Right$(dfspec$, 1) = ":" Then
  82.     dfspec$ = dfspec$ + ".\*.*"
  83.   End If
  84.   For pend% = Len(dfspec$) To 1 Step -1
  85.     If Mid$(dfspec$, pend%, 1) = "\" Then
  86.       Exit For
  87.     End If
  88.   Next pend%
  89.   If _DirExists(dfspec$) Then
  90.     If pend% = Len(dfspec$) Then
  91.       dfspec$ = dfspec$ + "*.*"
  92.     Else
  93.       dfspec$ = dfspec$ + "\*.*"
  94.       pend% = Len(dfspec$) - 3
  95.     End If
  96.   ElseIf pend% = 0 Then
  97.     dp% = InStr(dfspec$, ":")
  98.     dfspec$ = Left$(dfspec$, dp%) + ".\" + Mid$(dfspec$, dp% + 1)
  99.     pend% = dp% + 2
  100.   End If
  101.   If _DirExists(Left$(dfspec$, pend%)) Then
  102.     DIR.Error = 0
  103.     On Error GoTo DIR.err
  104.     ChDir Left$(dfspec$, pend%)
  105.     On Error GoTo 0
  106.     dspec$ = _CWD$
  107.     If DIR.Error = 0 Then
  108.       If Right$(dspec$, 1) <> "\" Then
  109.         dspec$ = dspec$ + "\"
  110.       End If
  111.       DIR.CheckPath% = Len(dspec$)
  112.       dfspec$ = dspec$ + Mid$(dfspec$, pend% + 1)
  113.     Else
  114.       DIR.CheckPath% = 0
  115.     End If
  116.   Else
  117.     DIR.CheckPath% = 0
  118.   End If
  119.  
  120. Function DIR.GetFiles& (dfspec$)
  121.   Dim Attribute As _Unsigned Long
  122.   Dim ASCIIZ As String * 260
  123.   Dim finddata As WIN32_FIND_DATAA
  124.   Dim Wfile.Handle As _Unsigned _Offset
  125.   Dim SysTime As __DIR_SYSTEMTIME_TYPE
  126.   Dim LocalTime As __DIR_FILETIME_TYPE
  127.  
  128.   Var$ = dfspec$
  129.   DIR.Dcount = 0
  130.   DIR.Fcount = 0
  131.   ASCIIZ = Var$ + Chr$(0)
  132.   Wfile.Handle = FindFirstFileA(_Offset(ASCIIZ), _Offset(finddata))
  133.   If Wfile.Handle <> __INVALID_HANDLE_VALUE Then
  134.     Do
  135.       Attribute = finddata.dwFileAttributes
  136.       Filename$ = finddata.cFileName
  137.       Filename$ = Left$(Filename$, InStr(Filename$, Chr$(0)) - 1)
  138.       If Filename$ <> "." And Filename$ <> ".." And Filename$ <> "$RECYCLE.BIN" And Filename$ <> "System Volume Information" Then
  139.  
  140.         ' store date/time
  141.         x& = FileTimeToLocalFileTime&(finddata.ftLastWriteTime, LocalTime)
  142.         x& = FileTimeToSystemTime&(LocalTime, SysTime)
  143.         Var$ = Right$("00" + LTrim$(Str$(SysTime.wMonth)), 2) + "-"
  144.         Var$ = Var$ + Right$("00" + LTrim$(Str$(SysTime.wDay)), 2) + "-"
  145.         Var$ = Var$ + LTrim$(Str$(SysTime.wYear)) + " "
  146.         Var$ = Var$ + Right$("00" + LTrim$(Str$(SysTime.wHour)), 2) + ":"
  147.         Var$ = Var$ + Right$("00" + LTrim$(Str$(SysTime.wMinute)), 2) + ":"
  148.         Var$ = Var$ + Right$("00" + LTrim$(Str$(SysTime.wSecond)), 2)
  149.  
  150.         If (Attribute And DIR.DIRECTORY) = DIR.DIRECTORY Then
  151.           DIR.Dcount = DIR.Dcount + 1
  152.           ReDim _Preserve DIR.Dname(DIR.Dcount) As String
  153.           DIR.Dname(DIR.Dcount) = Filename$
  154.  
  155.           ReDim _Preserve DIR.Dtime(DIR.Dcount) As String * 19
  156.           DIR.Dtime(DIR.Dcount) = Var$
  157.  
  158.           ReDim _Preserve DIR.Dattr(DIR.Dcount) As _Unsigned Long
  159.           DIR.Dattr(DIR.Dcount) = Attribute
  160.  
  161.           Filename$ = finddata.cAlternateFileName
  162.           Filename$ = Left$(Filename$, InStr(Filename$, Chr$(0)) - 1)
  163.           ReDim _Preserve DIR.Dshort(DIR.Dcount) As String
  164.           If Filename$ <> "" Then
  165.             DIR.Dshort(DIR.Dcount) = Filename$
  166.           Else
  167.             DIR.Dshort(DIR.Dcount) = UCase$(DIR.Dname(DIR.Dcount))
  168.           End If
  169.         Else
  170.           DIR.Fcount = DIR.Fcount + 1
  171.           ReDim _Preserve DIR.Fname(DIR.Fcount) As String
  172.           DIR.Fname(DIR.Fcount) = Filename$
  173.           ReDim _Preserve DIR.Fsize(DIR.Fcount) As _Integer64
  174.           F&& = finddata.nFileSizeHigh * &H100000000~&& Or finddata.nFileSizeLow
  175.           DIR.Fsize(DIR.Fcount) = F&&
  176.  
  177.           ReDim _Preserve DIR.Ftime(DIR.Fcount) As String * 19
  178.           DIR.Ftime(DIR.Fcount) = Var$
  179.  
  180.           ReDim _Preserve DIR.Fattr(DIR.Fcount) As _Unsigned Long
  181.           DIR.Fattr(DIR.Fcount) = Attribute
  182.  
  183.           Filename$ = finddata.cAlternateFileName
  184.           Filename$ = Left$(Filename$, InStr(Filename$, Chr$(0)) - 1)
  185.           ReDim _Preserve DIR.Fshort(DIR.Fcount) As String
  186.           If Filename$ <> "" Then
  187.             DIR.Fshort(DIR.Fcount) = Filename$
  188.           Else
  189.             DIR.Fshort(DIR.Fcount) = UCase$(DIR.Fname(DIR.Fcount))
  190.           End If
  191.         End If
  192.       End If
  193.     Loop While FindNextFileA(Wfile.Handle, _Offset(finddata))
  194.     x& = FindClose(Wfile.Handle)
  195.     DIR.GetFiles& = DIR.Fcount
  196.   Else
  197.     DIR.GetFiles& = -1
  198.   End If
  199.  
  200. Sub DIR.SortFiles ()
  201.   DIR.QSortDirs 1, DIR.Dcount
  202.   DIR.QSortFiles 1, DIR.Fcount
  203.  
  204. Sub DIR.QSortFiles (leftN As Long, rightN As Long)
  205.   Dim pivot As Long, leftNIdx As Long, rightNIdx As Long
  206.   leftNIdx = leftN
  207.   rightNIdx = rightN
  208.   If (rightN - leftN) > 0 Then
  209.     pivot = (leftN + rightN) / 2
  210.     While (leftNIdx <= pivot) And (rightNIdx >= pivot)
  211.       While (UCase$(DIR.Fname(leftNIdx)) < UCase$(DIR.Fname(pivot))) And (leftNIdx <= pivot)
  212.         leftNIdx = leftNIdx + 1
  213.       Wend
  214.       While (UCase$(DIR.Fname(rightNIdx)) > UCase$(DIR.Fname(pivot))) And (rightNIdx >= pivot)
  215.         rightNIdx = rightNIdx - 1
  216.       Wend
  217.       Swap DIR.Fname(leftNIdx), DIR.Fname(rightNIdx)
  218.       Swap DIR.Fshort(leftNIdx), DIR.Fshort(rightNIdx)
  219.       Swap DIR.Fsize(leftNIdx), DIR.Fsize(rightNIdx)
  220.       Swap DIR.Ftime(leftNIdx), DIR.Ftime(rightNIdx)
  221.       Swap DIR.Fattr(leftNIdx), DIR.Fattr(rightNIdx)
  222.       leftNIdx = leftNIdx + 1
  223.       rightNIdx = rightNIdx - 1
  224.       If (leftNIdx - 1) = pivot Then
  225.         rightNIdx = rightNIdx + 1
  226.         pivot = rightNIdx
  227.       ElseIf (rightNIdx + 1) = pivot Then
  228.         leftNIdx = leftNIdx - 1
  229.         pivot = leftNIdx
  230.       End If
  231.     Wend
  232.     DIR.QSortFiles leftN, pivot - 1
  233.     DIR.QSortFiles pivot + 1, rightN
  234.   End If
  235.  
  236. Sub DIR.QSortDirs (leftN As Integer, rightN As Integer)
  237.   Dim pivot As Integer, leftNIdx As Integer, rightNIdx As Integer
  238.   leftNIdx = leftN
  239.   rightNIdx = rightN
  240.   If (rightN - leftN) > 0 Then
  241.     pivot = (leftN + rightN) / 2
  242.     While (leftNIdx <= pivot) And (rightNIdx >= pivot)
  243.       While (UCase$(DIR.Dname(leftNIdx)) < UCase$(DIR.Dname(pivot))) And (leftNIdx <= pivot)
  244.         leftNIdx = leftNIdx + 1
  245.       Wend
  246.       While (UCase$(DIR.Dname(rightNIdx)) > UCase$(DIR.Dname(pivot))) And (rightNIdx >= pivot)
  247.         rightNIdx = rightNIdx - 1
  248.       Wend
  249.       Swap DIR.Dname(leftNIdx), DIR.Dname(rightNIdx)
  250.       Swap DIR.Dshort(leftNIdx), DIR.Dshort(rightNIdx)
  251.       Swap DIR.Dtime(leftNIdx), DIR.Dtime(rightNIdx)
  252.       Swap DIR.Dattr(leftNIdx), DIR.Dattr(rightNIdx)
  253.       leftNIdx = leftNIdx + 1
  254.       rightNIdx = rightNIdx - 1
  255.       If (leftNIdx - 1) = pivot Then
  256.         rightNIdx = rightNIdx + 1
  257.         pivot = rightNIdx
  258.       ElseIf (rightNIdx + 1) = pivot Then
  259.         leftNIdx = leftNIdx - 1
  260.         pivot = leftNIdx
  261.       End If
  262.     Wend
  263.     DIR.QSortDirs leftN, pivot - 1
  264.     DIR.QSortDirs pivot + 1, rightN
  265.   End If
  266.