Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - mdijkens

Pages: [1] 2 3
1
QB64 Discussion / Re: QB64 Bounty List
« on: April 14, 2022, 03:27:47 am »
1. A good Inkey$ like alternative for $console:only on Win and Linux would give much business value for me
2. Shell with stdin and stdout; preferably with _Nowait (to get some multitasking functionality)

2
Thanks,

I don't have any linux experience either; just testing in a VM.
But I need to support it often to support colleagues or customers
I've already tried your approach and a lot (crazy) others...

Would be really cool if there's someone with a linux background who could look into this...

3
I am really happy with all the functionality in QB64 and the professional grade applications we can build with it!
But one thing I'm really missing is an Inkey$ like function for Linux/Mac in $Console mode.
Things like catching arrow-keys or specific alphanumeric keys would be really helpful.
So far I have tried a lot of things to get something working via screenscraping and external tools but no luck until now.
I assume it is hard and totally different from Windows in the nature of terminal sessions but I really hope that something is possible, even in a limited way....
If any one knows workarounds, I'll be excited too

4
QB64 Discussion / Re: Fickle Increment variable
« on: April 05, 2022, 02:25:22 pm »
If you don't need the timings and sepate up/down events, the regular Inkey$ works easier.
I always do it like this:

Code: QB64: [Select]
  1. Const K_ESC = 27, K_SPACE = 32, K_ENTER = 13, K_BACKSPACE = 8, K_TAB = 9, K_DEL = 339
  2. Const K_UP = 328, K_LEFT = 331, K_RIGHT = 333, K_DOWN = 336
  3. Const K_HOME = 327, K_END = 335, K_PGUP = 329, K_PGDN = 337
  4.  
  5. Do While k% <> K_ESC
  6.   k% = testKey
  7.   Select Case k%
  8.     Case K_SPACE
  9.       x = 0: y = 0
  10.     Case K_UP
  11.       y = y - 1
  12.     Case K_DOWN
  13.       y = y + 1
  14.     Case K_LEFT
  15.       x = x - 1
  16.     Case K_RIGHT
  17.       x = x + 1
  18.     Case K_HOME
  19.       x = -100
  20.     Case K_END
  21.       x = 100
  22.     Case K_PGUP
  23.       y = y - 10
  24.     Case K_PGDN
  25.       y = y + 10
  26.     Case Else
  27.  
  28.  
  29. Function testKey%
  30.   ink$ = Chr$(0) + InKey$
  31.   testKey% = Asc(Right$(ink$, 1)) - 256 * (Len(ink$) = 3)

I also have a variant with added mouse inputs (testKey <0)

5
Programs / Multithreaded webserver
« on: March 30, 2022, 11:10:28 am »
For workshops I give, I sometimes need an easy mechanism to share (big) files with the audience or vice-versa on a local network.
I decided it would be a nice challenge to build something myself in QB64.
I've also added multithtreading (single CPU core) so people don't have to wait for eachother when downloading/uploading big files

Comments and advice always welcome ...

Code: QB64: [Select]
  1. Const VERSION = "v22.03.30.4"
  2. ' Start with root path of webserver as parameter and optional port e.g. mdserver2 d:\mysite 8088
  3. ' Place 'favicon.ico' file (+R+H) in root directory
  4. ' Place '.auth' file (+R+H) with authorized hashes in all protected directories
  5.  
  6. DefInt A-Z
  7. Const FALSE = 0, TRUE = Not FALSE
  8.  
  9. Const TIMEOUT = 10
  10. Const MAXURLLEN = 32000
  11. Const BLOCKSIZE = 2 ^ 21
  12. Const MAXFILESIZE = 2 ^ 39
  13. $If WIN Then
  14.   Const SEP0 = "/", SEP = "\"
  15.   Const SEP0 = "\", SEP = "/"
  16.  
  17. Type reqType
  18.   thread As Integer '                 thread#
  19.   client As Integer '                 http-client#
  20.   Typ As String '                     GET / POST / PUT
  21.   Path As String '                    Path in Url '/../../'
  22.   File As String '                    File in Url 'file.ext'
  23.   Param As String '                   param=123
  24.   Auth As String '                    Authorization hash
  25.   cLen As _Unsigned _Integer64 '      Centent-Length
  26.   cStart As _Unsigned _Integer64 '    Content start
  27.   cEnd As _Unsigned _Integer64 '      Content end
  28.   cBytes As _Unsigned _Integer64 '    Content bytes
  29.   cMime As String '                   Content mime type
  30.   cBoundary As String '               Content multi-part boundary string
  31.   cFileNameIn As String '             Post filename 'file.ext'
  32.   cFileNameOut As String '            '<SEP>...<SEP>file.ext'
  33.   cFileSize As _Unsigned _Integer64 ' Filesize in bytes
  34. Dim Shared CRLF As String * 2: CRLF = Chr$(13) + Chr$(10)
  35. Dim Shared As String APPLNAME, SITEPATH, PORT
  36.  
  37.  
  38. If init Then
  39.   main
  40.  
  41. Function init%
  42.   APPLNAME = appName$: SITEPATH = ".": PORT = "8088"
  43.   For c% = 1 To _CommandCount
  44.     cv~% = Val(Command$(c%))
  45.     If cv~% > 0 Then
  46.       PORT = _Trim$(Str$(cv~%))
  47.     Else
  48.       SITEPATH = replace$(_Trim$(Command$(c%)), SEP0, SEP)
  49.     End If
  50.   Next c%
  51.   If SITEPATH = SEP Or Right$(SITEPATH, 2) = ":\" Then SITEPATH = SITEPATH + "."
  52.   If Right$(SITEPATH, 1) = SEP Then SITEPATH = Left$(SITEPATH, Len(SITEPATH) - 1)
  53.   If SITEPATH = "" Or Not _DirExists(SITEPATH) Then SITEPATH = Left$(APPLNAME, _InStrRev(APPLNAME, SEP$) - 1)
  54.  
  55.   printLog "SERVER: '" + APPLNAME + "'"
  56.   printLog "VERSION: " + VERSION
  57.   printLog "PORT: " + PORT
  58.   If Right$(SITEPATH, 2) = "\." Then
  59.     printLog "SITEPATH: '" + Left$(SITEPATH, Len(SITEPATH) - 2) + SEP + "'"
  60.   Else
  61.     printLog "SITEPATH: '" + SITEPATH + SEP + "'"
  62.   End If
  63.   Dim thread(0 To 9) As Integer
  64.   For t% = 0 To 9: thread(t%) = _FreeTimer: Next t%
  65.   On Timer(thread(0), .01) Thread0
  66.   On Timer(thread(1), .01) Thread1
  67.   On Timer(thread(2), .01) Thread2
  68.   On Timer(thread(3), .01) Thread3
  69.   On Timer(thread(4), .01) Thread4
  70.   On Timer(thread(5), .01) Thread5
  71.   On Timer(thread(6), .01) Thread6
  72.   On Timer(thread(7), .01) Thread7
  73.   On Timer(thread(8), .01) Thread8
  74.   On Timer(thread(9), .01) Thread9
  75.   For t% = 0 To 9: Timer(thread(t%)) On: Next t%
  76.  
  77.   HOST = _OpenHost("TCP/IP:" + PORT)
  78.   init% = (HOST < 0)
  79.  
  80. Sub main
  81.   Do Until _KeyHit = 27
  82.     _Limit 10
  83.   Loop
  84.  
  85. Sub processRequest (thread%)
  86.   client% = _OpenConnection(HOST)
  87.   If client% < 0 Then
  88.     Dim req As reqType: req.thread = thread%: req.client = client%
  89.     Get req.client, , reqBytes$
  90.     If parseRequest(req, reqBytes$) Then
  91.       log$ = LTrim$(Str$(-req.client)) + ":" + req.Typ + " " + req.Path
  92.       If Not authorized(req) Then
  93.         log$ = log$ + "  Authenticate: "
  94.         If req.Auth <> "" Then log$ = log$ + req.Auth
  95.         res$ = httpHeader$(req, 401, ""): Put req.client, , res$
  96.       ElseIf req.Typ = "POST" Then
  97.         received~&& = handlePost(req, reqBytes$)
  98.         log$ = log$ + req.cFileNameIn + " (" + _Trim$(Str$(req.cFileSize)) + ")"
  99.         If received~&& <> req.cLen Then log$ = log$ + "  ERROR !!!"
  100.         'redirect
  101.         res$ = httpHeader$(req, 301, ""): Put req.client, , res$
  102.       ElseIf req.Typ = "GET" Then
  103.         If req.File <> "" Then 'download file
  104.           sent~&& = handleGetFile(req)
  105.           log$ = log$ + req.File
  106.           If req.Param <> "" Then log$ = log$ + "?" + req.Param
  107.           log$ = log$ + " (" + _Trim$(Str$(sent~&&)) + ")"
  108.           If sent~&& = 0 Then ' redirect
  109.             log$ = log$ + "  ERROR: File not found"
  110.             req.Path = "/": res$ = httpHeader$(req, 404, ""): Put req.client, , res$
  111.           End If
  112.         Else ' render page
  113.           html$ = renderDirectory$(req)
  114.           If html$ <> "" Then
  115.             res$ = httpHeader$(req, 200, html$)
  116.           Else
  117.             log$ = log$ + "  ERROR: Path not found"
  118.             res$ = httpHeader$(req, 404, "")
  119.           End If
  120.           Put req.client, , res$
  121.         End If
  122.       Else
  123.         log$ = "ERROR: NOT ALLOWED !!!"
  124.         'redirect
  125.         res$ = httpHeader$(req, 404, ""): Put req.client, , res$
  126.       End If
  127.       printLog log$
  128.     End If
  129.     Close req.client
  130.   End If
  131.  
  132. Function renderDirectory$ (req As reqType)
  133.   If Left$(req.Path, 1) <> "/" Or Right$(req.Path, 1) <> "/" Then Exit Function
  134.   fspec$ = replace$(SITEPATH + req.Path, SEP0, SEP)
  135.   px12$ = "style='font-family:" + quoted$("Courier New") + "; font-size:12px;'"
  136.   px14$ = "style='font-family:" + quoted$("Arial") + "; font-size:14px;'"
  137.   px20$ = "style='font-family:" + quoted$("Courier New") + "; font-size:20px;'"
  138.   html$ = "<html><body><form enctype='multipart/form-data' action='.' method='POST'>" + _
  139.           "<input type='file' name='filename' " + px14$ + ">" + _
  140.           "<input type='submit' " + px14$ + "></form><hr>" + _
  141.           "<p " + px20$ + ">"
  142.   If req.Path = "/" Then
  143.     html$ = html$ + "/"
  144.   Else
  145.     Dim p$(1000): parts% = split(req.Path, "/", p$())
  146.     href$ = ""
  147.     For i% = 0 To parts% - 2
  148.       href$ = href$ + p$(i%) + "/"
  149.       html$ = html$ + "<a href='" + href$ + "'>" + p$(i%) + "/</a> "
  150.     Next i%
  151.     html$ = html$ + p$(i%)
  152.   End If
  153.   html$ = html$ + "</p><table " + px12$ + ">"
  154.   tmp$ = APPLNAME + LTrim$(Str$(req.thread)) + ".tmp"
  155.   $If WIN Then
  156.     Shell _Hide "DIR /O:GN " + fspec$ + " >" + tmp$
  157.     Shell _Hide "ls -l --group-directories-first " + fspec$ + " >" + tmp$
  158.   $End If
  159.     ff% = FreeFile
  160.     Open tmp$ For Input As ff%
  161.     tdp$ = "<td style='padding-right: 20px;"
  162.     tda$ = tdp$ + " text-align:right;'>"
  163.     apName$ = Mid$(APPLNAME, _InStrRev(APPLNAME, SEP) + 1)
  164.     Do While Not EOF(ff%)
  165.       Line Input #ff%, l$
  166.       $If WIN Then
  167.         If Val(Left$(l$, 2)) > 0 And Right$(l$, 1) <> "." Then
  168.           dat$ = Left$(l$, 16): sz~&& = Val(replace$(Mid$(l$, 18), ",", "")): f$ = Mid$(l$, 36)
  169.           If InStr(l$, "<DIR>") > 0 And sz~&& = 0 Then
  170.     html$ = html$ + "<tr>" + tdp$ + "'><a href='" + req.Path + f$ + "/'>" + f$ + "</a></td>" + _
  171.     "<td/><td>" + dat$ + "</td></tr>"
  172.           ElseIf Left$(f$, 1) <> "." And Left$(f$, Len(apName$)) <> apName$ Then
  173.     html$ = html$ + "<tr>" + tdp$ + "'><a href='" + req.Path + f$ + "'>" + f$ + "</a></td>" + _
  174.     tda$ + Str$(sz~&&) + "</td><td>" + dat$ + "</td></tr>"
  175.           End If
  176.         End If
  177.       $Else
  178.         If InStr("-d", Left$(l$, 1)) > 0 Then
  179.         sp% = 0: For i% = 1 To 4: sp% = InStr(sp% + 1, l$, " "): Next i%: sp% = sp% + 1
  180.         Do While InStr("0123456789", Mid$(l$, sp%, 1)) = 0: sp% = sp% + 1: Loop
  181.         dp% = InStr(sp% + 1, l$, " ")
  182.         sz~&& = Val(Mid$(l$, sp%, dp% - sp%))
  183.         dat$ = _Trim$(Mid$(l$, dp%, 14))
  184.         f$ = _Trim$(Mid$(l$, dp% + 13))
  185.         If Left$(l$, 1) = "d" And sz~&& = 0 Then
  186.         html$ = html$ + "<tr>" + tdp$ + "'><a href='" + req.Path + f$ + "/'>" + f$ + "</a></td>" + _
  187.         "<td/><td>" + dat$ + "</td></tr>"
  188.         ElseIf Left$(f$, 1) <> "." And Left$(f$, Len(apName$)) <> apName$ Then
  189.         html$ = html$ + "<tr>" + tdp$ + "'><a href='" + req.Path + f$ + "'>" + f$ + "</a></td>" + _
  190.         tda$ + Str$(sz~&&) + "</td><td>" + dat$ + "</td></tr>"
  191.         End If
  192.         End If
  193.       $End If
  194.     Loop
  195.     Close ff%
  196.     Kill tmp$
  197.   End If
  198.   html$ = html$ + "</table></body></html>"
  199.   renderDirectory$ = html$
  200.  
  201. Function handleGetFile~&& (req As reqType)
  202.   If Left$(req.Path, 1) <> "/" Or Right$(req.Path, 1) <> "/" Or req.File = "" Then Exit Function
  203.   fspec$ = replace$(SITEPATH + req.Path + req.File, SEP0, SEP)
  204.   ff% = FreeFile: Open fspec$ For Binary Access Read As ff%
  205.   req.cFileSize = LOF(ff%)
  206.   res$ = httpHeader$(req, 200, "")
  207.   If req.cFileSize <= BLOCKSIZE Then
  208.     Put req.client, , res$
  209.     dat$ = String$(req.cFileSize, 0)
  210.     Get ff%, , dat$
  211.     req.cBytes = Len(dat$)
  212.     Put req.client, , dat$
  213.     _Delay .001 'for other threads
  214.   Else
  215.     blocks& = _Ceil((req.cFileSize / BLOCKSIZE))
  216.     dat$ = String$(BLOCKSIZE, 0)
  217.     Put req.client, , res$
  218.     req.cBytes = 0
  219.     For b& = 1 To blocks& - 1
  220.       Get ff%, , dat$
  221.       req.cBytes = req.cBytes + Len(dat$)
  222.       Put req.client, , dat$
  223.       _Delay .001 'for other threads
  224.     Next b&
  225.     dat$ = String$(req.cFileSize Mod BLOCKSIZE, 0)
  226.     Get ff%, , dat$
  227.     req.cBytes = req.cBytes + Len(dat$)
  228.     Put req.client, , dat$
  229.   End If
  230.   Close ff%
  231.   handleGetFile~&& = req.cBytes
  232.  
  233. Function handlePost~&& (req As reqType, reqBytes$)
  234.   If _FileExists(req.cFileNameOut) Then Exit Function
  235.   If req.cEnd = 0 Then
  236.     content$ = Mid$(reqBytes$, req.cStart)
  237.     req.cBytes = req.cBytes + Len(content$)
  238.   Else
  239.     content$ = Mid$(reqBytes$, req.cStart, req.cEnd - req.cStart - 4)
  240.     req.cBytes = req.cBytes + Len(content$) + Len(req.cBoundary) + 8
  241.   End If
  242.   ff% = FreeFile: Open req.cFileNameOut For Binary Access Write As ff%
  243.   Put ff%, , content$
  244.   req.cFileSize = Len(content$)
  245.   _Delay .001 'for other threads
  246.   If req.cEnd = 0 Then
  247.     Get req.client, , reqBytes$
  248.     tim! = Timer
  249.     Do While req.cBytes < req.cLen And ((86400 + Timer - tim!) Mod 86400) < TIMEOUT
  250.       If Len(reqBytes$) > 0 Then
  251.         req.cEnd = InStr(reqBytes$, req.cBoundary)
  252.         If req.cEnd = 0 Then
  253.           content$ = reqBytes$
  254.           req.cBytes = req.cBytes + Len(content$)
  255.         Else
  256.           content$ = Left$(reqBytes$, req.cEnd - 5)
  257.           req.cBytes = req.cBytes + Len(content$) + Len(req.cBoundary) + 8
  258.         End If
  259.         Put ff%, , content$
  260.         req.cFileSize = req.cFileSize + Len(content$)
  261.         _Delay .001 'for other threads
  262.         tim! = Timer
  263.       End If
  264.       Get req.client, , reqBytes$
  265.     Loop
  266.   End If
  267.   Close ff%
  268.   handlePost~&& = req.cBytes
  269.  
  270. Function parseRequest% (req As reqType, reqBytes$)
  271.   'printLog reqBytes$ '@@
  272.   parseRequest = FALSE
  273.   req.Typ = "": req.Path = "": req.Param = "": req.File = "": req.Auth = ""
  274.   req.cLen = 0: req.cStart = 0: req.cEnd = 0: req.cMime = "": req.cBoundary = ""
  275.   req.cFileNameIn = "": req.cFileNameOut = ""
  276.   req.cBytes = 0: req.cFileSize = 0
  277.   If Len(reqBytes$) < 36 Then Exit Function
  278.   If Left$(reqBytes$, 5) = "GET /" Then
  279.     req.Typ = "GET": s% = 5
  280.   ElseIf Left$(reqBytes$, 6) = "POST /" Then
  281.     req.Typ = "POST": s% = 6
  282.   Else
  283.   End If
  284.   h% = InStr(s%, reqBytes$, " HTTP/1.1" + CRLF): If h% = 0 Or h% > MAXURLLEN Then Exit Function
  285.   url$ = Mid$(reqBytes$, s%, h% - s%)
  286.   For i% = 1 To Len(url$)
  287.     uc$ = Mid$(url$, i%, 1)
  288.     If uc$ = "?" Then param% = TRUE
  289.     If Not param% Then
  290.       If InStr("./_-~ 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", uc$) > 0 Then req.Path = req.Path + uc$
  291.     Else
  292.       If InStr("=_-~ 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", uc$) > 0 Then req.Param = req.Param + uc$
  293.     End If
  294.   Next i%
  295.   If InStr(req.Path, "..") > 0 Or InStr(req.Path, "/.") > 0 Or InStr(req.Path, "./") > 0 Then Exit Function
  296.   If InStr(req.Path, "//") > 0 Or Left$(req.Path, 1) <> "/" Then Exit Function
  297.   bs% = _InStrRev(req.Path, "/")
  298.   req.File = Mid$(req.Path, bs% + 1)
  299.   req.Path = Left$(req.Path, bs%)
  300.   auth% = InStr(reqBytes$, "Authorization: ")
  301.   If auth% > 0 Then req.Auth = Mid$(reqBytes$, auth% + 15, InStr(auth%, reqBytes$, CRLF) - auth% - 15)
  302.   If req.Typ = "POST" Then
  303.     s% = InStr(h%, reqBytes$, "Content-Length: "): If s% = 0 Or s% > h% + 1000 Then Exit Function
  304.     req.cLen = Val(Mid$(reqBytes$, s% + 16)): If req.cLen < 1 Or req.cLen > MAXFILESIZE Then Exit Function
  305.     h% = InStr(s%, reqBytes$, "Content-Type: "): If h% = 0 Or h% > s% + 1000 Then Exit Function
  306.     s% = InStr(h%, reqBytes$, "; boundary="): If s% = 0 Or s% > h% + 100 Then Exit Function
  307.     h% = InStr(s%, reqBytes$, CRLF): If h% = 0 Or h% > s% + 100 Then Exit Function
  308.     req.cBoundary = Mid$(reqBytes$, s% + 11, h% - s% - 11)
  309.     req.cBytes = InStr(h%, reqBytes$, CRLF + CRLF) + 4: If req.cBytes = 0 Or req.cBytes > h% + 1000 Then Exit Function
  310.     s% = InStr(req.cBytes, reqBytes$, req.cBoundary): If s% = 0 Or s% > h% + 1000 Then Exit Function
  311.     h% = InStr(s%, reqBytes$, "; filename="): If h% = 0 Or h% > s% + 100 Then Exit Function
  312.     s% = InStr(h%, reqBytes$, CRLF): If s% = 0 Or s% > h% + 100 Then Exit Function
  313.     req.cFileNameIn = unquoted$(Mid$(reqBytes$, h% + 11, s% - h% - 11))
  314.     req.cFileNameOut = replace$(SITEPATH + req.Path + req.cFileNameIn, SEP0, SEP)
  315.     h% = InStr(s%, reqBytes$, "Content-Type: "): If h% = 0 Or h% > s% + 10 Then Exit Function
  316.     s% = InStr(h%, reqBytes$, CRLF): If s% = 0 Or s% > h% + 100 Then Exit Function
  317.     req.cMime = Mid$(reqBytes$, h% + 14, s% - h% - 14)
  318.     req.cStart = s% + 4
  319.     req.cBytes = req.cStart - req.cBytes
  320.     req.cEnd = InStr(req.cStart, reqBytes$, req.cBoundary)
  321.   End If
  322.   parseRequest = TRUE
  323.  
  324. Function authorized% (req As reqType)
  325.   fspec$ = replace$(SITEPATH + req.Path, SEP0, SEP) + ".auth"
  326.   If _FileExists(fspec$) Then
  327.     ff% = FreeFile
  328.     Open fspec$ For Input As ff%
  329.     Do While Not EOF(ff%)
  330.       Line Input #ff%, lin$
  331.       If req.Auth = lin$ Then authorized% = TRUE: Exit Do
  332.     Loop
  333.     Close ff%
  334.   Else
  335.     authorized% = TRUE
  336.   End If
  337.  
  338. Function httpHeader$ (req As reqType, code%, html$)
  339.   Select Case code%
  340.     Case 200 ' render page & favicon.ico & get file
  341.   res$ ="HTTP/1.1 200 OK" + CRLF + _
  342.   "Server: md" + CRLF + "Connection: close" + CRLF
  343.       If html$ <> "" Then ' render page
  344.         res$ = res$ + "Content-Type: text/html" + CRLF + "Content-Length:" + Str$(Len(html$)) + CRLF + CRLF + html$
  345.       ElseIf req.File = "favicon.ico" Then 'get favicon.ico
  346.   res$ = res$ + "Content-Type: image/png" + CRLF + _
  347.   "Content-Length:" + CRLF + Ltrim$(Str$(req.cFileSize)) + CRLF + CRLF
  348.       ElseIf req.cFileSize > 0 Then 'get file
  349.   res$ = res$ + "Content-Type: application/force-download" + CRLF + _
  350.   "Content-Length:" + CRLF + Ltrim$(Str$(req.cFileSize)) + CRLF + _
  351.   "Content-Transfer-Encoding: binary" + _
  352.   "Content-Disposition: attachment; filename=" + quoted$(req.File) + CRLF + CRLF
  353.       End If
  354.     Case 301 'after post & not allowed
  355.   res$ ="HTTP/1.1 301 Moved Permanently" + CRLF + _
  356.   "Location: " + req.Path + CRLF + _
  357.   "Server: md" + CRLF + "Connection: close" + CRLF + "Content-Type: text/html" + CRLF + CRLF
  358.     Case 401 'authenticate
  359.   res$ ="HTTP/1.1 401 Unauthorized" + CRLF + _
  360.   "WWW-Authenticate: Basic" + CRLF + _
  361.   "Server: md" + CRLF + "Connection: close" + CRLF + CRLF
  362.     Case Else '404
  363.   res$ ="HTTP/1.1 404 Not Found" + CRLF + _
  364.   "Server: md" + CRLF + "Connection: close" + CRLF + CRLF
  365.   httpHeader$ = res$
  366.  
  367. Sub printLog (l$)
  368.   ll$ = Date$ + " " + Time$ + " : " + l$
  369.   ff% = FreeFile: Open APPLNAME + ".log" For Append Access Write As ff%
  370.   Print #ff%, ll$
  371.   Close ff%
  372.   Print ll$
  373.  
  374. Function quoted$ (q$)
  375.   quoted$ = Chr$(34) + q$ + Chr$(34)
  376.  
  377. Function unquoted$ (qq$)
  378.   uq$ = _Trim$(qq$): l& = Len(uq$)
  379.   If l& > 0 Then
  380.     If Asc(Left$(uq$, 1)) = 34 And Asc(Mid$(uq$, l&, 1)) = 34 Then
  381.       unquoted$ = _Trim$(Mid$(uq$, 2, l& - 2))
  382.     Else
  383.       unquoted$ = uq$
  384.     End If
  385.   End If
  386.  
  387. Function replace$ (ir$, i0$, i1$)
  388.   or$ = ir$
  389.   i0len& = Len(i0$)
  390.   i& = InStr(or$, i0$)
  391.   If i0len& = Len(i1$) Then
  392.     Do While i& > 0
  393.       Mid$(or$, i&, i0len&) = i1$
  394.       i& = InStr(or$, i0$)
  395.     Loop
  396.   Else
  397.     Do While i& > 0
  398.       or$ = Left$(or$, i& - 1) + i1$ + Mid$(or$, i& + Len(i0$))
  399.       i& = InStr(or$, i0$)
  400.     Loop
  401.   End If
  402.   replace$ = or$
  403.  
  404. Function split& (inString As String, delim As String, outArray() As String)
  405.   Dim curpos As Long, arrpos As Long, LD As Long, dpos As Long
  406.   curpos = 1: arrpos = LBound(outArray): LD = Len(delim)
  407.   dpos = InStr(curpos, inString, delim)
  408.   Do Until dpos = 0
  409.     outArray(arrpos) = Mid$(inString, curpos, dpos - curpos)
  410.     arrpos = arrpos + 1
  411.     If arrpos > UBound(outArray) Then ReDim _Preserve outArray(LBound(outArray) To UBound(outArray) + 1000) As String
  412.     curpos = dpos + LD
  413.     dpos = InStr(curpos, inString, delim)
  414.   Loop
  415.   outArray(arrpos) = Mid$(inString, curpos)
  416.   ReDim _Preserve outArray(LBound(outArray) To arrpos) As String
  417.   split& = arrpos
  418.  
  419. Function appName$ ()
  420.   $If WIN Then
  421.     Declare Library 'Directory Information using KERNEL32
  422.       Function GetModuleFileNameA (ByVal hModule As Long, lpFileName As String, Byval nSize As Long)
  423.     End Declare
  424.     Static appNam$
  425.     If appNam$ = "" Then
  426.       FileName$ = Space$(512): res = GetModuleFileNameA(0, FileName$, Len(FileName$))
  427.       appNam$ = Left$(FileName$, Len(RTrim$(FileName$)) - 5)
  428.     End If
  429.     appName$ = appNam$
  430.     appName$ = Command$(0)
  431.   $End If
  432.  
  433. Sub Thread0 (): processRequest 0: End Sub
  434. Sub Thread1 (): processRequest 1: End Sub
  435. Sub Thread2 (): processRequest 2: End Sub
  436. Sub Thread3 (): processRequest 3: End Sub
  437. Sub Thread4 (): processRequest 4: End Sub
  438. Sub Thread5 (): processRequest 5: End Sub
  439. Sub Thread6 (): processRequest 6: End Sub
  440. Sub Thread7 (): processRequest 7: End Sub
  441. Sub Thread8 (): processRequest 8: End Sub
  442. Sub Thread9 (): processRequest 9: End Sub
  443.  

edit: cleaned it up a bit

6
Programs / Re: Control digital, pwm and analog signals from QB64
« on: March 18, 2022, 06:10:51 am »
Ik heb nog wat meer geexperimenteerd met de baudrate en daar valt inderdaad nog winst te behalen.
Met mijn NodeMCU (ESP8266 12E) met CP2102 usb-serial chip kom ik op
115200 kbps ~7000/s
128000 kbps ~8000/s
153600 kbps ~10000/s
230400 kbps ~14000/s
daarboven wordt het onbetrouwbaar

Bijgevoegd een wat nettere/betrouwbare versie van mijn experiment

7
Programs / Re: Control digital, pwm and analog signals from QB64
« on: March 16, 2022, 11:38:42 am »
Intereseting

The CH340G on some ESP boards is capable of 2Mbit USB Serial speeds, so worth to give it a try too.
Do you just enter a higher baudrate in the OPEN statement or just 115200 ?

8
QB64 Discussion / Re: Input output methods and hardware opinions
« on: March 16, 2022, 04:48:49 am »
I tried to find better (faster) ways to do this and USB serial (at 115k2) is a lot faster then TCP.
See my topic here https://qb64forum.alephc.xyz/index.php?topic=4727.msg141384#msg141384

9
Programs / Control digital, pwm and analog signals from QB64
« on: March 16, 2022, 04:45:39 am »
Triggered by a question on the forum from Parkland here https://qb64forum.alephc.xyz/index.php?topic=4723.0, I wanted to see how high a performance (reads/writes per second) I could get by controlling a NodeMCU (ESP8266 12E) from QB64
Attached my program that can get up to 4800 datapoints/sec via USB. It is only limited by the max baudrate of qb64 (115k2).
It can read analog, digital, pwm and write digital, pwm.
add/remove what you need to get maximum performance

10
QB64 Discussion / Re: Has $Debug been working well for you?
« on: March 14, 2022, 12:12:38 pm »
Functionally yes, but not integrated with the new $Debug functionality.
I would still use $ASSERTS for (debug) logging purposes.

11
QB64 Discussion / Re: Input output methods and hardware opinions
« on: March 14, 2022, 12:09:31 pm »
A half solutions that works for me is to connect to an ESP8266 via wifi and use the I/O of the ESP8266 via TCP connections from QB64.
This still does not give you real fast I/O but at least a few hundred reads/writes a second is achieveable

12
I'm not really seeing any recursion pattern in this example

The first one runs through a 'matrix' b,a which is fine (could also be done with 2 nested for-loops)
The second one runs a=1,c=[0,=>] and pauses at a=1,c=100

recursion is mostly evident when you want to do something with a piece of data/sequence and then do the same processing on the remaining part of the data/sequence

13
QB64 Discussion / Re: Has $Debug been working well for you?
« on: March 14, 2022, 10:30:52 am »
Just using Watchpoints and the condition can only be a simple one variable condition (which I understand from the nature of compiled code).

Wouldn't it be great if there was also a $DEBUG metacommand to set a programmatic watchpoint in your code only to be executed during $DEBUG ?
e.g. something like:
Code: QB64: [Select]
  1. $Debug If a Mod 7 <> Sqr(b) And C = 0 then $DEBUG_BREAK
or:
Code: QB64: [Select]
  1. $DebugBreak When a Mod 7 <> Sqr(b) And C = 0

This might be doable?

It would also be possible if you can detect in code if running in debug-mode
Code: QB64: [Select]
  1. $If $Debug Then
  2. MyWatchExpr1% = a Mod 7 <> Sqr(b) And C = 0
And then put a normal watchpoint on MyWatchExpr1%

14
QB64 Discussion / Re: No Sound on Mac
« on: March 14, 2022, 10:04:21 am »
I just found out via a youtube video about installing on Mac that on Big Sur Apple deprecated OpenAL library; so no sound om Mac Big Sur.

Is there any plan/idea how to support sound on Mac again in the (near) future?

Also, I do think this should also be noted on: https://wiki.qb64.org/wiki/Keywords_currently_not_supported_by_QB64#Keywords_Not_Supported_in_Linux_or_MAC_OSX_versions

15
Programs / Re: A skeleton code for Text Scroller via Drag-and-Drop
« 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.  

Pages: [1] 2 3