If a class or structure is changed the "xdr" method or g_xdr_ function for the new version should still be able to read old data files. The function
provides a simple version control mechanism.bool_t g_xdr_version(XDR *xdrp, int *ver)
When the function is called for writing the current version number (1 in the Scene and Chain examples above) is written. If the function is called for reading it reads in the version and compares it to the current version which was given as the second parameter. If the current version is lower then the version number read the function fails and returns FALSE -- in this case somebody else has written the data with a newer version of the method/function and the current version is not able to handle the data. Therefore ALWAYS call g_xdr_version before any other XDR function
or you get into trouble when you have to change the class or structure.
Look at the "xdr" method on class Suprop which is called in the Scene "xdr" method above via the g_xdr_instance call on &self->suprop:
The old version of class Suprop just contained the suprop_dev and grid_patch variables, later the linecolor and an enabled flag were added, therefore the lines marked with the ``new version'' comment were added to the method.SUPROP *suprop_xdr(XDR *xdrp) { SUPROP *self; int ver = 2; int grid_patch, enabled; self = (SUPROP *)START_METHOD(G_INSTANCE); ASSURE(self, "", END_METHOD(NULL)); grid_patch = (self->grid_patch == G_GRID ? 1 : 0); enabled = (int)self->enabled; /* new version */ if(!g_xdr_version(xdrp, &ver) || !g_xdr_suprop_dev(xdrp, &self->suprop_dev) || ! xdr_int(xdrp, &grid_patch)) END_METHOD(NULL); /* new version -> */ if(ver == 1) { g_vec3_set(self->linecolor, 1.0, 1.0, 1.0); enabled = (int)spefDefault; } else if(! xdr_int(xdrp, &enabled) || !g_xdr_vec3(xdrp, self->linecolor)) END_METHOD(NULL); /* <- new version */ self->grid_patch = (grid_patch ? G_GRID : G_PATCH); self->enabled = (SUPROP_ENABLE_FLAG)enabled; /* new version */ END_METHOD(self); }
If the method is used for writing or for reading a new version the else part is used. If an old version is read the if part is used, in this case the new variables have to be initialized to default values.
The enabled variable in copied to a local int variable (and back, this has no effect if the method is called for writing) because it is an enum and there is no special function for handling enums. The grid_patch flag is converted from G_GRID/G_PATCH to 1/0 (and back, again this has no effect on writing) because these defines were changed several times, otherwise for each change a new version of this routine would have been required.
Copyright © by the Sonderforschungsbereich 256 at the Institut für Angewandte Mathematik, Universität Bonn.