News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

A few questions

Started by MCpiroman, May 03, 2017, 10:34:09 PM

Previous topic - Next topic

MCpiroman

Hi, some beginner's questions here:

1.Why does it work
fopen("c:\the\path\to\file.txt")
and this doesn't

fpath db "c:\the\path\to\file.txt", 0
fopen(fpath)

and how to make that work? It seems like it wants a value; address doesn't work either.

2. How do I use (write/read) an array of strings (of diffrent length)? And array of arrays of strings (not rectangle)?
Also considering case when I have a big file of strings loaded and I want to make such array only for indexing/addressing them instead of copying.

3. What are the ways to load file and when are they prefered and when not.

4. Is it a bug that arrfile$ doesn't load files from another disk?

5. Any shortcuts for fast compile/run program?

6. How to print variables/registers?

7. And btw how does it work that when I pass a string or array (well, the same) somewhere it knows the length of it? Since i guess it just sends a single number of its address.

8. And then how do I know the length of an array, including case in question 2. ?


I know the answers should be in examples/tutorials folders but when I try get them work at my own they doesn't.

jj2007

1. fopen(offset fpath)

2. Recall "somefile.txt", my$()
There is also the masm32 macro ltok.

3. What are the ways to load file and when are they prefered and when not.
Many!

4. Is it a bug that arrfile$ doesn't load files from another disk?
Full correct path?

5. Any shortcuts for fast compile/run program?
In RichMasm, hit F6. Works also with non-MasmBasic sources.

6. How to print variables/registers?
Print Str$("This is eax: %i\n", eax)
or
deb "some test", eax, xmm0, MyDword, al, ax, ST(1), ... whatever you need for debugging


7. And btw how does it work that when I pass a string or array (well, the same) somewhere it knows the length of it? Since i guess it just sends a single number of its address.

Either zero-delimited, or len is stored somewhere.

8. And then how do I know the length of an array, including case in question 2. ?
Recall returns the #strings in eax. Afterwards,
Print Str$("The array My$() has %i elements", My$(?))

I know the answers should be in examples/tutorials folders but when I try get them work at my own they doesn't.


Come up with concrete code and questions, and we'll help you.

hutch--

This one is an easy one.

fpath db "c:\the\path\to\file.txt", 0
fopen(fpath)


"fpath" is an entry in the uninitialised data section, you normally use "OFFSET fpath" to get its address.

MCpiroman

1. I tried offset and that didn't work, although I was taking argument of procedure which apparently isn't the same as what I wrote. So then how to do this:

afunc proc filePath:byte
    fopen(filePath)
    ret
afunc endp


4. I did some more tests and it turned out that it crashes in depend of file content, especially number of lines, thought i can bet that that wasn't working with the same file on diffrent disks (with copyied paths for concurrence). Code:

    local hFile:dword                         
    local bwrt:dword                                                                             
    local flen:dword                         
    local hMem:dword   
   
    local hArr:dword

    ;"C:\users\w\desktop\test.txt" ;paths to both files (of the same content),program running from C
    ;"F:\a\test.txt"

    mov hFile, fopen("F:\a\test.txt")           
    mov flen, fsize(hFile)                     
    mov hMem, alloc(flen)                       
    mov bwrt, fread(hFile,hMem,flen)           
    fclose hFile
    print chr$("file content: ")                 
    print hMem,13,10
    print chr$("fopen ok", 13, 10, 13, 10)
 
    mov hArr, arrfile$("F:\a\test.txt")
    print chr$("file content: ")
    print arrget$(hArr,1),13,10     ; 1-based? why?
    print chr$("arrfile ok", 13, 10)


And do the arrget$ returns a array of lines? That would be really handy for me.

hutch--

For the task you have in mind, the "ltok" (line tokenise) procedure is the right one to use. Look up how to use it in the help file. It is a genuinely fast tokeniser and it performs the task in place. Note that it modifies the original string so if you need to preserve the original, make a copy to modify.

MCpiroman

Well, what I want to do is load file (~3mb) of words (one per line), and sort it by lenght, so I can reference them like allWords[length][indexOfWordOfThatLength].
That doesn't metter nowadays but it would be nice if i haden't to copy them and therefore double memory usage.

What i thing i have to do is create global array of length e.g. 20 (i haven't longer word), loop through all the words, count how many i have of each length, create subarrays inside the global of that length, then loop again and assing words to correct subarrays.

Btw, I have no idea how to start with all that arraying, lengthing, indexing and referencing.
(Isn't that something for another thread?)

jj2007

Quote from: MCpiroman on May 04, 2017, 04:37:42 AMWell, what I want to do is load file (~3mb) of words (one per line), and sort it by lenght

Something like this?

include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  Recall "\Masm32\include\Windows.inc", L$()      ; load 26900 lines
  For_ ecx=0 To eax-1
      Let L$(ecx)=Str$("%000i\t", Len(L$(ecx)))+L$(ecx)      ; e.g. 0013      CLIPDATA ENDS
  Next
  QSort L$()            ; short strings on top
  .While 1
      .Break .if dword ptr [L$(0)]!="0000"      ; eliminate all nullstrings
      Delete L$(0)
  .Endw
  Store "SortedByLength.txt", L$()      ; save modified array to disk
  Inkey "View the file? (y)"
  .if eax=="y"
      ShEx "SortedByLength.txt"      ; ShellExecute with Notepad or similar
  .endif
EndOfCode


Reading, sorting and saving to disk takes about 60 ms on my Core i5 machine. Strangely enough, it takes only 40 ms to sort a 4MB bible.txt, from a short 12 char "Jesus wept." to a line with 529 characters ::)

MCpiroman

@up
Wow, that's some high level stuff. Though, by sort i rather meant to 'segregate'. I mean to make an array of arrays of strings (also arrays) where in each sub array there are only strings of length of this array's index(or + 1).

Example:
From file:

on
a
that
nose
at
you
i
worm
...


make something like:

[
[a, i, o]
[on, to, at, up, me, us]
[one, you, jar, rat]
[nose, core, masm, heat, code, worm, that, make]
]
(just graph, don't want to save it anywhere)

and be able to access from code e.g. 'up' by theWords[1,3] and 'worm' by theWords[3,5]. And also get that length of theWords[0] is 3, and theWords[3] is 8 (there are 8 words of length = 4 (= 3+1))
Aaand then, that the 3'th char of 'worm' is 'r' so it would be theWords[3, 5, 2] = 'r'


I'd like to rather do it by myself, just want to know the way to make that arraying work.

jj2007

What is the purpose of the exercise? A text compressor?

MCpiroman

I'm trying to rewrite my c# text encrypter (or maybe encoder) in assembler to learn it and see the difference in preformance.

hutch--

Here is a test piece that loads a file and parses it into an array of words. You must remove and single and double quotes as this algo does not enter quoted text. It is so fast that it barely registers a timing. On my dev box I keep getting 15ms for a 4.5 meg file.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL hMem  :DWORD
    LOCAL pArr  :DWORD
    LOCAL wCnt  :DWORD
    LOCAL cntr  :DWORD
    LOCAL tcnt  :DWORD

    push esi
    push edi

  ; ----------------------------------------
  ; benchmark file load & word parser "wtok"
  ; ----------------------------------------
    invoke GetTickCount
    push eax

    mov hMem, InputFile("warpeace.txt")         ; <<<< change this to your own text file

    invoke wtok,hMem,ADDR pArr
    mov wCnt, eax

    invoke GetTickCount
    pop ecx
    sub eax, ecx

    print str$(eax)," Milliseconds",13,10
    inkey
  ; ----------------------------------------

  ; -----------------
  ; display the words
  ; -----------------
    mov esi, pArr
    mov edi, wCnt
    sub edi, 1
    mov cntr, -1
  @@:
    add cntr, 1
    invoke StdOut, [esi]
    invoke StdOut, chr$(13,10)
    add esi, 4
    cmp cntr, edi
    jb @B
  ; -----------------

    free hMem

    pop edi
    pop esi

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start