Table Of Contents

Previous topic

Error handling and Debugging Example

Next topic

Hash Table Example

Generic Object System Example

This code example implements the shape, circle and rectangle classes as discussed in the Generic Object System topic. It can also be found in the speect/engine/examples/base/objsystem/ directory, and be compiled with the WANT_EXAMPLES build option.

shape.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#ifndef _SPCT_SHAPE_EXAMPLE_H__
#define _SPCT_SHAPE_EXAMPLE_H__


/**
 * @file shape.h
 * 2d shape class as an example of Speect's object-oriented
 * programming support.
 */


/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "speect.h"


/************************************************************************************/
/*                                                                                  */
/* Begin external c declaration                                                     */
/*                                                                                  */
/************************************************************************************/
S_BEGIN_C_DECLS


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @name Utility Macros
 * @{
 */


/**
 * @hideinitializer
 * Return the given #SShape child class object as a shape
 * object.
 *
 * @param SELF The given object.
 *
 * @return Given object as #SShape* type.
 *
 * @note This casting is not safety checked.
 */
#define S_SHAPE(SELF)    ((SShape *)(SELF))


/**
 * @}
 */


/************************************************************************************/
/*                                                                                  */
/* SShape definition                                                                */
/*                                                                                  */
/************************************************************************************/

/**
 * @ingroup SShape
 * A 2d shape class as an example of Speect's
 * object-oriented programming support.
 * @extends SObject
 */
typedef struct
{
    /**
     * @protected Inherit from #SObject.
     */
    SObject     obj;

    /**
     * @protected x-coordinate of rectangle top left hand position.
     */
    int x;

    /**
     * @protected y-coordinate of rectangle top left hand position.
     */
    int y;
} SShape;


/************************************************************************************/
/*                                                                                  */
/* SShapeClass definition                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * The abstract shape class structure.
 * @extends SObjectClass
 */
typedef struct
{
    /* Class members */
    /**
     * @protected Inherit from #SObjectClass.
     */
    SObjectClass  _inherit;

    /* Class methods */
    /**
     * @protected Move function pointer.
     * Move the given shape to the given coordinates.
     *
     * @param  self The shape to move.
     * @param  newx The new x coordinate.
     * @param  newy The new y coordinate.
     * @param  error Error code.
     */
    void  (* const move)   (SShape *self, int newx, int newy, s_erc *error);

    /**
     * @protected Area function pointer.
     * Calculate and return the given shape's area.
     *
     * @param self The shape to calculate the area of.
     * @param  error Error code.
     *
     * @return The given shape's area.
     */
    float (* const area)   (const SShape *self, s_erc *error);

} SShapeClass;


/************************************************************************************/
/*                                                                                  */
/* Function prototypes                                                              */
/*                                                                                  */
/************************************************************************************/

/**
 * Move the given shape to the given coordinates.
 * @public @memberof SShape
 *
 * @param self The shape to move.
 * @param newx The new x coordinate.
 * @param newy The new y coordinate.
 * @param error Error code.
 */
S_API void SShapeMove(SShape *self, int newx, int newy, s_erc *error);


/**
 * Calculate and return the given shape's area.
 * @public @memberof SShape
 *
 * @param self The shape to calculate the area of.
 * @param error Error code.
 *
 * @return The given shape's area.
 */
S_API float SShapeArea(const SShape *self, s_erc *error);


/**
 * Register the SShape class to the object system.
 * @private @memberof SShape
 *
 * @param error Error code.
 */
S_LOCAL void _s_shape_class_reg(s_erc *error);


/**
 * Free the SShape class from the object system.
 * @private @memberof SShape
 *
 * @param error Error code.
 */
S_LOCAL void _s_shape_class_free(s_erc *error);


/************************************************************************************/
/*                                                                                  */
/* End external c declaration                                                       */
/*                                                                                  */
/************************************************************************************/
S_END_C_DECLS


/**
 * @}
 * end documentation
 */

#endif /* _SPCT_SHAPE_EXAMPLE_H__ */

shape.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "shape.h"


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @hideinitializer
 * Call the given function method of the given #SShape,
 * see full description #S_SHAPE_CALL for usage.
 *
 * @param SELF The given #SShape*.
 * @param FUNC The function method of the given object to call.
 *
 * @note This casting is not safety checked.
 * @note Example usage:
 @verbatim
 S_SHAPE_CALL(self, func)(param1, param2, ..., paramN);
 @endverbatim
 * where @c param1, @c param2, ..., @c paramN are the parameters
 * passed to the object function @c func.
 */
#define S_SHAPE_CALL(SELF, FUNC)                    \
    ((SShapeClass *)S_OBJECT_CLS(SELF))->FUNC


/**
 * @hideinitializer
 * Test if the given function method of the given #SShape
 * can be called.
 *
 * @param SELF The given #SShape*.
 * @param FUNC The function method of the given object to check.
 *
 * @return #TRUE if function can be called, otherwise #FALSE.
 *
 * @note This casting is not safety checked.
 */
#define S_SHAPE_METH_VALID(SELF, FUNC)      \
    S_SHAPE_CALL(SELF, FUNC) ? TRUE : FALSE




/************************************************************************************/
/*                                                                                  */
/* Static variables                                                                 */
/*                                                                                  */
/************************************************************************************/

static SShapeClass ShapeClass; /* Shape class declaration. */


/************************************************************************************/
/*                                                                                  */
/* Function implementations                                                         */
/*                                                                                  */
/************************************************************************************/

S_API void SShapeMove(SShape *self, int newx, int newy, s_erc *error)
{
    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SShapeMove",
                  "Argument \"self\" is NULL");
        return;
    }

    if (!S_SHAPE_METH_VALID(self, move))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SShapeMove",
                  "Shape method \"move\" not implemented");
        return;
    }


    S_SHAPE_CALL(self, move)(self, newx, newy, error);
    S_CHK_ERR(error, S_CONTERR,
              "SShapeMove",
              "Call to class method \"move\" failed");
}


S_API float SShapeArea(const SShape *self, s_erc *error)
{
    float area;


    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SShapeArea",
                  "Argument \"self\" is NULL");
        return 0.0;
    }

    if (!S_SHAPE_METH_VALID(self, area))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SShapeArea",
                  "Shape method \"area\" not implemented");
        return 0.0;
    }

    area = S_SHAPE_CALL(self, area)(self, error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "SShapeArea",
                  "Call to class method \"area\" failed"))
        return 0.0;

    return area;
}


/************************************************************************************/
/*                                                                                  */
/* Class registration                                                               */
/*                                                                                  */
/************************************************************************************/

S_LOCAL void _s_shape_class_reg(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_reg(S_OBJECTCLASS(&ShapeClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_shape_class_reg",
              "Failed to register SShapeClass");
}


S_LOCAL void _s_shape_class_free(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_free(S_OBJECTCLASS(&ShapeClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_shape_class_free",
              "Failed to free SShapeClass");
}


/************************************************************************************/
/*                                                                                  */
/* Static class function implementations                                            */
/*                                                                                  */
/************************************************************************************/

static void InitShape(void *obj, s_erc *error)
{
    SShape *self = obj;


    S_CLR_ERR(error);
    self->x = 0;
    self->y = 0;
}


static void DisposeShape(void *obj, s_erc *error)
{
    S_CLR_ERR(error);
    SObjectDecRef(obj);
}


static void MoveShape(SShape *self, int newx, int newy, s_erc *error)
{
    S_CLR_ERR(error);
    self->x = newx;
    self->y = newy;
}


/************************************************************************************/
/*                                                                                  */
/* Class initialization                                                             */
/*                                                                                  */
/************************************************************************************/

static SShapeClass ShapeClass =
{
    /* SObjectClass */
    {
        "SShape",
        sizeof(SShape),
        { 0, 1},
        InitShape,         /* init    */
        NULL,              /* destroy */
        DisposeShape,      /* dispose */
        NULL,              /* compare */
        NULL,              /* print   */
        NULL,              /* copy    */
    },
    /* SShapeClass */
    MoveShape,             /* move    */
    NULL                   /* area    */
};

rectangle.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#ifndef _SPCT_RECTANGLE_EXAMPLE_H__
#define _SPCT_RECTANGLE_EXAMPLE_H__


/**
 * @file rectangle.h
 * 2d rectangle class as an example of Speect's object-oriented
 * programming support.
 */


/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "shape.h"


/************************************************************************************/
/*                                                                                  */
/* Begin external c declaration                                                     */
/*                                                                                  */
/************************************************************************************/
S_BEGIN_C_DECLS


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @name Utility Macros
 * @{
 */


/**
 * @hideinitializer
 * Return the given #SRectangle child class object as a rectangle
 * object.
 *
 * @param SELF The given object.
 *
 * @return Given object as #SRectangle* type.
 *
 * @note This casting is not safety checked.
 */
#define S_RECTANGLE(SELF)    ((SRectangle *)(SELF))


/**
 * @}
 */


/************************************************************************************/
/*                                                                                  */
/* SRectangle definition                                                            */
/*                                                                                  */
/************************************************************************************/

/**
 * @ingroup SRectangle
 * A 2d rectangle class as an example of Speect's object-oriented programming support.
 * @extends SShape
 */
typedef struct
{
    /**
     * @protected Inherit from #SShape.
     */
    SShape     obj;

    /**
     * @protected Rectangle width.
     */
    int width;

    /**
     * @protected Rectangle height.
     */
    int height;

} SRectangle;


/************************************************************************************/
/*                                                                                  */
/* SRectangleClass definition                                                       */
/*                                                                                  */
/************************************************************************************/

/**
 * The rectangle class structure.
 * @extends SShapeClass
 */
typedef struct
{
    /* Class members */
    /**
     * @protected Inherit from #SShapeClass.
     */
    SShapeClass  _inherit;

    /* Class methods */
    /**
     * @protected SetWidth function pointer.
     * Set the width of the given rectangle.
     *
     * @param  self The rectangle to set the width of.
     * @param  new_width The new width of the rectangle.
     * @param  error Error code.
     */
    void  (* const set_width)   (SRectangle *self, int new_width, s_erc *error);

    /**
     * @protected SetHeight function pointer.
     * Set the height of the given rectangle.
     *
     * @param  self The rectangle to set the height of.
     * @param  new_height The new height of the rectangle.
     * @param  error Error code.
     */
    void  (* const set_height)   (SRectangle *self, int new_height, s_erc *error);

} SRectangleClass;


/************************************************************************************/
/*                                                                                  */
/* Function prototypes                                                              */
/*                                                                                  */
/************************************************************************************/

/**
 * Create a new rectangle from the given parameters.
 * @public @memberof SRectangle
 *
 * @param x x-coordinate of rectangle top left hand position.
 * @param y y-coordinate of rectangle top left hand position.
 * @param width Rectangle width.
 * @param height Rectangle height.
 * @param error error Error code.
 *
 * @return Pointer to newly created rectangle.
 */
S_API SRectangle *SRectangleNew(int x, int y, int width, int height, s_erc *error);


/**
 * Set the width of the given rectangle.
 * @public @memberof SRectangle
 *
 * @param self The rectangle to set the width of.
 * @param new_width The new width of the rectangle.
 * @param error Error code.
 */
S_API void SRectangleSetWidth(SRectangle *self, int new_width, s_erc *error);


/**
 * Set the height of the given rectangle.
 * @public @memberof SRectangle
 *
 * @param self The rectangle to set the height of.
 * @param new_height The new height of the rectangle.
 * @param error Error code.
 */
S_API void SRectangleSetHeight(SRectangle *self, int new_height, s_erc *error);


/**
 * Register the SRectangle class to the object system.
 * @private @memberof SRectangle
 *
 * @param error Error code.
 */
S_LOCAL void _s_rectangle_class_reg(s_erc *error);


/**
 * Free the SRectangle class from the object system.
 * @private @memberof SRectangle
 *
 * @param error Error code.
 */
S_LOCAL void _s_rectangle_class_free(s_erc *error);


/************************************************************************************/
/*                                                                                  */
/* End external c declaration                                                       */
/*                                                                                  */
/************************************************************************************/
S_END_C_DECLS


/**
 * @}
 * end documentation
 */

#endif /* _SPCT_RECTANGLE_EXAMPLE_H__ */

rectangle.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "rectangle.h"


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @hideinitializer
 * Call the given function method of the given #SRectangle,
 * see full description #S_RECTANGLE_CALL for usage.
 *
 * @param SELF The given #SRectangle*.
 * @param FUNC The function method of the given object to call.
 *
 * @note This casting is not safety checked.
 * @note Example usage:
 @verbatim
 S_RECTANGLE_CALL(self, func)(param1, param2, ..., paramN);
 @endverbatim
 * where @c param1, @c param2, ..., @c paramN are the parameters
 * passed to the object function @c func.
 */
#define S_RECTANGLE_CALL(SELF, FUNC)                    \
    ((SRectangleClass *)S_OBJECT_CLS(SELF))->FUNC


/**
 * @hideinitializer
 * Test if the given function method of the given #SRectangle
 * can be called.
 *
 * @param SELF The given #SRectangle*.
 * @param FUNC The function method of the given object to check.
 *
 * @return #TRUE if function can be called, otherwise #FALSE.
 *
 * @note This casting is not safety checked.
 */
#define S_RECTANGLE_METH_VALID(SELF, FUNC)      \
    S_RECTANGLE_CALL(SELF, FUNC) ? TRUE : FALSE


/************************************************************************************/
/*                                                                                  */
/* Static variables                                                                 */
/*                                                                                  */
/************************************************************************************/

static SRectangleClass RectangleClass; /* Rectangle class declaration. */


/************************************************************************************/
/*                                                                                  */
/* Function implementations                                                         */
/*                                                                                  */
/************************************************************************************/

S_API SRectangle *SRectangleNew(int x, int y, int width, int height, s_erc *error)
{
    SRectangle *self;


    S_CLR_ERR(error);

    self = S_NEW(SRectangle, error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "SRectangleNew",
                  "Failed to create new object"))
    {
        return NULL;
    }

    S_SHAPE(self)->x = x;
    S_SHAPE(self)->y = y;
    self->width = width;
    self->height = height;

    return self;
}


S_API void SRectangleSetWidth(SRectangle *self, int new_width, s_erc *error)
{
    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SRectangleSetWidth",
                  "Argument \"self\" is NULL");
        return;
    }

    if (!S_RECTANGLE_METH_VALID(self, set_width))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SRectangleSetWidth",
                  "Rectangle method \"set_width\" not implemented");
        return;
    }


    S_RECTANGLE_CALL(self, set_width)(self, new_width, error);
    S_CHK_ERR(error, S_CONTERR,
              "SRectangleSetWidth",
              "Call to class method \"set_width\" failed");
}


S_API void SRectangleSetHeight(SRectangle *self, int new_height, s_erc *error)
{
    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SRectangleSetHeight",
                  "Argument \"self\" is NULL");
        return;
    }

    if (!S_RECTANGLE_METH_VALID(self, set_height))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SRectangleSetHeight",
                  "Rectangle method \"set_height\" not implemented");
        return;
    }


    S_RECTANGLE_CALL(self, set_height)(self, new_height, error);
    S_CHK_ERR(error, S_CONTERR,
              "SRectangleSetHeight",
              "Call to class method \"set_height\" failed");
}


/************************************************************************************/
/*                                                                                  */
/* Class registration                                                               */
/*                                                                                  */
/************************************************************************************/

S_LOCAL void _s_rectangle_class_reg(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_reg(S_OBJECTCLASS(&RectangleClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_rectangle_class_reg",
              "Failed to register SRectangleClass");
}


S_LOCAL void _s_rectangle_class_free(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_free(S_OBJECTCLASS(&RectangleClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_rectangle_class_free",
              "Failed to free SRectangleClass");
}


/************************************************************************************/
/*                                                                                  */
/* Static class function implementations                                            */
/*                                                                                  */
/************************************************************************************/

static void InitRectangle(void *obj, s_erc *error)
{
    SRectangle *self = obj;


    S_CLR_ERR(error);
    self->width = 0;
    self->height = 0;
}


static void DisposeRectangle(void *obj, s_erc *error)
{
    S_CLR_ERR(error);
    SObjectDecRef(obj);
}


static char *PrintRectangle(const SObject *self, s_erc *error)
{
    SRectangle *rec = S_RECTANGLE(self);
    const char *type = "[SRectangle] at (%d,%d), width %d, height %d";
    char *buf;

    S_CLR_ERR(error);

    s_asprintf(&buf, error, type, S_SHAPE(rec)->x, S_SHAPE(rec)->y, rec->width, rec->height);
    if (S_CHK_ERR(error, S_CONTERR,
                  "PrintRectangle",
                  "Call to \"s_asprintf\" failed"))
    {
        if (buf != NULL)
            S_FREE(buf);
        return NULL;
    }

    return buf;
}


static void MoveRectangle(SShape *self, int newx, int newy, s_erc *error)
{
    S_CLR_ERR(error);
    self->x = newx;
    self->y = newy;
}


static float AreaRectangle(const SShape *self, s_erc *error)
{
    SRectangle *rec = S_RECTANGLE(self);
    float area;


    S_CLR_ERR(error);
    area = rec->width * rec->height;

    return area;
}


static void SetWidthRectangle(SRectangle *self, int new_width, s_erc *error)
{
    S_CLR_ERR(error);
    self->width = new_width;
}


static void SetHeightRectangle(SRectangle *self, int new_heigth, s_erc *error)
{
    S_CLR_ERR(error);
    self->height = new_heigth;
}


/************************************************************************************/
/*                                                                                  */
/* Class initialization                                                             */
/*                                                                                  */
/************************************************************************************/

static SRectangleClass RectangleClass =
{
    {
        /* SObjectClass */
        {
            "SShape:SRectangle",
            sizeof(SRectangle),
            { 0, 1},
            InitRectangle,     /* init    */
            NULL,              /* destroy */
            DisposeRectangle,  /* dispose */
            NULL,              /* compare */
            PrintRectangle,    /* print   */
            NULL,              /* copy    */
        },
        /* SShapeClass */
        MoveRectangle,         /* move    */
        AreaRectangle,         /* area    */
    },
    /* SRectangleClass */
    SetWidthRectangle,         /* set_width  */
    SetHeightRectangle         /* set_height */
};

circle.h

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#ifndef _SPCT_CIRCLE_EXAMPLE_H__
#define _SPCT_CIRCLE_EXAMPLE_H__


/**
 * @file circle.h
 * 2d circle class as an example of Speect's object-oriented
 * programming support.
 */


/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "shape.h"


/************************************************************************************/
/*                                                                                  */
/* Begin external c declaration                                                     */
/*                                                                                  */
/************************************************************************************/
S_BEGIN_C_DECLS


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @name Utility Macros
 * @{
 */


/**
 * @hideinitializer
 * Return the given #SCircle child class object as a circle
 * object.
 *
 * @param SELF The given object.
 *
 * @return Given object as #SCircle* type.
 *
 * @note This casting is not safety checked.
 */
#define S_CIRCLE(SELF)    ((SCircle *)(SELF))


/**
 * @}
 */


/************************************************************************************/
/*                                                                                  */
/* SCircle definition                                                               */
/*                                                                                  */
/************************************************************************************/

/**
 * @ingroup SCircle
 * A 2d circle class as an example of Speect's object-oriented programming support.
 * @extends SShape
 */
typedef struct
{
    /**
     * @protected Inherit from #SShape.
     */
    SShape     obj;

    /**
     * @protected Circle radius.
     */
    int radius;

    /**
     * @protected Circle colour.
     */
    char *colour;

} SCircle;


/************************************************************************************/
/*                                                                                  */
/* SCircleClass definition                                                          */
/*                                                                                  */
/************************************************************************************/

/**
 * The circle class structure.
 * @extends SShapeClass
 */
typedef struct
{
    /* Class members */
    /**
     * @protected Inherit from #SShapeClass.
     */
    SShapeClass  _inherit;

    /* Class methods */
    /**
     * @protected SetRadius function pointer.
     * Set the radius of the given circle.
     *
     * @param  self The circle to set the radius of.
     * @param  new_radius The new radius of the circle.
     * @param  error Error code.
     */
    void  (* const set_radius)   (SCircle *self, int new_radius, s_erc *error);

    /**
     * @protected SetColour function pointer.
     * Set the colour of the given circle.
     *
     * @param  self The circle to set the colour of.
     * @param  new_colour The new colour of the circle.
     * @param  error Error code.
     */
    void  (* const set_colour)   (SCircle *self, const char *new_colour, s_erc *error);

} SCircleClass;


/************************************************************************************/
/*                                                                                  */
/* Function prototypes                                                              */
/*                                                                                  */
/************************************************************************************/

/**
 * Create a new circle from the given parameters.
 * @public @memberof SCircle
 *
 * @param x x-coordinate of circle top left hand position.
 * @param y y-coordinate of circle top left hand position.
 * @param radius Circle radius.
 * @param colour Circle colour.
 * @param error error Error code.
 *
 * @return Pointer to newly created circle.
 */
S_API SCircle *SCircleNew(int x, int y, int radius, const char *colour, s_erc *error);


/**
 * Set the radius of the given circle.
 * @public @memberof SCircle
 *
 * @param self The circle to set the radius of.
 * @param new_radius The new radius of the circle.
 * @param error Error code.
 */
S_API void SCircleSetRadius(SCircle *self, int new_radius, s_erc *error);


/**
 * Set the colour of the given circle.
 * @public @memberof SCircle
 *
 * @param self The circle to set the colour of.
 * @param new_colour The new colour of the circle.
 * @param error Error code.
 */
S_API void SCircleSetColour(SCircle *self, const char *new_colour, s_erc *error);


/**
 * Register the SCircle class to the object system.
 * @private @memberof SCircle
 *
 * @param error Error code.
 */
S_LOCAL void _s_circle_class_reg(s_erc *error);


/**
 * Free the SCircle class from the object system.
 * @private @memberof SCircle
 *
 * @param error Error code.
 */
S_LOCAL void _s_circle_class_free(s_erc *error);


/************************************************************************************/
/*                                                                                  */
/* End external c declaration                                                       */
/*                                                                                  */
/************************************************************************************/
S_END_C_DECLS


/**
 * @}
 * end documentation
 */

#endif /* _SPCT_CIRCLE_EXAMPLE_H__ */

circle.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/************************************************************************************/
/*                                                                                  */
/* Modules used                                                                     */
/*                                                                                  */
/************************************************************************************/

#include "circle.h"


/************************************************************************************/
/*                                                                                  */
/* Macros                                                                           */
/*                                                                                  */
/************************************************************************************/

/**
 * @hideinitializer
 * Call the given function method of the given #SCircle,
 * see full description #S_CIRCLE_CALL for usage.
 *
 * @param SELF The given #SCircle*.
 * @param FUNC The function method of the given object to call.
 *
 * @note This casting is not safety checked.
 * @note Example usage:
 @verbatim
 S_CIRCLE_CALL(self, func)(param1, param2, ..., paramN);
 @endverbatim
 * where @c param1, @c param2, ..., @c paramN are the parameters
 * passed to the object function @c func.
 */
#define S_CIRCLE_CALL(SELF, FUNC)                   \
    ((SCircleClass *)S_OBJECT_CLS(SELF))->FUNC


/**
 * @hideinitializer
 * Test if the given function method of the given #SCircle
 * can be called.
 *
 * @param SELF The given #SCircle*.
 * @param FUNC The function method of the given object to check.
 *
 * @return #TRUE if function can be called, otherwise #FALSE.
 *
 * @note This casting is not safety checked.
 */
#define S_CIRCLE_METH_VALID(SELF, FUNC)     \
    S_CIRCLE_CALL(SELF, FUNC) ? TRUE : FALSE


/************************************************************************************/
/*                                                                                  */
/* Static variables                                                                 */
/*                                                                                  */
/************************************************************************************/

static SCircleClass CircleClass; /* Circle class declaration. */


/************************************************************************************/
/*                                                                                  */
/* Function implementations                                                         */
/*                                                                                  */
/************************************************************************************/

S_API SCircle *SCircleNew(int x, int y, int radius, const char *colour, s_erc *error)
{
    SCircle *self;


    S_CLR_ERR(error);

    self = S_NEW(SCircle, error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "SCircleNew",
                  "Failed to create new object"))
    {
        return NULL;
    }

    S_SHAPE(self)->x = x;
    S_SHAPE(self)->y = y;
    self->radius = radius;
    self->colour = s_strdup(colour, error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "SCircleNew",
                  "Call to \"s_strdup\" failed"))
    {
        S_DELETE(self, "SCircleNew", error);
        return NULL;
    }

    return self;
}


S_API void SCircleSetRadius(SCircle *self, int new_radius, s_erc *error)
{
    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SCircleSetRadius",
                  "Argument \"self\" is NULL");
        return;
    }

    if (!S_CIRCLE_METH_VALID(self, set_radius))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SCircleSetRadius",
                  "Circle method \"set_radius\" not implemented");
        return;
    }


    S_CIRCLE_CALL(self, set_radius)(self, new_radius, error);
    S_CHK_ERR(error, S_CONTERR,
              "SCircleSetRadius",
              "Call to class method \"set_radius\" failed");
}


S_API void SCircleSetColour(SCircle *self, const char *new_colour, s_erc *error)
{
    S_CLR_ERR(error);

    if (self == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SCircleSetColour",
                  "Argument \"self\" is NULL");
        return;
    }

    if (new_colour == NULL)
    {
        S_CTX_ERR(error, S_ARGERROR,
                  "SCircleSetColour",
                  "Argument \"new_colour\" is NULL");
        return;
    }

    if (!S_CIRCLE_METH_VALID(self, set_colour))
    {
        S_CTX_ERR(error, S_METHINVLD,
                  "SCircleSetColour",
                  "Circle method \"set_colour\" not implemented");
        return;
    }


    S_CIRCLE_CALL(self, set_colour)(self, new_colour, error);
    S_CHK_ERR(error, S_CONTERR,
              "SCircleSetColour",
              "Call to class method \"set_colour\" failed");
}


/************************************************************************************/
/*                                                                                  */
/* Class registration                                                               */
/*                                                                                  */
/************************************************************************************/

S_LOCAL void _s_circle_class_reg(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_reg(S_OBJECTCLASS(&CircleClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_circle_class_reg",
              "Failed to register SCircleClass");
}


S_LOCAL void _s_circle_class_free(s_erc *error)
{
    S_CLR_ERR(error);
    s_class_free(S_OBJECTCLASS(&CircleClass), error);
    S_CHK_ERR(error, S_CONTERR,
              "_s_circle_class_free",
              "Failed to free SCircleClass");
}


/************************************************************************************/
/*                                                                                  */
/* Static class function implementations                                            */
/*                                                                                  */
/************************************************************************************/

static void InitCircle(void *obj, s_erc *error)
{
    SCircle *self = obj;


    S_CLR_ERR(error);
    self->radius = 0;
    self->colour = NULL;
}


static void DestroyCircle(void *obj, s_erc *error)
{
    SCircle *self = obj;


    S_CLR_ERR(error);
    if (self->colour != NULL)
    {
        S_FREE(self->colour);
    }
}


static void DisposeCircle(void *obj, s_erc *error)
{
    S_CLR_ERR(error);
    SObjectDecRef(obj);
}


static char *PrintCircle(const SObject *self, s_erc *error)
{
    SCircle *cir = S_CIRCLE(self);
    const char *type = "[SCircle] at (%d,%d), radius %d, colour %s";
    char *buf;

    S_CLR_ERR(error);

    if (cir->colour == NULL)
    {
        s_asprintf(&buf, error, type, S_SHAPE(cir)->x, S_SHAPE(cir)->y, cir->radius, "None");
    }
    else
    {
        s_asprintf(&buf, error, type, S_SHAPE(cir)->x, S_SHAPE(cir)->y, cir->radius, cir->colour);
    }

    if (S_CHK_ERR(error, S_CONTERR,
                  "PrintCircle",
                  "Call to \"s_asprintf\" failed"))
    {
        if (buf != NULL)
            S_FREE(buf);
        return NULL;
    }

    return buf;
}


static void MoveCircle(SShape *self, int newx, int newy, s_erc *error)
{
    SShapeClass *shapeClass = NULL;


    S_CLR_ERR(error);
    shapeClass = S_FIND_CLASS(SShape, error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "MoveCircle",
                  "Call to \"S_FIND_CLASS\" failed"))
        return;

    shapeClass->move(self, newx, newy, error);
}


static float AreaCircle(const SShape *self, s_erc *error)
{
    SCircle *cir = S_CIRCLE(self);
    float area;


    S_CLR_ERR(error);
    area = S_PI * cir->radius * cir->radius;

    return area;
}


static void SetRadiusCircle(SCircle *self, int new_radius, s_erc *error)
{
    S_CLR_ERR(error);
    self->radius = new_radius;
}


static void SetColourCircle(SCircle *self, const char *new_colour, s_erc *error)
{
    S_CLR_ERR(error);
    if (self->colour != NULL)
        S_FREE(self->colour);

    self->colour = s_strdup(new_colour, error);
    S_CHK_ERR(error, S_CONTERR,
              "SetColourCircle",
              "Call to \"s_strdup\" failed");
}


/************************************************************************************/
/*                                                                                  */
/* Class initialization                                                             */
/*                                                                                  */
/************************************************************************************/

static SCircleClass CircleClass =
{
    {
        /* SObjectClass */
        {
            "SShape:SCircle",
            sizeof(SCircle),
            { 0, 1},
            InitCircle,     /* init    */
            DestroyCircle,  /* destroy */
            DisposeCircle,  /* dispose */
            NULL,           /* compare */
            PrintCircle,    /* print   */
            NULL,           /* copy    */
        },
        /* SShapeClass */
        MoveCircle,         /* move    */
        AreaCircle,         /* area    */
    },
    /* SCircleClass */
    SetRadiusCircle,        /* set_radius */
    SetColourCircle         /* set_colour */
};

objsystem_example.c

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#include <stdio.h>
#include "speect.h"
#include "shape.h"
#include "rectangle.h"
#include "circle.h"



/*
 * register shape, rectangle and circle objects with the Speect object
 * system.
 */
void register_objects(s_erc *error)
{
    s_erc local_err = S_SUCCESS;

    S_CLR_ERR(error);

    _s_shape_class_reg(error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_shape_class_reg\" failed"))
        return;

    _s_rectangle_class_reg(error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_rectangle_class_reg\" failed"))
    {
        _s_shape_class_free(&local_err);
        return;
    }

    _s_circle_class_reg(error);
    if (S_CHK_ERR(error, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_circle_class_reg\" failed"))
    {
        _s_rectangle_class_free(&local_err);
        _s_shape_class_free(&local_err);
        return;
    }
}


/*
 * free shape, rectangle and circle objects from the Speect object
 * system.
 */
void free_objects(s_erc *error)
{
    s_erc local_err = S_SUCCESS;

    S_CLR_ERR(error);

    _s_circle_class_free(&local_err);
    if (S_CHK_ERR(&local_err, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_circle_class_free\" failed"))
        S_NEW_ERR(error, local_err);

    _s_rectangle_class_free(&local_err);
    if (S_CHK_ERR(&local_err, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_rectangle_class_free\" failed"))
        S_NEW_ERR(error, local_err);

    _s_shape_class_free(&local_err);
    if (S_CHK_ERR(&local_err, S_CONTERR,
                  "register_objects",
                  "Call to \"_s_shape_class_free\" failed"))
        S_NEW_ERR(error, local_err);
}


int main()
{
    s_erc error = S_SUCCESS;
    SCircle *circleShape = NULL;
    SRectangle *rectangleShape = NULL;
    int rv = 0;
    char *buf = NULL;
    int registered = 0;
    float area = 0.0;


    /*
     * initialize speect
     */
    error = speect_init(NULL);
    if (error != S_SUCCESS)
    {
        printf("Failed to initialize Speect\n");
        return 1;
    }

    /*
     * register SShape, SRectangle and SCircle classes with the Speect
     * object system.
     */
    register_objects(&error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SRectangleNew\" failed"))
    {
        rv = 1;
        goto quit;
    }
    else
    {
        registered = 1;
    }

    /*
     * create new rectangle
     */
    rectangleShape = SRectangleNew(10, 15, 100, 140, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SRectangleNew\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /*
     * Print the SRectangle object as an SObject
     */
    buf = SObjectPrint(S_OBJECT(rectangleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SObjectPrint\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("%s\n", buf);
    S_FREE(buf);

    /* get the rectangle's area */
    area = SShapeArea(S_SHAPE(rectangleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeArea\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("rectangle area = %f\n\n", area);


    /*
     * create new circle
     */
    circleShape = SCircleNew(20, 62, 70, "green", &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SCircleNew\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /*
     * Print the SCircle object as an SObject
     */
    buf = SObjectPrint(S_OBJECT(circleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SObjectPrint\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("%s\n", buf);
    S_FREE(buf);

    /* get the circle's area */
    area = SShapeArea(S_SHAPE(circleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeArea\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("circle area = %f\n\n", area);


    /* move the rectangle to new coordinates */
    SShapeMove(S_SHAPE(rectangleShape), 631, 103, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeMove\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /* move the circle to new coordinates */
    SShapeMove(S_SHAPE(circleShape), 311, 67, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeMove\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /* set the width and height of the rectangle */
    SRectangleSetWidth(rectangleShape, 32, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SRectangleSetWidth\" failed"))
    {
        rv = 1;
        goto quit;
    }


    SRectangleSetHeight(rectangleShape, 102, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SRectangleSetHeight\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /* set the radius and colour of the circle */
    SCircleSetRadius(circleShape, 34, &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SCircleSetRadius\" failed"))
    {
        rv = 1;
        goto quit;
    }

    SCircleSetColour(circleShape, "red", &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SCircleSetColour\" failed"))
    {
        rv = 1;
        goto quit;
    }

    /* print rectangle and circle attributes after all changes */
    printf("attributes after changes\n");

    /*
     * Print the SRectangle object as an SObject
     */
    buf = SObjectPrint(S_OBJECT(rectangleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SObjectPrint\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("%s\n", buf);
    S_FREE(buf);

    /* get the rectangle's area */
    area = SShapeArea(S_SHAPE(rectangleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeArea\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("rectangle area = %f\n\n", area);

    /*
     * Print the SCircle object as an SObject
     */
    buf = SObjectPrint(S_OBJECT(circleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SObjectPrint\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("%s\n", buf);
    S_FREE(buf);

    /* get the circle's area */
    area = SShapeArea(S_SHAPE(circleShape), &error);
    if (S_CHK_ERR(&error, S_CONTERR,
                  "main",
                  "Call to \"SShapeArea\" failed"))
    {
        rv = 1;
        goto quit;
    }

    printf("circle area = %f\n\n", area);


quit:
    if (circleShape != NULL)
        S_DELETE(circleShape, "main", &error);

    if (rectangleShape != NULL)
        S_DELETE(rectangleShape, "main", &error);

    if (registered)
        free_objects(&error);

    /*
     * quit speect
     */
    error = speect_quit();
    if (error != S_SUCCESS)
    {
        printf("Call to 'speect_quit' failed\n");
        return 1;
    }

    return rv;
}