Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Due to spam on this forum, all posts now need moderator approval.
Entire forum
➜ SMAUG
➜ Compiling the server
➜ How to convert SMAUG to C++
|
How to convert SMAUG to C++
|
It is now over 60 days since the last post. This thread is closed.
Refresh page
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Wed 21 Jan 2004 01:01 AM (UTC) Amended on Tue 01 Aug 2006 11:48 PM (UTC) by Nick Gammon
|
| Message
| As part of another thread (programming with the Standard Template Library (STL) ) I wanted to show how you could use STL in SMAUG.
However the initial problem was that SMAUG is written in C, not C++.
I have converted it to C++, however it was a tedious process - to say the least.
One major problem was the use of the word "class" (being the player's class) in many places in the source, however "class" is a reserved word in C++. Also, to a lesser extent, the use of the word "new".
This meant finding and replacing each word "class", however not inside comments or quoted strings, to "mudclass".
There were also other fixups to do with stricter checking of the "const" keyword, and various other fiddly things.
To save anyone else the trouble of doing it, the chanages are in this file:
http://www.gammon.com.au/files/smaug/smaug1.4a_mxp.cpp_diffs.txt.gz
This is a gzipped file of differences (context diffs), between the C source and the C++ source, for the version:
http://www.gammon.com.au/files/smaug/smaug1.4a_mxp.tgz
In other words, the Unix source of version 1.4a *with* the MXP patches.
If you try to apply it to the non-MXP version it should work, except that some patch hunks will fail, particularly in comm.c.
To apply, download the patch file, unzip it, and copy it to your "src" directory. Then type:
patch < smaug1.4a_mxp.cpp_diffs.txt
You should then be able to "make clean" and then "make".
In order to keep the same file names for patching purposes the C++ source files still end in .c, however once you have patched them you may wish to rename them as .cpp files.
Why convert?
Once you have SMAUG in C++ you can use STL which makes handling lists and vectors much easier, and gives you the "string" class which lets you handle string data without having to "malloc" and "free" all the time, and worry about strings overflowing their defined lengths.
However the converted version presented here is simply exactly the same code with the minimal modifications made to make it compile as a C++ project. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Reply #1 on Wed 21 Jan 2004 08:22 PM (UTC) |
| Message
| Just to clarify my earlier post - the patches given above convert SMAUG so it will *compile* under the C++ compiler (g++) however they are not a full conversion to C++.
To do that properly, you would need to convert "malloc" to "new" whenever allocating new things (like player data, object data, room data, and so on). The reason this is important is that "new" will call the constructor for any class contained within things.
For instance, if you amended the "char_data" structure to include an STL "string" type it would not be properly constructed by malloc.
eg.
struct char_data
{
CHAR_DATA * next;
CHAR_DATA * prev;
CHAR_DATA * next_in_room;
CHAR_DATA * prev_in_room;
CHAR_DATA * master;
CHAR_DATA * leader;
FIGHT_DATA * fighting;
...
string some_string_data_here;
}
Here is an example from db.c:
CREATE( mob, CHAR_DATA, 1 );
clear_char( mob );
Instead of doing that you would do something like this instead:
And, put all the "clear_char" stuff into the constructor for that object.
Then, put the code for "free_char" into the destructor for it.
Also, of course, instead of using DISPOSE to get rid of a character you would "delete" it. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Reply #2 on Thu 12 Feb 2004 02:49 AM (UTC) Amended on Thu 12 Feb 2004 02:50 AM (UTC) by Nick Gammon
|
| Message
| I notice that some of the changes I suggested in the patch are in fact wrong. Strangely, they made it through the compile-and-test phase.
Specifically in a number of places (20 or so) I had an error when compiling this in C++;
word = feof( fp ) ? "End" : fread_word( fp );
The error was:
invalid conversion from `const char*' to `char*'
This was because "word" was defined as "char * word" and "End" is a const char *.
So, I changed it to:
if (feof (fp))
strcpy (word, "End");
else
word = fread_word( fp );
However while this compiles, it is wrong. The field "word" is declared like this:
The problem here is that my change does a strcpy to a pointer that is not initialised. So, the workaround is to do this:
word = feof(fp) ? (char *) "End" : fread_word(fp);
This is not quite as neat, as it is casting a literal to a char, which is not very good, but that is better than copying into uninitialised memory.
I think the reason I got away with it, is that in fread_word it returns a pointer to a static buffer, a technique I am not wild about:
char *fread_word( FILE *fp )
{
static char word[MAX_INPUT_LENGTH];
....
return word;
}
So, what would happen is that, provided there was at least one entry in each file (eg. the class file) then the "word" field would be filled in to point to the static buffer "word" inside fread_word, and thus was allocated from then on.
It is really a mess, and shows how obscure bugs can creep in and hit you months after you have made them.
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|
| Posted by
| Samson
USA (683 posts) Bio
|
| Date
| Reply #3 on Thu 12 Feb 2004 07:23 AM (UTC) |
| Message
| Interesting to note on the char *word thing, if you change the declaration of that to:
const char *word;
it works just as well and doesn't require any further changes. I ran into the same when I undertook the pain of making AFKMud compile in g++. | | Top |
|
| Posted by
| Nick Gammon
Australia (23,173 posts) Bio
Forum Administrator |
| Date
| Reply #4 on Thu 12 Feb 2004 10:16 AM (UTC) Amended on Thu 12 Feb 2004 10:18 AM (UTC) by Nick Gammon
|
| Message
| You are right, and that is a better solution, as it doesn't involve a cast.
I always get confused with "const", and in this case I assumed that because we were putting something *into* word, it couldn't be const.
However there is a difference between a const pointer and const 'what it points to'. In this case we can change the *pointer* 'word', but not what it points to.
For example, if we had wanted to do this:
word [0] = toupper ( word [0] );
... then that would not have worked.
I have written a little program to illustrate the differences, in case anyone is keen to know what I am talking about ...
int main (void)
{
char * a = "alpha"; // declare a as pointer to char
const char * b = "bravo"; // declare b as pointer to const char
char * const c = "charlie"; // declare c as const pointer to char
const char * const d = "delta"; // declare d as const pointer to const char
a = "Nick"; // change the pointer
a [0] = 'x'; // change what it points to
b = "Nick"; // change the pointer
b [0] = 'x'; // ERROR: assignment of read-only location
c = "Nick"; // ERROR: assignment of read-only variable `c'
c [0] = 'x'; // change what it points to
d = "Nick"; // ERROR: assignment of read-only variable `d'
d [0] = 'x'; // ERROR: assignment of read-only location
} // end of main
In practice, this program is not good programming, because the attempts to change the variable are actually changing a literal, but the important thing is to illustrate the compiler errors on the various declarations of const.
The four declarations (a, b, c, d) are the four different ways you can have "const" with a pointer.
It is interesting to use the program "cdecl" if you have it on your system.
For instance, you can "explain" a declaration, like this:
$ cdecl
Type `help' or `?' for help
cdecl> explain const char * const d
declare d as const pointer to const char
This explains what something does, or as the help puts it:
It also works the other way, so you can type:
$ cdecl
Type `help' or `?' for help
cdecl> declare d as const pointer to const char
const char * const d
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
13,832 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top