Could somebody tell me what is the proper way to convert a NSString* to an ANTLR3 string (used in C) ?
EDIT: this seems to work
char buf[255];
if ( YES == [myNSString getCString:buf maxLength:255 encoding:NSStringEncodingConversionAllowLossy] )
{
pANTLR3_UINT8 theExpression = (pANTLR3_UINT8*)buf;
...
Assuming that you want the complete string without loss, you can use the following code:
NSString *myString = ...;
NSUInteger len = [myString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
char *buf = malloc(len + 1);
if ([myString getCString:buf maxLength:(len + 1) encoding:NSUTF8StringEncoding]) {
// pANTLR3_UINT8 is equivalent to ANTLR3_UINT8*
pANTLR3_UINT8 theExpression = (pANTLR3_UINT8) buf;
}
free(buf);
Of course you can use another encoding if character loss is not important.
Related
I use a script with the SDK Gracenote (GNSDK) for audio recognition of a file (fingerprint).
The script works correctly, I just want to escape the double quotes in a variable.
I found this function:
void str_replace(char *target, const char *needle, const char *replacement)
{
char buffer[1024] = { 0 };
char *insert_point = &buffer[0];
const char *tmp = target;
size_t needle_len = strlen(needle);
size_t repl_len = strlen(replacement);
while (1) {
const char *p = strstr(tmp, needle);
// walked past last occurrence of needle; copy remaining part
if (p == NULL) {
strcpy(insert_point, tmp);
break;
}
// copy part before needle
memcpy(insert_point, tmp, p - tmp);
insert_point += p - tmp;
// copy replacement string
memcpy(insert_point, replacement, repl_len);
insert_point += repl_len;
// adjust pointers, move on
tmp = p + needle_len;
}
// write altered string back to target
strcpy(target, buffer);
}
I want to use here, I have the impression that the variable type is different but I do not know how (gnsdk_cstr_t at the start and char in function str_replace). Here is the part of the code or want to escape the double quotes of "VALUE" :
static void
_display_track_gdo(
gnsdk_gdo_handle_t track_gdo
)
{
gnsdk_error_t error = GNSDK_SUCCESS;
gnsdk_gdo_handle_t title_gdo = GNSDK_NULL;
gnsdk_cstr_t value = GNSDK_NULL;
/* Track Title */
error = gnsdk_manager_gdo_child_get(track_gdo, GNSDK_GDO_CHILD_TITLE_OFFICIAL, 1, &title_gdo);
if (GNSDK_SUCCESS == error)
{
error = gnsdk_manager_gdo_value_get(title_gdo, GNSDK_GDO_VALUE_DISPLAY, 1, &value);
if (GNSDK_SUCCESS == error)
{
char s[1024] = value;
str_replace(s, "\"", "\\\"");
printf("\"%s\": \"%s\"", "track", s);
}
else
{
_display_last_error(__LINE__);
}
gnsdk_manager_gdo_release(title_gdo);
}
else
{
_display_last_error(__LINE__);
}
}
During compilation , the error is:
main.c: In function '_display_track_gdo':
main.c:756:4: error: invalid initializer
char s[1024] = value;
How can I solve my problem? Or use another method to escape the double quotes ?
Thank you in advance.
Cordially.
PS: I do not know much the langage C, so it is possible that I make mistakes in how to code .
value is of type gnsdk_cstr_t, you cannot use it to initialize a char array. Use the API the library provides, likely you can copy or convert it into a char array. But you cannot assign to an array.
Looking the source of the library, in fact, gnsdk_cstr_t is defined as typedef const gnsdk_char_t* gnsdk_cstr_t;, and gnsdk_char_t is defined as typedef char gnsdk_char_t;, this means, gnsdk_cstr_t is the same as null-terminated strings, can just call standard string functions on it:
char s[1024];
strcpy(s, value);
reference:
https://github.com/tingled/jambox/blob/master/rpi_gnsdk/include/gnsdk/gnsdk_defines.h
I am getting a CFStringRef out of a CFDictionaryRef using CFDictionaryGetValue.
I've been trying to convert the CFStringRef to a char* using CFStringGetCString or CFStringGetCStringPtr and they either return a NULL or it crashes.
Is there a way to do this? How?
Thank you.
EDIT: sample code:
SecStaticCodeRef staticCode;
CFDictionaryRef information;
SecCSFlags flags = kSecCSInternalInformation
| kSecCSSigningInformation
| kSecCSRequirementInformation
| kSecCSInternalInformation;
CFURLRef pathURL = NULL;
CFStringRef pathStr = NULL;
CFStringRef uniqueid;
char* str = NULL;
CFIndex length;
pathStr = CFStringCreateWithCString(kCFAllocatorDefault,
filename, kCFStringEncodingUTF8);
pathURL = CFURLCreateWithString(kCFAllocatorDefault, pathStr, NULL);
SecStaticCodeCreateWithPath(pathURL, kSecCSDefaultFlags, &staticCode);
SecCodeCopySigningInformation(staticCode, flags, &information);
uniqueid = (CFStringRef) CFDictionaryGetValue(information, kSecCodeInfoUnique);
// how do I convert it here to char *?
length = CFStringGetLength(uniqueid);
str = (char *)malloc( length + 1 );
CFStringGetCString(uniqueid, str, length, kCFStringEncodingUTF8);
printf("hash of signature is %s\n", str);
CFRelease(information);
CFRelease(staticCode);
From the Chapter 17 example code in iOS:PTL.
char * MYCFStringCopyUTF8String(CFStringRef aString) {
if (aString == NULL) {
return NULL;
}
CFIndex length = CFStringGetLength(aString);
CFIndex maxSize =
CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buffer = (char *)malloc(maxSize);
if (CFStringGetCString(aString, buffer, maxSize,
kCFStringEncodingUTF8)) {
return buffer;
}
free(buffer); // If we failed
return NULL;
}
The resulting buffer must always be freed (which is why Copy is in the name). The linked example code also has a slightly faster version that uses a buffer you provide.
Another answer:
const char *cs = CFStringGetCStringPtr( cfString, kCFStringEncodingMacRoman ) ;
puts( cs ) ; // works
I can't find the reason why kCFStringEncodingUTF8 gives NULL, but kCFStringEncodingMacRoman seems to work fine.
There is an another one line solution for the same problem:
char * myCString = [(__bridge NSString *)myCfstring UTF8String];
Happy Coding :)
why not simply: printf("%s\n", CFStringGetCStringPtr(uniqueid, kCFStringEncodingUTF8));?
very simple:
CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
const char *path = CFStringGetCStringPtr(cfStrRef, encodingMethod);
From the String Programming Guide for Core Foundation Documentation. Here is how you get the Contents of a CFStringRef as a C String.
I have made a modification to it as so, this should do what you are looking for.
#include <CoreFoundation/CoreFoundation.h>
CFStringRef str;
//Removed CFRange
const char *bytes; //This is where the conversion result will end up.
str = CFSTR("You Want this String!\n"); //Changed this part
bytes = CFStringGetCStringPtr(str, kCFStringEncodingMacRoman);
if (bytes == NULL)
{
//Adding in getting the size
CFIndex stringLengthIndex = CFStringGetLength(str);
//Converted index (signed long ) to int
char localBuffer[(int) stringLengthIndex];
Boolean success;
success = CFStringGetCString(str, localBuffer, stringLengthIndex, kCFStringEncodingMacRoman);
}
//At this point the "bytes" variable should contain your C string copied from the provided CFStringRef
I have to use fputs to print something and fputs take "const char *str" to print out.
I have 3 strings to print(I don't care if it's strings or char[]) as str.
I dont know the right way to do it. I used 3 string and I added them to one but is not working. I also tried to convert string to char but nothing is working!
Any recommendations?
struct passwd* user_info = getpwuid(getuid());
struct utsname uts;
uname(&uts);
I want my char const *str = user_info->pw_name + '#' + uts.nodename
You need to create a new string for that. I have no idea why you need the fputs restriction, but I assume that even if you can't/don't want to use fprintf, you still have snprintf available. You'd then do it like this:
char *new_str;
int new_length;
// Determine how much space we'll need.
new_length = snprintf(NULL, "%s#%s", user_info->pw_name, uts.nodename);
if (new_length < 0) {
// Handle error here.
}
// Need to allocate one more character for the NULL termination.
new_str = malloc(new_length + 1);
// Write new string.
snprintf(new_str, "%s#%s", user_info->pw_name, uts.nodename);
A possible solution:
/* 1 for '#' and 1 for terminating NULL */
int size = strlen(user_info->pw_name) + strlen(uts.nodename) + 2;
char* s = malloc(size);
strcpy(s, user_info->pw_name);
strcat(s, "#");
strcat(s, uts.nodename);
/* Free when done. */
free(s);
EDIT:
If C++ you can use std::string:
std::string s(user_info->pw_name);
s += "#";
s += uts.nodename;
// s.c_str(); this will return const char* to the string.
I cannot believe there is no API to do this in GLib, for now I have only found people doing their own conversion, like here and here (function named "decode"). I would really like to find a way to do this in a simple GLib call, but if there is no way, the above methods don't work for me because the former is C++ (I'm using C/GObject) and the latter doesn't seem to work perfectly (I'm having problems with the length of the result).
TIA
As mentioned, this is a bit uncommon. If you have a short enough hex string, you can prefix it with 0x and use strtoll(). But for arbitrary length strings, here is a C function:
char *hex_to_string(const char *input)
{
char a;
size_t i, len;
char *retval = NULL;
if (!input) return NULL;
if((len = strlen(input)) & 1) return NULL;
retval = (char*) malloc(len >> 1);
for ( i = 0; i < len; i ++)
{
a = toupper(input[i]);
if (!isxdigit(a)) break;
if (isdigit(a)) a -= '0';
else a = a - 'A' + '\10';
if (i & 1) retval[i >> 1] |= a;
else retval[i >> 1] = a<<4;
}
if (i < len)
{
free(retval);
retval = NULL;
}
return retval;
}
I'm no 100% sure what you mean by "hexadecimal string" but may be this thread will be of some help.
As part of learning C, I wrote the following code to combine directory name with file name. Eg: combine("/home/user", "filename") will result in /home/user/filename. This function is expected work across platforms (atleast on all popular linux distributions and windows 32 and 64bit).
Here is the code.
const char* combine(const char* path1, const char* path2)
{
if(path1 == NULL && path2 == NULL) {
return NULL;
}
if(path2 == NULL || strlen(path2) == 0) return path1;
if(path1 == NULL || strlen(path1) == 0) return path2;
char* directory_separator = "";
#ifdef WIN32
directory_separator = "\\";
#else
directory_separator = "/";
#endif
char p1[strlen(path1)]; // (1)
strcpy(p1, path1); // (2)
char *last_char = &p1[strlen(path1) - 1]; // (3)
char *combined = malloc(strlen(path1) + 1 + strlen(path2));
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(combined, path1);
if(append_directory_separator)
strcat(combined, directory_separator);
strcat(combined, path2);
return combined;
}
I have the following questions regarding the above code.
Consider the lines numbered 1,2,3. All those 3 lines are for getting the last element from the string. It looks like I am writing more code for such a small thing. What is the correct method to get the last element from the char* string.
To return the result, I am allocating a new string using malloc. I am not sure this is the right way to do this. Is caller expected to free the result? How can I indicate the caller that he has to free the result? Is there a less error prone method available?
How do you rate the code (Poor, Average, Good)? What are the areas that can be imrpoved?
Any help would be great.
Edit
Fixed all the issues discussed and implemented the changes suggested. Here is the updated code.
void combine(char* destination, const char* path1, const char* path2)
{
if(path1 == NULL && path2 == NULL) {
strcpy(destination, "");;
}
else if(path2 == NULL || strlen(path2) == 0) {
strcpy(destination, path1);
}
else if(path1 == NULL || strlen(path1) == 0) {
strcpy(destination, path2);
}
else {
char directory_separator[] = "/";
#ifdef WIN32
directory_separator[0] = '\\';
#endif
const char *last_char = path1;
while(*last_char != '\0')
last_char++;
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(destination, path1);
if(append_directory_separator)
strcat(destination, directory_separator);
strcat(destination, path2);
}
}
In the new version, caller has to allocate enough buffer and send to combine method. This avoids the use of malloc and free issue. Here is the usage
int main(int argc, char **argv)
{
const char *d = "/usr/bin";
const char* f = "filename.txt";
char result[strlen(d) + strlen(f) + 2];
combine(result, d, f);
printf("%s\n", result);
return 0;
}
Any suggestions for more improvements?
And there is a memory leak:
const char *one = combine("foo", "file");
const char *two = combine("bar", "");
//...
free(one); // needed
free(two); // disaster!
Edit: Your new code looks better. Some minor stylistic changes:
Double semi-colon ;; in line 4.
In line 6, replace strlen(path2) == 0 with path2[0] == '\0'' or just !path2[0].
Similarly in line 9.
Remove loop determining last_char, and use const char last_char = path1[strlen(path1) - 1];
Change if(append_directory_separator) to if(last_char != directory_separator[0]). And so you don't need the variable append_directory_separator any more.
Have your function also return destination, similar to strcpy(dst, src), which returns dst.
Edit: And your loop for last_char has a bug: it always returns the end of path1, and so you could end up with a double slash // in your answer. (But Unix will treat this as a single slash, unless it is at the start). Anyway, my suggestion fixes this--which I see is quite similar to jdmichal's answer. And I see that you had this correct in your original code (which I admit I only glanced at--it was too complicated for my taste; your new code is much better).
And two more, slightly-more subjective, opinions:
I would use stpcpy(), to avoid the inefficiency of strcat(). (Easy to write your own, if need be.)
Some people have very strong opinions about strcat() and the like as being unsafe. However, I think your usage here is perfectly fine.
The only time you use last_char is in the comparision to check if the last character is a separator.
Why not replace it with this:
/* Retrieve the last character, and compare it to the directory separator character. */
char directory_separator = '\\';
if (path1[strlen(path1) - 1] == directory_separator)
{
append_directory_separator = 1;
}
If you want to account for the possibility of multiple character separators, you can use the following. But be sure when allocating the combined string to add strlen(directory_separator) instead of just 1.
/* First part is retrieving the address of the character which is
strlen(directory_separator) characters back from the end of the path1 string.
This can then be directly compared with the directory_separator string. */
char* directory_separator = "\\";
if (strcmp(&(path1[strlen(path1) - strlen(directory_separator)]), directory_separator))
{
append_directory_separator = 1;
}
The less error-prone method would be to have the user give you the destination buffer and its length, much the way strcpy works. This makes it clear that they must manage allocating and freeing the memory.
The process seems decent enough. I think there's just some specifics that can be worked on, mostly with doing things in a clunky way. But you are doing well, in that you can already recognize that happening and ask for help.
This is what I use:
#if defined(WIN32)
# define DIR_SEPARATOR '\\'
#else
# define DIR_SEPARATOR '/'
#endif
void combine(char *destination, const char *path1, const char *path2) {
if (path1 && *path1) {
auto len = strlen(path1);
strcpy(destination, path1);
if (destination[len - 1] == DIR_SEPARATOR) {
if (path2 && *path2) {
strcpy(destination + len, (*path2 == DIR_SEPARATOR) ? (path2 + 1) : path2);
}
}
else {
if (path2 && *path2) {
if (*path2 == DIR_SEPARATOR)
strcpy(destination + len, path2);
else {
destination[len] = DIR_SEPARATOR;
strcpy(destination + len + 1, path2);
}
}
}
}
else if (path2 && *path2)
strcpy(destination, path2);
else
destination[0] = '\0';
}
Maybe I'm a bit late to this, but I improved the updated code in a way, that it also works with something like this "/../".
/*
* Combine two paths into one. Note that the function
* will write to the specified buffer, which has to
* be allocated beforehand.
*
* #dst: The buffer to write to
* #pth1: Part one of the path
* #pth2: Part two of the path
*/
void joinpath(char *dst, const char *pth1, const char *pth2)
{
if(pth1 == NULL && pth2 == NULL) {
strcpy(dst, "");
}
else if(pth2 == NULL || strlen(pth2) == 0) {
strcpy(dst, pth1);
}
else if(pth1 == NULL || strlen(pth1) == 0) {
strcpy(dst, pth2);
}
else {
char directory_separator[] = "/";
#ifdef WIN32
directory_separator[0] = '\\';
#endif
const char *last_char = pth1;
while(*last_char != '\0')
last_char++;
int append_directory_separator = 0;
if(strcmp(last_char, directory_separator) != 0) {
append_directory_separator = 1;
}
strcpy(dst, pth1);
if(append_directory_separator)
strcat(dst, directory_separator);
strcat(dst, pth2);
}
char *rm, *fn;
int l;
while((rm = strstr (dst, "/../")) != NULL) {
for(fn = (rm - 1); fn >= dst; fn--) {
if(*fn == '/') {
l = strlen(rm + 4);
memcpy(fn + 1, rm + 4, l);
*(fn + len + 1) = 0;
break;
}
}
}
}
Just a little remark in order to improve your function:
Windows does support both '/' and '\\' separators in paths. So I should be able to perform the following call:
const char* path1 = "C:\\foo/bar";
const char* path2 = "here/is\\my/file.txt";
char destination [ MAX_PATH ];
combine ( destination, path1, path2 );
An idea when writing a multiplatform project could be to convert '\\' to '/' in any input path (from user input, loaded files...), then you will only have to deal with '/' characters.
Regards.
A quick glance shows:
you are using C++ comments (//) which is not standard C
you are declaring variables part way down the code - also not C. They should be defined at the start of the function.
your string p1 at #1 has 1 too many bytes written to it at #2 because strlen returns the length of a string and you need 1 more byte for the null terminator.
the malloc does not allocate enough memory - you need length of path1 + length of path2 + length of separator + null terminator.