I'm not certain where I found this program but I suspect it was from somewhere on Dilwyn Jones QL site http://www.dilwyn.me.uk/. It was written by Tony Tebby and was embedded in a document explaining the modular structure of smsqe:
Scanning an SMSQ OS File:
An SMSQ file can be scanned fairly easily with a simple SBASIC
program:
l00 REMark - scan bootloader file
110 DIM version$(4): version$(0)=4
120 OPEN #0,CON: CLS: BORDER 1,4
130 height = 17
140 INPUT 'SMSQ file>';f$
150 OPEN IN #3,f$
160 fln = FLEN(#3)
170 LGET #3\fln-$18+$4,mod_ptr : REMark - get length of host module
180 LGET #3\fln-$18+$14,bln : REMark - length of bootloader file
190 IF bln: mod_ptr = mod_ptr + fln - bln
200 FOR i=1 to 9999
210 LGET #3\(mod_ptr),mbase,mlength
220 IF NOT mbase: EXIT : REMark - end of file
230 IF NOT i mod height: INPUT a$; : REMark - pause at screen full
240 WGET#3\(mod_ptr+$16),name_rel: REMark - relative pointer to name
250 GET#3\(mod_ptr+$16+name rel),name$ : REMark - fetch module name
260 IF LEN (name$)&&1: BGET#3,a : REMark - odd length name is padded
270 BGET #3,version$(1 TO 4) : REMark - get version, if any
280 PRINT HEX$(mlength,24) !! version$ ! name$
290 mod_ptr = mod_ptr + mbase + mlength
300 END FOR i
310 CLOSE #3
320 INPUT a$
This will print the index (in hex), the version and the name of all except the host module.

This is the typical output of the file. Now here is a first pass improved version of the program.
100
REMark - scan bootloader file
110 DIM version$(4): version$(0)=4
120
OPEN #0,CON_512x420a20x16: CLS: BORDER 1,4
130 height = 52 : DIM
d$(height,84) : pg=1
140 INPUT 'SMSQ file>';f$ : IF
f$="":QUIT
150 OPEN_IN #3,f$
160 fln = FLEN(#3) :
PRINT#0,CHR$(10)&HEX$(fln,32)&" length of
file"&CHR$(10)
170 LGET #3\fln-$18+$4,mod_ptr : REMark - get
length of host module
175 PRINT#0,HEX$(mod_ptr,32)&" length of
host module"&CHR$(10)
180 LGET #3\fln-$18+$14,bln : REMark - length of bootloader file
185
PRINT#0,HEX$(bln,32)&" length of bootloader
file"&CHR$(10)
190 IF bln: mod_ptr = mod_ptr + fln - bln
200
FOR i=1 to 9999
210 LGET
#3\(mod_ptr),mbase,mlength
220 IF
NOT mbase: EXIT : REMark -
end of file
230 IF NOT i mod
height: Inc : pg=pg+1 : INPUT a$; :
REMark - pause at screen full
240
WGET#3\(mod_ptr+$16),name_rel: REMark - relative pointer to name
250 GET#3\(mod_ptr+$16+name_rel),name$ : REMark - fetch module name
260 IF LEN (name$)&&1: BGET#3,a :
REMark - odd length name is padded
270
BGET #3,version$(1 TO 4) : REMark - get version, if any
280 PRINT HEX$(mod_ptr,32) !!!!
HEX$(mlength,24) !! version$ ! name$
285
d$(i)=HEX$(mod_ptr,32)&"
"&HEX$(mlength,24)&"
"&version$&" "&name$
290 mod_ptr = mod_ptr + mbase + mlength
300
END FOR i
310 CLOSE #3 : PRINT#0,CHR$(10)&HEX$(mod_ptr,32)&"
end of file"
320 PRINT#0,\"Save data as text file (S/s) or Quit
program"
330 in=INKEY$(#0,-1) INSTR 'SsQq'&CHR$(27): REMark wait
to close program
340 SELect on in
350 =1,2 : INPUT 'save file name>';sf$ : IF
sf$="":QUIT
360
=Remainder : QUIT
370 END SELect
380 OPEN_NEW#3,sf$ :
PRINT#3,f$\\HEX$(fln,32)&" length of file"&CHR$(10)
390
FOR i=1 TO height : IF d$(i)<>"": PRINT#3,d$(i) : END FOR
i
400 PRINT#3,\\HEX$(mod_ptr,32)&" end of file"
410
CLOSE#3 : QUIT
420 :
430 DEFine PROCedure Inc
440 LOCal z$(height*pg),j
450 FOR j=1 TO height*pg : z$(j)=d$(j)
460 DIM d$(height*pg)
470 FOR j=1 TO height*pg :d$(j)=z$(j)
480
END DEFine

This gives more useful information and now gives an option to save the screen output to a text file.