Hi,
This code is assembling proper & running but it isn't functioning as expected.
Its supposed to display the highest no of charactesr (that a line has). but its displaying 0
something wrong's happening after the cmp byte ptr [esi], 0 line & it seems to be
jumping to exit.
.data
fpattern db "*.txt",0
hfile dd 0
pfbuff dd 0
flen dd 0
fname db "H:\Project\filetest.txt",0
count1 dd 0
;----------------------------------------------------------------------
.code
start:
;---------------
; load file into a buffer
;----------------
invoke read_disk_file,addr fname,addr pfbuff, addr flen
cmp eax, 0
jne @F
print "file open error",13,10
inkey
exit
@@:
xor esi, esi
mov esi, pfbuff ; move the address into esi
jmp count_
pre_count:
xor ecx, ecx
add esi, 1
count_:
cmp byte ptr [esi], 0 ; check for end of file
je exit_
cmp byte ptr [esi], 10 ; check for end of line
je reset_count
add ecx, 1 ; keep count of characters in ecx
add esi, 1
jmp count_
; --------------------------------------------------------
; replace the value in count1 with ecx if it is less than the value in ecx
;----------------------------------------------------------
reset_count:
cmp ecx , count1
jna pre_count
mov count1, ecx
jmp pre_count
;--------------------
; display the results
;--------------------
exit_:
free pfbuff
print "highest character count: - "
print ustr$(count1),13,10
inkey
exit
end start
I had not looked at it before, but the read_disk_file proc seems to have several points of possible failure that is not passed to the user. Perhaps it would be better to handle the reading yourself to see what's going wrong. It's not that hard to do a getfilesize, followed by a heapalloc and a readfile. Or perhaps in your case better to do a CreateFileMapping, and MapViewOfFile.
Jimg
appreciate the feed back.
i had inserted some code (not in the above post) just to test what was going wrong.
the first value in esi returns the right letter, like is in the file but it somehow doesn't go pasthe je exit line here count_:
cmp byte ptr [esi], 0 ; check for end of file
je exit
seems kinda contradictory.
[code
xor esi, esi
mov esi, pfbuff ; move the address into esi
xor ecx, ecx ; need this or the first line could prestart with a large amount
jmp count_
reset_count:
add ecx, 1 ; add this so cr and lf are both counted
cmp ecx , count1
How about posting a file with some actual working code? Trying to assemble your code as you posted it was a problem.
This code:jne @F
print "file open error",13,10
inkey
exit
@@:
created the error "error A2006: undefined symbol : @@"
some kind of interaction with the macro I guess.
On the surface, your code looks ok. Give us a fully functioning (or in this case dis-functioning but assembleable) file to play with.
xor esi, esi
mov esi, pfbuff ; move the address into esi
jmp count_
Here is no need for xor ESI,ESI .
No mater what You "do" with ESI it will be "overwrited" in next line : mov ESI,pfbuff
add ecx, 1 ; keep count of characters in ecx
add esi, 1
jmp count_
If You have to add just 1 to "something" You can use INC it increments destination by 1 and its "smaller and faster"
for example :
INC ECX
INC ESI
Same You can subtract something by 1 with DEC
for example :
DEC ECX ; is like SUB ECX,1
DEC dword ptr[ESI] ; ect
And one more thing.
You should always remember that many things (input data) are dynamic and most of time You cant be sure
if given data will be the way You expect it to be, or it even can be completly invalid.
You have to "expect" and be ready for most of things that can be given to You as a input.
For example : You expect that file is terminated by 0 while *.txt files ARENT terminated by 0
Also depends what program (notepad) You use to create *.txt file You may encounter 10 or 10,13 as EndOfLine.
If it hapen, will You count 13 as a CHR ? You may also, have completly nothing at EndOfFile, no 0 no 10 and no 10,13
if *.txt file creator will not press ENTER after last word.
I would use a different way of checking for EOF
xor esi,esi
mov edi, pfbuff
jmp count_
pre_count:
xor ecx, ecx
add esi, 1
count_:
cmp esi,flen
jae exit_
cmp byte ptr [edi+esi], 10 ; check for end of line
je reset_count
add ecx, 1 ; keep count of characters in ecx
add esi, 1
jmp count_
QuoteHow about posting a file with some actual working code? Trying to assemble your code as you posted it was a problem.
This code:
Code:
jne @F
print "file open error",13,10
inkey
exit
@@:
created the error "error A2006: undefined symbol : @@"
some kind of interaction with the macro I guess.
Jimg the code was assembling properly for me. - To make doubly sure i copied the code in my first post
again & assembled it. - I am not getting any error of the kind you mention.
btw now the character count am getting is some number but its wrong.
sometimes the char count changes to 0 again if i edit the file being tested
sinsi,
i tried with your code.. & its still not functioning proper.
today when i was testing it seems that if there is just 1 line the result becomes zero, & at other times it returns the total characters in the file instead of just the highest in a line.
thanks .
[edit] i guess using the flen is a better way but in the main files i tested there weren't any '0' value
ascii chars inserted
I am not sure exactly what you were testing but this mod of your original posted code works fine.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
pfbuff dd 0
flen dd 0
fname db "\masm32\include\windows.inc",0
.code
start:
; -----------------------
; load file into a buffer
; -----------------------
invoke read_disk_file,ADDR fname,ADDR pfbuff,ADDR flen
test eax, eax
jnz @F
print "file open error",13,10
inkey
exit
@@:
print str$(flen)," Returned file length",13,10 ; display the file length.
push ebx
push esi
xor ebx, ebx ; zero ebx
mov esi, pfbuff
sub esi, 1
@@:
add esi, 1
cmp BYTE PTR [esi], 10 ; test for line feed
jne nxt
add ebx, 1 ; count lines while scanning lewngth
nxt:
cmp BYTE PTR [esi], 0 ; test for zero
jnz @B
sub esi, pfbuff
print str$(esi)," Scanned file length",13,10
print str$(ebx)," Scanned file line count",13,10
pop esi
pop ebx
inkey
exit
end start
Result is,
1127755 Returned file length
1127755 Scanned file length
30780 Scanned file line count
Press any key to continue ...
hutch,
the code i wrote is supposed to return the highest no of characters a line contains.
so as it scans the file, the value in the count1 variable is replaced with higher character counts other lines might have. & in the end the highest one is displayed.
thanks.
sebart7,
thanks for all that info. - when i read a file into a buffer isn't a 0 added at the end ?
QuoteAlso depends what program (notepad) You use to create *.txt file You may encounter 10 or 10,13 as EndOfLine.
- wasn't aware that
13i could be the end of line thought it was
10 like 13,10
so what do i use to detect an 'end of line'
@@:
xor esi, esi
mov esi, pfbuff ; move the address into esi
jmp count_
On entry, ECX isn't initialised to 0, so the first time around ECX actually has the file length (as returned by read_disk_file).
Maybe "xor esi,esi" is supposed to be "xor ecx,ecx"?
I think this does what you want.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
pfbuff dd 0
flen dd 0
count1 dd 0
fname db "\masm32\include\windows.inc",0
.code
start:
; -----------------------
; load file into a buffer
; -----------------------
invoke read_disk_file,ADDR fname,ADDR pfbuff,ADDR flen
test eax, eax
jnz @F
print "file open error",13,10
inkey
exit
@@:
print str$(flen)," Returned file length",13,10 ; display the file length.
push ebx
push esi
push edi
xor ebx, ebx ; zero ebx
xor edi, edi ; zero edi
mov esi, pfbuff
sub esi, 1
@@:
add esi, 1
add edi, 1
cmp BYTE PTR [esi], 10 ; test for line feed
jne nxt
add ebx, 1 ; count lines while scanning length
cmp edi, count1
jle ovrit
mov count1, edi
ovrit:
xor edi, edi
nxt:
cmp BYTE PTR [esi], 0 ; test for zero
jnz @B
sub esi, pfbuff
print str$(count1)," characters longest line length",13,10
print str$(esi)," Scanned file length",13,10
print str$(ebx)," Scanned file line count",13,10
pop edi
pop esi
pop ebx
inkey
exit
end start
Sinsi had the answer, it's initializing ecx that was the problem.
Your original code will work with that change. That's not to say it couldn't use some work as others have indicated :wink
There will be a zero byte terminator on the file since the read_disk_file macro will zero memory before reading, and adds an extra 32 bytes just to make sure. But it would be better form to get the size of the file and process that many bytes.
I am still getting the same error with the @@: that I mentioned. If it works for everyone else, there must be something wrong with my setup. I'm using Masm 6.15 if it makes a difference.
As to the carriage return problem. I've always considered a line feed as a change to a new line. You may find a line feed alone at the end of a line or as you say, usually a 13,10. So that part should be ok except do you really want to count a carriage return as part of the length of a line? I'm sure you can figure out the code to count it or not.
And to everyone else, is there a system where a 13 indicates an end of line? Unix perhaps? I am working on a program right now that needs this info. In my experience, a carriage return was meant for a printer to return to the beginning of the current line to do overstrikes, etc. Only the linefeed actually advanced the line.
Edit:
I was making a debug build of your program, and this was causing the problem with the @@:
Making a release version solved the problem, but I have no idea why it would be a problem in a debug build. Anyone?
Jim,
The MAC used to do it that way, ascii 13 only and a later Windows rich edit control works internally with only and ascii 13.
PS : Also check if you are running a custom "print" macro as the standard masm32 "print" macro has no problems with that style of code layout.
Hutch-
Well, I'm certainly not going to worry about mac files :snooty:
As for the error, did you try it making a debug build? I used these parameters - /c /coff /Cp /nologo /Fm /Zi /Zd /Fl /Sn
And I get this-
00000014 33 C9 invoke read_disk_file,addr fname,addr pfbuff, addr flen
00000016 83 F8 00 xor ecx,ecx
cmp eax, 0
F:\WinAsm\Progs\AMiscTests\consoletest2\Console.Asm(26) : error A2006: undefined symbol : @@
jne @f
2 LOCAL nustr
= " 2 quot SUBSTR <"file open error">,1,1
2 IFIDN quot,<">
00000019 0000002E 2 .data
0000002E 66 69 6C 65 20 2 ??0019 db "file open error",0
6F 70 65 6E 20
65 72 72 6F 72
00
00000021 2 .code
2 EXITM <ADDR ??0019>
00000021 68 0000002E R * push OFFSET ??0019
00000026 E8 00000000 E * call StdOut
1 invoke StdOut,reparg("file open error")
1 IFNB <13,10>
2 LOCAL txtname
0000002B 0000003E 2 .data
0000003E 0D 0A 00 2 ??001A db 13,10,0
0000002B 2 .code
2 EXITM <OFFSET ??001A>
0000002B 68 0000003E R * push dword ptr OFFSET FLAT:??001A
00000030 E8 00000000 E * call StdOut
1 invoke StdOut,chr$(13,10)
1 ENDIF
print "file open error",13,10
1 IFDIF <>,<NULL>
1 IFNB <>
1 print ;; print user defined text
1 ELSE ;; else
1 print "Press any key to continue ..." ;; print default text
3 LOCAL nustr
= " 3 quot SUBSTR <"Press any key to continue ...">,1,1
3 IFIDN quot,<">
00000035 00000041 3 .data
00000041 50 72 65 73 73 3 ??001B db "Press any key to continue ...",0
20 61 6E 79 20
6B 65 79 20 74
6F 20 63 6F 6E
74 69 6E 75 65
20 2E 2E 2E 00
00000035 3 .code
3 EXITM <ADDR ??001B>
00000035 68 00000041 R * push OFFSET ??001B
0000003A E8 00000000 E * call StdOut
2 invoke StdOut,reparg("Press any key to continue ...")
2 IFNB <>
2 invoke StdOut,chr$()
2 ENDIF
1 ENDIF
1 ENDIF
0000003F E8 00000000 E 1 call wait_key
1 print chr$(13,10)
3 LOCAL txtname
00000044 0000005F 3 .data
0000005F 0D 0A 00 3 ??001C db 13,10,0
00000044 3 .code
3 EXITM <OFFSET ??001C>
3 LOCAL nustr
= O 3 quot SUBSTR <OFFSET ??001C>,1,1
3 IFIDN quot,<">
3 .data
3 ??001D db OFFSET ??001C,0
3 .code
3 EXITM <ADDR ??001D>
3 ELSE
3 EXITM <OFFSET ??001C>
00000044 68 0000005F R * push dword ptr OFFSET FLAT:??001C
00000049 E8 00000000 E * call StdOut
2 invoke StdOut,reparg(OFFSET ??001C)
2 IFNB <>
2 invoke StdOut,chr$()
2 ENDIF
inkey
1 IFNDEF
0000004E 6A 00 * push +000000000h
00000050 E8 00000000 E * call ExitProcess
1 invoke ExitProcess, 0
1 ELSE
1 invoke ExitProcess,
1 ENDIF
exit
00000055
00000055 33 F6 @@:
00000057 8B 35 0000000A R xor esi, esi
0000005D EB 05 mov esi, pfbuff ; move the address into esi
Sorry for the mess, but I would like to get to the bottom of this. Perhaps you would like to move this part to a new thread?
Jim,
I have not used debug builds since masm 6.0 in the early 90s in DOS. Does it build OK without the debug build, "/c /coff" minimum style ?
Yes, it assembles with no errors. (But of course it won't link, but that's not what we're working on.)
Here's the minimum program that has the problem -
.nolist
include \masm32\include\masm32rt.inc
.listall
.code
start:
jmp @f
print "x"
@@:
exit
end start
Not here it doesn't.
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
Assembling: H:\asm3\rstorm\jimg\jimg.asm
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Volume in drive H is WIN2K_H
Volume Serial Number is 20E8-3719
Directory of H:\asm3\rstorm\jimg
04/11/2007 03:58a 117 jimg.asm
04/11/2007 03:58a 997 jimg.obj
04/11/2007 03:58a 2,560 jimg.exe
3 File(s) 3,674 bytes
0 Dir(s) 19,336,445,952 bytes free
Press any key to continue . . .
QuoteOn entry, ECX isn't initialised to 0, so the first time around ECX actually has the file length (as returned by read_disk_file).
sinsi, that was it,
: ) now it functions properly except if there is just
one line in the file (then it returns 0 & not the proper character count) - but i realised that was because the EOF is on that 1st line itself so to speak, & I was using the zero terminator to check the EOF.
Same thing was happening with the last code hutch posted, i.e it shows a '0' charactercount if there is just one line in the file. - I will use the 'flen' method & that would eliminate that problem too.
jimg , am using the usual 6.14 version that comes with the masm package.
thanks all.
Rainstorm
-
Rainstorm-
Glad you got it all working. I didn't mean to hijack your thread, I'll start a new thread with my problem.
no probs :)
in, the below code ecx becomes 0 in the line pre_count:
xor ecx, ecx
yet in the end ecx seems to hold the right character count of the whole file & matches the file length
mov scanned_length, ecx <--- that line
how come ? that's weird
.data
pfbuff dd 0
flen dd 0
fname db "H:\Project\filetest1.txt",0
count2 dd 0
scanned_length dd 0,0
;----------------------------------------------------------------------
.code
start:
invoke read_disk_file,addr fname,addr pfbuff, addr flen
cmp eax, 0
jne @F
print "file open error",13,10
inkey
exit
@@:
print "returned file length - "
print ustr$(flen),13,10
xor ecx, ecx
mov esi, pfbuff
jmp count_
pre_count:
xor ecx, ecx <--- ecx 0 here
add esi, 1
count_:
cmp ecx, flen ; check for 'end of file'
je exit_
cmp byte ptr [esi], 10 ; check for 'end of line'
je reset_count
add ecx, 1 ; keep count of characters in ecx
add esi, 1
jmp count_
; --------------------------------------------------------
; replace the value in count1 with ecx if is less than the value in ecx
; --------------------------------------------------------
reset_count:
cmp ecx, count1
jna pre_count
mov count1, ecx
jmp pre_count
;--------------------
; display the results
;--------------------
exit_:
mov scanned_length, ecx <-- ecx still holding the right character count of the whole file here
free pfbuff
print "scanned length - "
print ustr$(scanned_length),13,10
print "highest character count: - "
print ustr$(count1),13,10
inkey
exit
end start
apparently the very last line is the longest, and it doesn't have a newline on the end.
yes that's true too.
i got it
actually because ecx gets reset the loop is running along in the buffer far past the file length.
thx