The MASM Forum

General => The Workshop => Topic started by: jj2007 on January 23, 2024, 12:20:01 PM

Title: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 23, 2024, 12:20:01 PM
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:
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 23, 2024, 01:46:29 PM
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.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: TimoVJL on January 23, 2024, 06:11:57 PM
When MS-DOS extensions are MAX 3, those are like DWORDs and easy to access.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 23, 2024, 08:38:47 PM
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.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 23, 2024, 09:20:16 PM
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
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 23, 2024, 11:07:59 PM
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.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 05:46:28 AM
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
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 24, 2024, 08:08:59 AM
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.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 08:15:56 AM
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?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 24, 2024, 08:22:42 AM
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!
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 24, 2024, 08:47:54 AM
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>
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 10:13:21 AM
.jpeg and .json files are very common now. Is the point necessary?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 10:16:10 AM
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?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 12:47:17 PM
Quote from: jj2007 on January 24, 2024, 10:16:10 AM
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?


No. Exactly here. Perhaps you don't have an answer.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: NoCforMe on January 24, 2024, 12:48:30 PM
Are you referring to the fact that these extensions are 4 characters, not 3?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 12:53:50 PM
More than obvious  :thumbsup:
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 01:01:23 PM
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...
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 08:31:38 PM
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?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 08:42:55 PM
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)).
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 09:05:06 PM
RinstrX("file1.xlsx",1,.xls,.xlsx,.doc,.docx,.htm,.html)  ?
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 09:38:59 PM
  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.
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: TimoVJL on January 24, 2024, 09:51:54 PM
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:
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 10:02:10 PM
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:
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: HSE on January 24, 2024, 10:44:57 PM
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
Title: Re: RinstrX returns an index (for use with file extensions)
Post by: jj2007 on January 24, 2024, 10:59:25 PM
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 ;-)