Author Topic: The strpbrk function - Should it not be used in QB64 programs?  (Read 3485 times)

0 Members and 1 Guest are viewing this topic.

Offline EricE

  • Forum Regular
  • Posts: 114
    • View Profile
The strpbrk function - Should it not be used in QB64 programs?
« on: February 21, 2020, 05:52:29 pm »
The C language "string pointer break" function,  strpbrk, has this prototype:
Quote
char* strpbrk(char* dest, const char* breakset );
and it performs this function:
Quote
Scans the null-terminated byte string pointed to by dest for any character from the null-terminated byte string pointed to by breakset, and returns a pointer to that character.
https://en.cppreference.com/w/cpp/string/byte/strpbrk

In QB64 the strpbrk function is made callable using the declaration:
Code: QB64: [Select]
  1.         'Find the first occurrence in x$ of any of the characters in y$.
  2.         FUNCTION strpbrk%& (x$, y$)
  3.     END DECLARE
  4.  

The strpbrk returns a pointer to a character in a string, but QB64 might at any time move a string to another memory location.
If QB64 relocates the string after strpbrk has been called, then the returned character address will no longer be valid.

Should we conclude that the strpbrk function not be used in QB64 programs?

Some more question about how QB64 works.
  • Does QB64 pass the x$ and y$ strings to the strpbrk%& function by reference, or by value?
  • Will the strpbrk function see the x$ and y$ parameters as null-terminated character strings?


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #1 on: February 21, 2020, 06:10:08 pm »
I’d say:

1) Use with fixed length string *only*, as they never move in memory.
2) QB64 strings aren’t null terminated by default, so either add a CHR$(0) to your strings, or manually error check:

Startpos = _OFFSET(fixedlengthstring$)
Findpos = strpbrk(fixedlengthstring$, “foo”)
If Findpos - Startpos > LEN(fixedlengthstring$) THEN Findpos = 0 ‘null terminator outside string memory area


Note: I can’t swear the above still wouldn’t give error messages if the function failed to find a CHR$(0) before hitting restricted memory.  I don’t think ‘d personally consider it safe to use, except when I knew I was working with null-terminated strings.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

FellippeHeitor

  • Guest
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #2 on: February 21, 2020, 06:18:22 pm »
Any advantages to using the C call instead of INSTR, for example?
« Last Edit: February 21, 2020, 06:19:59 pm by FellippeHeitor »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #3 on: February 21, 2020, 06:20:23 pm »
Hi EricE
welcome to the forum!
Waiting other coders more expert and/or the developers of QB64  with their accurately answers
my 2 cents
about 
Quote
Should we conclude that the strpbrk function not be used in QB64 programs?
I can observe that  "string pointer break" function,  strpbrk works like INSTR of Qbasic but using pointers and String Null terminated, like C usually is used to do.

about
Quote
Does QB64 pass the x$ and y$ strings to the strpbrk%& function by reference, or by value?
IMHO QB has always passed arguments as reference except some cases among these there are external procedure see here http://www.qb64.org/wiki/DECLARE_LIBRARY and here http://www.qb64.org/wiki/Parenthesis

about
Quote
Will the strpbrk function see the x$ and y$ parameters as null-terminated character strings?
I think no because I have seen many example code with interface with C/C++ in which you must manually add CHR$(0) at the end of string before use them as parameter of a C function. See here http://www.qb64.org/wiki/Windows_Libraries#Windows_API

PS Too late :-)))
Programming isn't difficult, only it's  consuming time and coffee

Offline EricE

  • Forum Regular
  • Posts: 114
    • View Profile
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #4 on: February 22, 2020, 03:00:05 pm »
Thank you SMcNeill, FellippeHeitor, and TempodiBasic for your replies.
Thank you TempodiBasic for the welcome to the forum.

The answer to my question is that the strpbrk function can be used in QB64 programs.
The requirements for calling the function are:
  • The strpbrk must be made callable by declaring it as a library function
  • strpbrk's first parameter, the string to be searched, must be a fixed length string so that its position in memory does not change.
  • Both of strpbrk's parameters must be null terminated. This is because of how the C language determines the end of a string.
There is another consideration.
  • The QB64 declared version of strpbrk, strpbrk%&, will return an _OFFSET address value. This will require an _OFFSET value being changed to an INTEGER type.
Here is QB64 code for the sinstr% (x$, y$) function.
It uses strpbrk to find the string position in x% of the first occurrence of any character in y$.

Code: QB64: [Select]
  1. DECLARE FUNCTION sinstr% (str1$, set1$)
  2.  
  3. a$ = "Hello"
  4. b$ = "ol"
  5.  
  6. i% = sinstr(a$, b$)
  7.  
  8.  
  9. '-------------------------------------------------------------------------------
  10. ' Function: sinstr% (str1$, set1$)
  11. ' Finds position in str1$ of first occurrence of any of the characters in set1$
  12. '
  13. '------------------------------------------------
  14. ' References:
  15. ' https://www.qb64.org/wiki/MEM
  16. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5967-30/
  17. '------------------------------------------------
  18.  
  19. FUNCTION sinstr% (str1$, set1$)
  20.         'Find the first character in x$ of any of the characters in y$.
  21.         FUNCTION strpbrk%& (x$, y$)
  22.     END DECLARE
  23.  
  24.     DIM m AS _MEM 'Define a memblock
  25.  
  26.     ' copy variable strings to fixed length strings
  27.     ' add terminating null.
  28.     str1$1024 = str1$ + CHR$(0)
  29.     set1$ = set1$ + CHR$(0)
  30.  
  31.     find_first_of%& = strpbrk%&(str1$1024, set1$)
  32.     IF find_first_of%& <> 0 THEN
  33.         'Strings are unit-based in QB64, so we must add 1.
  34.         find_first_of%& = find_first_of%& - _OFFSET(str1$1024) + 1
  35.     END IF
  36.     m = _MEM(find_first_of%&)
  37.  
  38.     $IF 64BIT THEN
  39.         'On 64 bit OSes, an OFFSET is 8 bytes in size.
  40.         _MEMGET m, m.OFFSET, temp&&
  41.         sinstr% = temp&&
  42.     $ELSE
  43.         'However, on 32 bit OSes, an OFFSET is only 4 bytes.
  44.         _MEMGET m, m.OFFSET, temp&
  45.         sinstr% = temp&
  46.     $END IF
  47.  
  48.     _MEMFREE m 'Free the memblock
  49.  

Offline EricE

  • Forum Regular
  • Posts: 114
    • View Profile
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #5 on: February 22, 2020, 03:11:49 pm »
FellippeHeitor wrote:
Quote
Any advantages to using the C call instead of INSTR, for example?
Definitely not!
Using INSTR to implement the sinstr% function requires only 10 lines of QB64 code.
The code simpler and looks much better than the version using strpbrk.
Also the INSTR version does not require worrying about strings being of fixed length and null terminated.
It just works!

Code: QB64: [Select]
  1. DECLARE FUNCTION sinstr% (str1$, set1$)
  2.  
  3. a$ = "Hello"
  4. b$ = "lo"
  5.  
  6. i% = sinstr(a$, b$)
  7.  
  8.  
  9. 'Find the first character in str1$ of any of the characters in set1$.
  10.  
  11. FUNCTION sinstr% (str1$, set1$)
  12.     sinstr% = 0
  13.     FOR i% = 1 TO LEN(str1$)
  14.         ptr% = INSTR(set1$, CHR$(ASC(str1$, i%)))
  15.         IF ptr% <> 0 THEN
  16.             sinstr% = i%
  17.             EXIT FOR
  18.         END IF
  19.     NEXT i%

FellippeHeitor

  • Guest
Re: The strpbrk function - Should it not be used in QB64 programs?
« Reply #6 on: February 22, 2020, 03:39:24 pm »
Glad to hear you found your way around it. You can also replace two function calls - the CHR$(ASC(str1$, i%)) bit - with one: MID$(str1$, i%, 1).
« Last Edit: February 22, 2020, 03:42:50 pm by FellippeHeitor »