I'm back from the beach with the computer, so I can take a look at this

Sunburned despite spending the majority of the time inside reading Steve Jobs's biography

Okay, there are a number of issues here.
Scope
In C (and derived languages), there is the notion of scope within which variables exist.
Any local variable (defined inside a function) only exists within its scope, which is the compound block, delimited by { and }, the largest of which is the function's body.
What this means is that you cannot return a pointer to a local array and expect it to be valid memory outside the function. In this case, this applies to your char str[100]; and char str2[100].
So there are a few ways to work around this, to return a string from a a function:
1. You return it in a parameter, declared as char *, by doing a strcpy() into that char * parameter
2. You return newly allocated memory (CopyString), but it needs to be deleted by the caller
3. You return a pointer to memory allocated on the heap: a global, a static local variable, or a class member to which you have access, and is guaranteed to be alive. For example, textLogo. Especially for globals or statics, this can be dangerous with concurrency, if any kind of threading or recursion is going on, because any time the function is ran, the same variable is being used.
PrintBuf Usage
PrintBuf's first two arguments are the memory (buffer) in which to output the result, and its allocated length (the maximum number of bytes that will be written).
You were using strlen(str), which is wrong, as that tries to compute the length of the string, searching for a null ('\0') character in it. while you have not even initialized the str variable yet.
So the proper way is to use sizeof:
PrintBuf(str, sizeof(str), textLogo);
Substrings in C
Now you have:
Code: Select all
if (returnMain == true) { rez = textLogo[0];/*str[0];*/ }
else
{
int i;
char str2[100];
for(i = 1; i < strlen(str); i++)
{
str2[i-1] = str[i];
}
rez = str2;
}
splash.ec:372:39: warning: incompatible expression this.textLogo[0] (byte); expected char *
Here you are mixing indirection levels, char and char *. textLogo[0] refers to the first character of the string, as opposed to the string itself (or in your case what you were hoping for, a new string that only contained the first character. char and char * are two fundamentally different data types, the former being a byte, the latter being a pointer.
In the else clause, you try to form a new string that starts at the 2nd character. In C, this is extremely easy to do (much easier than a substring at the start of the string as above!) with pointer arithmetic, without having to copy anything, you simply do 'textLogo + 1'. Because C strings works with null-termination, i.e. the string ends when a null character is found, this is possible. A few things to note about your original else clause, it would need to go one character further to copy said null character: i < strlen(str) + 1. Also, because each time you invoke strlen() it has to search the entire string, a better way would be:
for(i = 1; str; i++)
This will loop until str is the null character itself, at the end of the string. (But you would still need to add the null character at the end: str2 = 0;
Another OK approach would be to compute the strlen() before the for, e.g. int len = strlen(str); and then use i < len + 1
Again in this else clause, you made the scope mistake of assigning str2, which is only valid inside the else, to a variable declared outside (rez).
So here is some code that does work:
Using a static local array:
Code: Select all
String TextLogoPrepare(bool returnMain)
{
if(returnMain)
{
static char str[2];
str[0] = textLogo[0];
str[1] = 0;
return str;
}
else
return textLogo + 1;
}
Code: Select all
String TextLogoPrepare(bool returnMain)
{
if(returnMain)
return PrintString((char)textLogo[0]); // (char) is needed here, otherwise E gets printed as 69 ( Bug http://ecere.com/mantis/view.php?id=681 )
else
return PrintString(textLogo+1);
}
Code: Select all
String TextLogoPrepare(bool returnMain)
{
if(returnMain)
{
static char str[2];
PrintBuf(str, sizeof(str), (char)textLogo[0]);
return str;
}
else
return textLogo + 1;
}
Code: Select all
String TextLogoPrepare(bool returnMain)
{
char * rez;
char str[100];
if(returnMain)
{
str[0] = textLogo[0];
str[1] = 0;
rez = str;
}
else
rez = textLogo + 1;
return CopyString(rez);
}
Code: Select all
char * TextLogoPrepare(bool returnMain, char * output)
{
if(returnMain)
{
output[0] = textLogo[0];
output[1] = 0;
}
else
strcpy(output, textLogo + 1);
return output;
}
And add s as an argument to calls to TextLogoPrepare, e.g.:
TextLogoPrepare(false, s);
For such a scenario, I would normally prefer the last solution.
Class member/property initialization
Another thing I've noticed, at the top of the program you were trying to assign initial values to the class properties, e.g.:
String textLogo = "ECERE";
eC does not yet support this syntax to both declare a class member and initialize it together at the same time, although I hope to make it work in the future. It can be done however, as you had it commented out, in two parts:
String textLogo; textLogo = "ECERE";
The problem with this, is that within a class, data members are resolved before properties.
Because textLogo is both a data member and a property of the class, here the data member takes precedence, and so "ECERE" gets assigned to the data member textLogo. That would also obviously be what happens if we had the String textLogo = "ECERE"; syntax, because that is the member you are declaring!!
Now the problem with this here, is that when using the property, you assign a copy of the string, and delete it upon destruction. Deleting a string literal constant will crash.
( I just saw your "Works only if there is no default value set for it" comments )
There are two ways to work around this:
1. String textLogo; textLogo = CopyString("ECERE"); // Since you know you have to make a copy, you can do it on the initialization
2. String textLogo; property::textLogo = "ECERE"; // This forces the 'property' textLogo to be invoked, instead of being a simple data member assignment. The textLogo property will call CopyString and assign the new string to the textLogo data member as usual
Conclusion
C strings are based and presented as their low level pointer to characters implementation, and it can be quite a challenge to grasp them. Sadly, eC does not yet do enough to simplify this and make life easy for non-C programmers. We hope to have a nice String class in the future that will change this. Until then, I hope you can find consolation in the fact that you are gaining C and system programming skills

Cheers,
Jerome