wmarkham
Level: Master Delver
Rank Points: 125
Registered: 12-06-2004
IP: Logged
|
Re: Caravel DROD source code (+2)
Here are stylistic changes that might ease the efforts needed in order to port the code to a new architecture:
- I use "#ifdef WHM_HAVE_FMOD" around any FMOD-specific calls. This replaces "#ifdef __sgi" that is already there. The benefit is that it is not specific to any platform, so that different ports can include/exclude the functionality very simply, without additional modifications within the code that calls FMOD.
- In the future, I may eliminate the dependency of my Sound.h header file on <fmod.h>. This has the minor benefit that different implementations of Sound.cpp become link-compatible. In other words, one could choose the with-fmod or the without-fmod version at link time. To take this one step further, one could define virtual functions in CSound for playing songs and effects, then provide different implementations for different underlying sound libraries. The single instance that is constructed and used could be selected at runtime.
- I use "#ifdef _MSC_VER" instead of "#ifdef WIN32" to detect platform differences that are related to the compiler or the runtime library. This eases porting to other compilers for Windows. As long as SDL supports it, it should be easy to compile a Windows executable with the g++ compiler. (using Cygwin or mingw libraries; I believe I compiled all the .cpp files like this at some point, but didn't bother to link it, due to the external dependencies)
- using enumerated types, inline functions, and function templates can eliminate many of the uses of preprocessor macros that appear within DROD headers, which can potentially conflict with names used in library header files. Admittedly, system headers should not be sensitive to most of the macros that are defined, and other libraries' headers will be similar across other platforms. I have been replacing these as I encounter them.
- use of namespaces would further prevent name conflicts with libraries. I haven't bothered to look into the changes needed, because they wouldn't have much benefit to me. I just thought I'd mention it for the sake of completeness, since it ties in with the above point.
- rewrite of DbPackedVars. I eliminated the return values from the SetVar member functions. I don't think that they are ever used. Casting a "void*" that refers to arbitrarily-aligned memory into a pointer to a specific type is undefined (non-portable) behavior. (except for char and unsigned char types) Internally, I simply copy raw memory into the storage for a return value, which is returned by value. Byte swapping might need to be performed here as well. (See a question I ask later...)
- I have been replacing the conditionally-compiled ("#ifdef __sgi") calls to "LittleToBig" functions with unconditionally-compiled "externalToInternal" and "internalToExternal" functions. On a little-endian machine, these do nothing; on a big-endian machine, they call the appropriate "LittleToBig" functions. The main benefit to porting efforts is that additional ports can simply provide the appropriate definition (by ensuring that the endianness is detected appropriately), without needing to change code in several places that calls the conversion functions. There is an additional benefit, I believe, of clarity. (the usage follows that of htonl, ntohl, etc.)
Here are other stylistic changes that I am imposing on my own code, which I also recommend for "general consumption", since they are simply good ideas:
- use std::auto_ptr to manage the lifetime of objects constructed through "new".
- use STL containers.
- more generally, use RAII ("Resource Aquisistion Is Initialization") to manage the acquisition and disposal of resources.
Finally, some more-or-less random questions about the code. If someone knowledgable about it can lend some insight, that would be great:
- In EditRoomScreen.cpp, why would this->nUndoSize ever be nonzero? I think one of the compilers that I've tried warned about a signed/unsigned comparison in the "if" statement in CEditRoomScreen::RoomChanging(), but it was not clear to me at the time what should cause the body of it to be executed.
- Clipboard.cpp appears to leak, in SetString(const WSTRING&).
- The handling of strings seems odd, to me. If I understand correctly, some effort has been taken to ensure that the in-memory representation of a string always matches (byte-for-byte) the external representation that is stored, e.g., in the database. Is there any reason not to simply convert to/from wstring for internal use? Or am I misunderstanding the situation?
- In DbRooms.cpp, near line 3660, does the c4_Bytes (it's named SettingsBytes) take ownership of the BYTE* that is used to construct it?
- the documentation for CDbMessageText indicates that the destructor will automatically "flush" (i.e., apply changes to the database). The code does not appear to do this. Which is supposed to be true?
- In CDbMessageText, if "Clear" is called, should bIsLoaded perhaps get set to true?
- Why are the o-layer and t-layer arrays in CDbRoom allocated with 1 extra char?
- when "__sgi" is defined, there are some commented-out calls to "LittleToBig" in CDbPackedVars. These appear to be necessary to me. Why are they commented out? Have I been misunderstanding the purpose of LittleToBig?
|