I needed an index as a function of a file extension:
xor ecx, ecx ; file format index
.if Instr_(edi, ".xls", 1)
inc ecx
.else
.if Instr_(edi, ".mdb", 1)
inc ecx
inc ecx
.else
.if Instr_(edi, ".dbf", 1)
add ecx, 3
.else
.if Instr_(edi, ".wk", 1) ; Lotus wk*, Works
add ecx, 4
.endif
.endif
.endif
.endif
dec ecx
js NoFile ; Extension not implemented
So far, so clear. However, there are lots of ifs, which is somewhat clumsy if you have more than 3 or 4 extensions to test. So I wrote a macro that shortens the exercise:
test ecx, RinstrX(edi, 1, .xls, .mdb, .dbf, .wk) ; returns index in ecx: 0=xls, 1=mdb, etc
js NoFile ; Extension not implemented
Here is the RinstrX macro:
RinstrX MACRO src, mode, args:VARARG
LOCAL is, arg, tmp$
push ebp
mov ebp, esp
is=0
for arg, <args>
tmp$ CATSTR <Chr$(">, <arg>, <")>
push tmp$
is=is+1
endm
push is-1
pop ecx
.Repeat
pop eax
.Break .if Rinstr(src, eax, mode)
dec ecx
.Until esp>=ebp
leave ; returns 1-based index in ecx, pointer to the
EXITM <ecx> ; match in eax, and position of match in edx
ENDM
If you don't use MasmBasic, just replace Chr$() (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1143) and Rinstr() (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1154) with the corresponding functions of your library :cool:
I prefer a data-driven approach to problems like this:
.data
Ext1 DB "xls", 0
Ext2 DB "mdb", 0
Ext3 DB "dbf", 0
Ext4 DB "wk", 0
Ext5 DB "xyz", 0
ExtensionList LABEL DWORD
DD Ext1
DD Ext2
DD Ext3
DD Ext4
DD Ext5
DD -1 ;End o'list
.code
GetExtIndex PROC ;Ptr. to extension in EDI
LOCAL index:DWORD
MOV index, 0
PUSH EBX
MOV EBX, OFFSET ExtensionList
getlp: CMP DWORD PTR [EBX], -1
JE nofind
INVOKE Instr, EDI, EBX, 1
CMP EAX, 1
JE found
INC index
ADD EBX, SIZEOF DWORD
JMP getlp
found: MOV EAX, index
POP EBX
RET
nofind:MOV EAX, -1
POP EBX
RET
GetExtIndex ENDP
Need more or different extensions? Just edit the list.
When MS-DOS extensions are MAX 3, those are like DWORDs and easy to access.
Quote from: NoCforMe on January 23, 2024, 01:46:29 PMI prefer a data-driven approach
Why waste time on a two-liner if you can do the same with 40 lines?
test ecx, RinstrX(edi, 1, .xls, .mdb, .dbf, .wk) ; returns index in ecx: 0=xls, 1=mdb, etc
js NoFile ; Extension not implemented
Quote from: TimoVJL on January 23, 2024, 06:11:57 PMWhen MS-DOS extensions are MAX 3, those are like DWORDs and easy to access.
Valid point.
What're you talking about? Mine works w/4 lines, minus the function (and let's not forget you have ~20 lines of macro):
LEA EDI, <buffer w/text>
CALL GetExtIndex
CMP EAX, -1
JE NoFile
Quote from: NoCforMe on January 23, 2024, 09:20:16 PMMine works w/4 lines
You need a whole bunch of .DATA declarations, plus the function. My version really works with just a path and an extension.
Quote from: NoCforMe on January 23, 2024, 01:46:29 PMNeed more or different extensions? Just edit the list.
test ecx, RinstrX(edi, 1, .xls, .mdb, .dbf, .wk) ; old
test ecx, RinstrX(edi, 1, .xls, .ldb, .dbf, .wk4, .xyz) ;new
Minor point: yours will fail for .xls in C:\.xlsAnd.dbf\MyFile.dbf - you need to use some variant of InString that starts from the end.
Just for fun, the Masm32 SDK versions of RinstrX and GetExtIndex. Main differences:
- RinstrX is a macro, so code will be generated only if it's effectively being used; in contrast, GetExtIndex is a proc, so it depends on how the library is constructed whether code will be generated or not.
- MB RinstrX works from the end, so a path like C:\.xlsAnd.dbf\MyFile.dbf will not falsely return the index for .xls
- RinstrX is case-insensitive, so .XLS and .xls will be found
- RinstrX is 10 bytes shorter
- a bug in NoCforMe's code was fixed
Quote from: jj2007 on January 23, 2024, 11:07:59 PMMinor point: yours will fail for .xls in C:\.xlsAnd.dbf\MyFile.dbf - you need to use some variant of InString that starts from the end.
I thought of that. Wouldn't yours fail for the same reason? You're not using any special variant of InString() either.
Quote from: NoCforMe on January 24, 2024, 08:08:59 AMWouldn't yours fail for the same reason? You're not using any special variant of InString() either.
Correct for the Masm32 SDK variant. The MasmBasic RinstrX macro uses Rinstr() (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1154).
AFAIK there is no Masm32 SDK equivalent to Rinstr - maybe the CRT has one?
Well, I'll have to say that your solution here is, as usual, a shining example of elegance--even if I'll never use it!
Gratuitous rant here:
All this reminds me of how retarded the Windows file system is when it comes to file names and type identification, which of course is a holdover from the dim dark days of DOS.
I always thought that whatever its faults, Apple's file system was much smarter in this regard. Instead of relying on a group of 3 characters tacked onto the end of the name after a period, Apple files have the type embedded within the file directory, which makes a whole lot more sense. (Well, unless you wanted to play games, as back in DOS days, where you could change the type of a file just by renaming it, say from SOMEPROG.BIN to SOMEPROG.COM.) You set the file type when you create the file, and that's that. There are (presumably) ways to retrieve the file type through the OS.
Plus, why the stupid restrictions on allowable characters in filenames? No "?/\|=<>", etc.? (Sheesh, at least we can now actually use spaces in "long filenames"; whoop-te-do.) Again, a throwback to DOS.
<end_rant>
.jpeg and .json files are very common now. Is the point necessary?
Quote from: NoCforMe on January 24, 2024, 08:22:42 AMWell, I'll have to say that your solution here is, as usual, a shining example of elegance--even if I'll never use it!
That is very kind of you :thup:
Searching for Rinstr or InstrRev, I stumbled over an old VB library - see this post in the FreeBasic forum (https://freebasic.net/forum/viewtopic.php?t=31940). There is a direct download to a DLL (http://vbtoolbox.kerys.co.uk/bin/vbtoolbox.zip).
I made a quick test:
include \masm32\MasmBasic\MasmBasic.inc
Init ; old VB library (http://vbtoolbox.kerys.co.uk/)
Dll "mslib145" ; download (https://freebasic.net/forum/viewtopic.php?t=31940)
Declare InStrRev, 2
Declare Replace, 3
Print Str$("Test=%i\n", InStrRev("This test tests InStrRev: test", "test"))
REPEAT 5
NanoTimer()
push 999999
.Repeat
Let esi=Replace("quick brown fox","brown","red")
dec stack
.Until Sign?
pop edx
PrintLine NanoTimer$(), " for VB: ", esi
NanoTimer()
push 999999
.Repeat
Let esi=Replace$("quick brown fox","brown","red")
dec stack
.Until Sign?
pop edx
PrintLine NanoTimer$(), " for MB: ", esi
ENDM
EndOfCode
Works like a charm:
Test=27 :cool:
The Replace() function is also reasonably fast. There are quite a number of goodies in that library.
Quote from: HSE on January 24, 2024, 10:13:21 AM.jpeg and .json files are very common now. Is the point necessary?
Wrong thread?
Quote from: jj2007 on January 24, 2024, 10:16:10 AMQuote from: HSE on January 24, 2024, 10:13:21 AM.jpeg and .json files are very common now. Is the point necessary?
Wrong thread?
No. Exactly here. Perhaps you don't have an answer.
Are you referring to the fact that these extensions are 4 characters, not 3?
More than obvious :thumbsup:
Quote from: HSE on January 24, 2024, 10:13:21 AM.jpeg and .json files are very common now. Is the point necessary?
Quote from: HSE on January 24, 2024, 12:47:17 PMNo. Exactly here. Perhaps you don't have an answer.
Oh... now I get it: "point"="dot". So you mean this case:
test ecx, RinstrX("This is a test.json", 1, .xls, .mdb, .json, .wk)
inkey str$(eax), " is the index by RinstrX", 13, 10
Is the dot necessary?
test ecx, RinstrX("C:\XlsJsonJpegEtcFolder\MyFoto.jpeg", 1, .xls, .mdb, .Json, .Jpeg, .wk)
Guess what it would return without the dot...
Quote from: jj2007 on January 24, 2024, 01:01:23 PMOh... now I get it: "point"="dot".
D**m. But perfectly valid in pseudo-english :biggrin: :biggrin:
Quote from: jj2007 on January 24, 2024, 01:01:23 PMIs the dot necessary?
Ok. Perhaps English problem too. Look like, including the "dot", RinstrX is not so useful in 32 bits. Is posible to make modifications to recognice 4 characters instead of 3?
Quote from: HSE on January 24, 2024, 08:31:38 PMIs posible to make modifications to recognice 4 characters instead of 3?
No need to modify the RinstrX macro :cool:
test ecx, RinstrX("C:\HectorsFiles\MyFoto.HSEpic", 1, .xls, .hsepic, .mdb, .Json, .Jpeg, .wk)
js NoSuchExtension
Returns index 1 (the "1" before .xls sets case-insensitive mode (https://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1154)).
RinstrX("file1.xlsx",1,.xls,.xlsx,.doc,.docx,.htm,.html) ?
test ecx, RinstrX("file1.xslx",1,.xsl,.xslx,.doc,.docx,.htm,.html)
print str$(eax), " is the mode 1 index by RinstrX", 13, 10
Works fine, as long as you respect the order first 3-byte, then 4-byte extension.
a good point, as dot is just a dot and point have a larger meaning.
Quotea small, round spot that is used in numbers to separate whole numbers from parts of numbers:
Quote from: TimoVJL on January 24, 2024, 09:51:54 PMa good point, as dot is just a dot
You've made your point, Timo :biggrin:
Quote from: jj2007 on January 24, 2024, 09:38:59 PMWorks fine, as long as you respect the order first 3-byte, then 4-byte extension.
:thumbsup: Perfect.
Sorry, I was thinking in super fast comparison:
mov eax, 'xlsx'
push eax
...
pop eax
.if eax == extension
...
.endif
Quote from: HSE on January 24, 2024, 10:44:57 PMI was thinking in super fast comparison
Less reliable (see examples above), and I doubt you'd ever use it in a speed-critical innermost loop ;-)