News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

RinstrX returns an index (for use with file extensions)

Started by jj2007, January 23, 2024, 12:20:01 PM

Previous topic - Next topic

jj2007

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$() and Rinstr() with the corresponding functions of your library :cool:

NoCforMe

#1
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.
Assembly language programming should be fun. That's why I do it.

TimoVJL

When MS-DOS extensions are MAX 3, those are like DWORDs and easy to access.
May the source be with you

jj2007

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.

NoCforMe

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
Assembly language programming should be fun. That's why I do it.

jj2007

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.

jj2007

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

NoCforMe

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.
Assembly language programming should be fun. That's why I do it.

jj2007

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().

AFAIK there is no Masm32 SDK equivalent to Rinstr - maybe the CRT has one?

NoCforMe

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!
Assembly language programming should be fun. That's why I do it.

NoCforMe

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>
Assembly language programming should be fun. That's why I do it.

HSE

.jpeg and .json files are very common now. Is the point necessary?
Equations in Assembly: SmplMath

jj2007

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. There is a direct download to a DLL.

I made a quick test:

include \masm32\MasmBasic\MasmBasic.inc
  Init            ; old VB library
  Dll "mslib145"      ; download
  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?

HSE

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.
Equations in Assembly: SmplMath

NoCforMe

Are you referring to the fact that these extensions are 4 characters, not 3?
Assembly language programming should be fun. That's why I do it.