Concatenating Strings in a REALbasic Plugin

November 22nd, 2007 by Joe Ranieri

Concatenating strings in REALbasic itself is a very simple operation:

dim str as string = "foo" + "bar"

However, the plugins SDK provides no function for concatenating REALstrings together. There’s also no function we can load through REALLoadObjectMethod or REALLoadGlobalMethod. While it would be nice if it was provided, it’s rather easy to do yourself.

//! Creates a new string by concatenating `firstString` and `secondString`.
REALstring ALConcatStrings(REALstring firstString, REALstring secondString) {
    REALstring convertedFirstString = NULL;
    REALstring convertedSecondString = NULL;
    bool needsUnlock = false;
 
    if(REALGetStringEncoding(firstString) == REALGetStringEncoding(secondString)) {
        // encodings are equal, so no need to convert anything
        convertedFirstString = firstString;
        convertedSecondString = secondString;
    } else {
        // if the two strings aren't in the same encoding, we need to change them both to UTF8
        convertedFirstString = REALConvertString(firstString, kREALTextEncodingUTF8);
        convertedSecondString = REALConvertString(secondString, kREALTextEncodingUTF8);
        needsUnlock = true;
    }
 
    // the total length (in bytes) of the resulting string
    size_t totalLength = convertedFirstString->Length() + convertedSecondString->Length();
 
    // ok, now we need to create a buffer for the total string contents
    char *buffer = (char *)malloc(totalLength);
 
    // copy in the first and second strings' data to the right spots
    memcpy(buffer, convertedFirstString->CString(), convertedFirstString->Length());
    memcpy(buffer + convertedFirstString->Length(), convertedSecondString->CString(), convertedSecondString->Length());
 
    // next we create a REALstring from it
    REALstring result =  REALBuildString(buffer, totalLength, REALGetStringEncoding(convertedFirstString));
 
    // free our buffer (REALbasic copies it on BuildString)
    free(buffer);
 
    // unlock our converted strings if we have to
    if(needsUnlock) {
        REALUnlockString(convertedFirstString);
        REALUnlockString(convertedSecondString);
    }
 
    // phew, that was easy enough!
    return result;
}

I apologize for the awful formatting of this page! It looks decent in an RSS reader at least…


COMMENTS

5 Responses to “Concatenating Strings in a REALbasic Plugin”

  1. Thomas Tempelmann Says:

    I doubt that strncpy is the proper function to use here. Keep in mind that strings may contain binary data, with zero bytes inside. strncpy() would not copy them entirely. memcpy would be safer. Also, I wonder if the rules that RB uses to convert two differently-encoded strings are different from the way your code does it. At the very least, this should be pointed out to the user of such a plugin.

  2. Joe Ranieri Says:

    D’oh. Thanks for pointing that out… That’s what I get for posting so late at night. I also changed the encoding handling to match REALbasic’s.

  3. Aaron Ballman Says:

    calloc is a rather strange choice — you’re filling the entire buffer’s contents anyways, so you could skip the initialization to zero and save some cycles. Also, if you’re using the newer SDK, it’s preferred to use REALBuildStringWithEncoding (or the REALBuildString overload that assigns encoding) instead of separating the two calls. However, my recommendation is slightly different. Here’s how I’d do it (if you’re looking for speed, this reduces memory allocations, deallocations and copies):

    1) Ensure the same encodings like you’re doing
    2) Call REALGetStringContents on both strings to get a pointer and length for each buffer
    3) Call REALBuildStringWithEncoding( nil, lhsLength + rhsLength, lhsEncoding ) — this will allocate a buffer large enough to hold both strings, but not copy any data in.
    4) Call REALGetStringContents on the resulting string to get its void *
    5) Call memcpy to move the lhs and rhs strings into the resulting void * at their appropriate locations.

    It’s going to be quicker than what you were doing, but it comes with the caveat that step #3 is technically undocumented (though I doubt it’ll change since it’s worked this way for about 10 years now).

  4. Joe Ranieri Says:

    Is your commenting about it count as documentation? :-P

  5. Aaron Ballman Says:

    Never has in the past, so I don’t know why it would start now. ;-) Of course, that doesn’t stop people from assuming my word is law. :-P

Leave a Reply