Shop OBEX P1 Docs P2 Docs Learn Events
How to copy strings using bytemove (Spin,Flexprop) ? — Parallax Forums

How to copy strings using bytemove (Spin,Flexprop) ?

I wrote a method to copy one string into another (inserting a short string into a longer one, replacing the old content of the destination)

It works.

pub strcpy(sto,sfrom,ifrom,count) |i

repeat i from 0 to count-1
  byte[sto+ifrom+i]:=byte[sfrom+i]

I tried to use bytemove to achieve the same results, without success. (and with strange side effects instead)
Is it possible to replace the loop with bytemove? If yes, how?

Comments

  • AribaAriba Posts: 2,690

    I would try it like that:

      bytemove(sto+ifrom, sfrom, count)
    
  • JonnyMacJonnyMac Posts: 9,102
    edited 2021-11-23 17:28

    Andy's example will work. I've not (yet) needed to instert a string, but I often replace one with another. I do it like this

      bytemove(p_dest, p_src, strsize(p_src)+1)
    

    The +1 ensures that the terminating 0 is also copied so we don't end up with fragments of the original string. Of course, p_dest must be the same length or larger than p_src.

  • If count is the length of the string AND the zero at the end, Ariba's code is all you need, otherwise you will need to take other steps to ensure the zero-termination.

    I clear my entire destination buffer to zeros first, then copy the actual string. This ensures that I have the zero termination, and makes me think about whether I've done something stupid like copy a string that's longer than the buffer.

    One of my big gotchas was copying a string that wasn't zero terminated, after setting count from strsize() and getting a length of who-knows-what!

  • pik33pik33 Posts: 2,366

    @Ariba said:
    I would try it like that:

      bytemove(sto+ifrom, sfrom, count)
    

    This didn't work, inserting garbage into the string. It seems I have to try this in a clean environment, and, if it still fails, report a bug, else find a bug in my code.

  • Here is some code I use for handling strings on the P1. It should easily adapt to P2
    `
    pub NewString 'Clear the string buffer

        StrPtr := @StrBufr
        StrBufr[0] := 0
        bytefill(@StrBufr,0,BufferSize)
        Return StrPtr
    

    pub AddString(str) |StrLen, BufCap

        StrLen := STRSIZE (str)
        BufCap := BufferSize-STRSIZE(@StrBufr)
        if StrLen > BufCap
          return true
        bytemove(StrPtr,str,StrLen)
        StrPtr += (StrLen)
    
        return StrPtr
    

    pub CopyString(str)

        bytemove(@StrBufr,str,STRSIZE(str))
    

    `

  • JonnyMacJonnyMac Posts: 9,102
    edited 2021-11-23 18:05

    The arguments for your method aren't clear. I took ifrom to mean how far from the beginning of the source string to start the copy process. It works.

  • R BaggettR Baggett Posts: 155
    edited 2021-11-23 18:07

    One potential source of 'garbage' is this:

    I have a string in the array String[256]..

    If I call AddString(String) I will get a whole lot of garbage from whatever the first 4 bytes of my string point to when interpreted as a LONG

    If I call AddString(@String) I will properly pass the address of String, which will result in correct operation.

  • I looked up the C version of strcpy().

    To duplicate that in Spin you would do this:

      bytemove(p_dest, p_src, strsize(p_src)+1)
    

    The +1 with strsize() ensures that the terminating 0 is copied as well. I suggest you simplify your version like this:

    pub strcpy(p_dest, p_src, count)
    
      bytemove(p_dest, p_src, count)
    

    It's just a wrapper, but may make your code easier for others to understand.

  • If I call AddString(@String) I will properly pass the address of String, which will result in correct operation.

    Yes. When dealing with strings, you always have to deal with their addresses.

  • Wuerfel_21Wuerfel_21 Posts: 5,053
    edited 2021-11-23 20:58

    Winners don't do strcpy

    (unless they're really really sure).
    C's strncopy isn't much better, either.
    A correct and safe string copy in Spin2 would be

    PUB stringcopy(to,from,max_size)
      if max_size > 1
        repeat max_size-1
          ifnot byte[to++] := byte[from++]
            return
      if max_size > 0
        byte[to] := 0 
    

    or using bytemove

    PUB stringcopy(to,from,max_size)
      if max_size > 0
        bytemove(to,from,strsize(from) <# max_size)
        byte[to+max_size-1] := 0
    

    or "brr go fast" (untested)

    PUB stringcopy(to,from,max_size)
      org
            mov ptrb,to
            rdfast #0,from
            rep @.loop,max_size
            rfbyte from wz
            wrbyte from,ptrb++
      if_z  ret
      .loop
            wrbyte #0,--ptrb
      end
    
  • All this talk about "strcpy" is kind of missing the point of the original post, I think -- the original code was not a string copy, but rather inserting some number of characters into the middle of a string. So probably the function would better have been named "strins", it's not the same as C "strcpy".

    Here's a program to do that using bytemove:

    CON
      _clkfreq = 180_000_000
    
    OBJ
      ser: "jm_serial"
    
    DAT
    
    str1 byte "hello, world!", 13, 10, 0
    
    pub main()
      ser.start(230_400)
      ser.str(@str1)
      strins(@str1, string("you! "), 7, 5)
      ser.str(@str1)
      strins(@str1, string("xxx"), 1, 3)
      ser.str(@str1)
    
    pub strins(sto, sfrom, ifrom, count)
      bytemove(sto+ifrom, sfrom, count)
    
    { ' original implementation
    pub strins(sto,sfrom,ifrom,count) |i
      repeat i from 0 to count-1
        byte[sto+ifrom+i]:=byte[sfrom+i]
    }
    

    Output is:

    hello, world!
    hello, you! !
    hxxxo, you! !
    
  • Cluso99Cluso99 Posts: 18,069

    IMHO you need to move the original string from its' end+1 to its' new end+1 (which is the size of the inserted string past the current end) and step -1 back to the insertion point.
    This allows for the problem of moving the original string with overlapping data.

  • well depends if it overlaps on the end or the beginning.

    But if I remember correctly Spin 1 byte/word/longmove take that into account.

    Mike

Sign In or Register to comment.