Re: A use case for fromStringz
Why not: string getNameOld() { static char[256] name; cDispatch(name.ptr, kGetProductName); return to!string(name.ptr); }
Re: A use case for fromStringz
Actually, this still suffers from the problem when the returned char* doesn't have a null terminator. It really sucks when C code does that, and I've just experienced that. There is a solution though: Since we can detect the length of the D array passed into `fromStringz`, we can do the job of to!string ourselves and check for a null terminator. If one isn't found, we return a string of length 0. Here's an updated version which doesn't suffer from the missing null terminator problem: string fromStringz(T)(T value) { static if (isArray!T) { if (value is null || value.length == 0) { return ""; } auto nullPos = value.indexOf("\0"); if (nullPos == -1) return ""; return to!string(value[0..nullPos]); } else { return to!string(value); } }
Re: A use case for fromStringz
On 3/31/11, Jesse Phillips wrote: > Why not: > > string getNameOld() > { > static char[256] name; > cDispatch(name.ptr, kGetProductName); > return to!string(name.ptr); > } > Nice catch! But see my second reply. If a null terminator is missing and we know we're operating on a D array (which has a length), then it could be best to check for a null terminator. If there isn't one it is highly likely that the array contains garbage.
Re: A use case for fromStringz
Andrej Mitrovic Wrote: > Actually, this still suffers from the problem when the returned char* > doesn't have a null terminator. It really sucks when C code does that, > and I've just experienced that. There is a solution though: > > Since we can detect the length of the D array passed into > `fromStringz`, we can do the job of to!string ourselves and check for > a null terminator. If one isn't found, we return a string of length 0. > Here's an updated version which doesn't suffer from the missing null > terminator problem: I do not know the proper action if the string you receive is garbage. Shouldn't it throw an exception since it did not receive a string? This to me seems like a validation issue. If the functions you are calling are expected to return improper data _you_ must validate what your receive, that includes running it through utf validation.
Re: A use case for fromStringz
Oh I'm not trying to get this into Phobos, I just needed the function so I wrote it and sharing it here. Maybe it should throw. For my purposes I don't need it to throw. :)
Re: A use case for fromStringz
On 3/31/11 11:18 PM, Andrej Mitrovic wrote: Actually, this still suffers from the problem when the returned char* doesn't have a null terminator. It really sucks when C code does that, and I've just experienced that. There is a solution though: In those cases, doesn't the function return the length of the filled data or something like that? Since we can detect the length of the D array passed into `fromStringz`, we can do the job of to!string ourselves and check for a null terminator. If one isn't found, we return a string of length 0. Here's an updated version which doesn't suffer from the missing null terminator problem: string fromStringz(T)(T value) { static if (isArray!T) { if (value is null || value.length == 0) { return ""; } auto nullPos = value.indexOf("\0"); if (nullPos == -1) return ""; return to!string(value[0..nullPos]); } else { return to!string(value); } } -- /Jacob Carlborg
Re: A use case for fromStringz
On 4/1/11, Jacob Carlborg wrote: > In those cases, doesn't the function return the length of the filled > data or something like that? I know what you mean. I would expect a C function to do just that, but in this case it does not. Its lame but I have to deal with it.
Re: A use case for fromStringz
Hmm.. now I need a function that converts a wchar* to a wchar[] or wstring. There doesn't seem to be anything in Phobos for this type of conversion. Or maybe I haven't looked hard enough? I don't know whether this is safe since I'm not sure how the null terminator is represented in utf16, but it does seem to work ok from a few test cases: wstring fromWStringz(wchar* value) { if (value is null) return ""; auto oldPos = value; uint nullPos; while (*value++ != '\0') { nullPos++; } if (nullPos == 0) return ""; return to!wstring(oldPos[0..nullPos]); } I thought we would pay more attention to interfacing with C code. Since D is supposed to work side-by-side with C, we should have more functions that convert common data types between the two languages.
Re: A use case for fromStringz
Microsoft has some of the most ridiculous functions. This one (GetEnvironmentStrings) returns a pointer to a block of null-terminated strings, with no information on the count of strings returned. Each string ends with a null-terminator, standard stuff. But only when you find two null terminators in succession you'll know that you've reached the end of the entire block of strings. So from some example code I've seen, people usually create a count variable and increment it for every null terminator in the block until they find a double null terminator. And then they have to loop all over again when constructing a list of strings. Talk about inefficient designs.. There's also a wchar* edition of this function, I don't want to even touch it. Here's what the example code looks like: char *l_EnvStr; l_EnvStr = GetEnvironmentStrings(); LPTSTR l_str = l_EnvStr; int count = 0; while (true) { if (*l_str == 0) break; while (*l_str != 0) l_str++; l_str++; count++; } for (int i = 0; i < count; i++) { printf("%s\n", l_EnvStr); while(*l_EnvStr != '\0') l_EnvStr++; l_EnvStr++; } FreeEnvironmentStrings(l_EnvStr); I wonder.. in all these years.. have they ever thought about using a convention in C where the length is embedded as a 32/64bit value at the pointed location of a pointer, followed by the array contents? I mean something like the following (I'm pseudocoding here, this is not valid C code, and it's 7 AM.): // allocate memory for the length field + character count char* mystring = malloc(sizeof(size_t) + sizeof(char)*length); *(cast(size_t*)mystring) = length; // embed the length // call a function expecting a char* printString(mystring); // void printString(char* string) { size_t length = *(cast(size_t*)string); (cast(size_t*)string)++; // skip count to reach first char // now print all chars one by one for (size_t i; i < length; i++) { printChar(*string++); } } Well, they can always use an extra parameter in a function that has the length, but it seems many people are too lazy to even do that. I guess C programmers just *love* their nulls. :p
Re: A use case for fromStringz
On 04/16/2011 06:55 AM, Andrej Mitrovic wrote: I wonder.. in all these years.. have they ever thought about using a convention in C where the length is embedded as a 32/64bit value at the pointed location of a pointer, followed by the array contents? Sometimes called "Pascal strings" (actually, IIRC, the length is at the address /before/ the one pointed by the pointer). One of the important diffs between C & Pascal from the practical pov. Actually, it's the same diff as C arrays vs true arrays like D's. Denis -- _ vita es estrany spir.wikidot.com
Re: A use case for fromStringz
Yeah I basically took the idea from the existing D implementation. Although D's arrays are a struct with a length and a pointer (I think so).