Design Pattern Examples
Overview of object-oriented design patterns
Command_Exercise.c
Go to the documentation of this file.
1
6
7#include <stdbool.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "helpers/replace.h"
13#include "helpers/stack.h"
14
15#include "Command_Exercise.h"
16#include "Command_Command.h"
17
22
23
24//=============================================================================
25//=============================================================================
26
33{
35 Command_Execute(command);
36}
37
38
45static void Command_Operation_Replace(Command_TextObject* source, const char* searchPattern, const char* replaceText)
46{
47 const char* newText = replace_str(Command_TextObject_GetText(source), searchPattern, replaceText);
48 if (newText != NULL)
49 {
50 Command_TextObject_SetText(source, newText);
51 }
52 else
53 {
54 printf(" Error replacing text, probably out of memory.\n");
55 }
56}
57
63{
64 if (source != NULL && source->text != NULL)
65 {
66 char* text = Command_TextObject_GetText(source);
67
68 size_t textSize = strlen(text);
69 size_t halftextSize = textSize / 2;
70 for (size_t index = 0; index < halftextSize; ++index)
71 {
72 char c = text[index];
73 text[index] = text[textSize - index - 1];
74 text[textSize - index - 1] = c;
75 }
76 }
77}
78
79
86{
88 {
89 // Reset the text to the starting point.
91
92 // Get rid of the last command applied and remember it.
93 Command* lastCommand = (Command*)Stack_Pop(&_commandUndoList);
94
95 // Reverse the existing stack onto another stack so we can apply
96 // the commands in order.
97 //
98 // Note: A doubly-linked list would eliminate the need for this stack-
99 // swapping and be much more efficient but a doubly-linked list is a
100 // bear to get right.
101 StackEntry* operationsStack = NULL;
103 {
105 Stack_Push(&operationsStack, command);
106 }
107
108 // Now apply all remaining commands to the text in order
109 // (oldest to newest). Also puts the commands back on the original
110 // undo stack.
111 while (!(Stack_IsEmpty(&operationsStack)))
112 {
113 Command* command = Stack_Pop(&operationsStack);
114 Command_Execute(command);
115 Stack_Push(&_commandUndoList, command);
116 }
117
118 // Show off what we (un)did.
119 printf(" undoing command %-31s==> \"%s\"\n", Command_ToString(lastCommand), Command_TextObject_ToString(text));
120 Command_Destroy(lastCommand);
121 }
122}
123
124
133static void Command_ApplyReplaceCommand(Command_TextObject* text, const char* searchPattern, const char* replaceText)
134{
135 Command* command = Command_Create_Two_Parameters("Replace", text, Command_Operation_Replace, searchPattern, replaceText);
136 if (command != NULL)
137 {
139 printf(" command %-31s==> \"%s\"\n", Command_ToString(command), Command_TextObject_ToString(text));
140 }
141 else
142 {
143 printf(" Error! Out of memory allocating a Command structure for replace operation.\n");
144 }
145}
146
147
156{
158 if (command != NULL)
159 {
161 printf(" command %-31s==> \"%s\"\n", Command_ToString(command), Command_TextObject_ToString(text));
162 }
163 else
164 {
165 printf(" Error! Out of memory allocating a Command structure for reverse operation.\n");
166 }
167}
168
169//=============================================================================
170//=============================================================================
171
184// ! [Using Command in C]
186{
187 printf("\nCommand_Exercise\n");
188
189 Command_TextObject textObject = { 0 };
190 if (Command_TextObject_Initialize(&textObject, "This is a line of text on which to experiment."))
191 {
192 printf(" Starting text: \"%s\"\n", Command_TextObject_ToString(&textObject));
193
194 // Apply four operations to the text.
195 Command_ApplyReplaceCommand(&textObject, "text", "painting");
196 Command_ApplyReplaceCommand(&textObject, "on", "off");
197 Command_ApplyReverseCommand(&textObject);
198 Command_ApplyReplaceCommand(&textObject, "i", "!");
199
200 printf(" Now perform undo until back to original\n");
201
202 // Now undo the four operations.
203 Command_Undo(&textObject);
204 Command_Undo(&textObject);
205 Command_Undo(&textObject);
206 Command_Undo(&textObject);
207
208 printf(" Final text : \"%s\"\n", Command_TextObject_ToString(&textObject));
209
210 Command_TextObject_Clear(&textObject);
211 }
212 printf(" Done.\n");
213}
214// ! [Using Command in C]
Command * Command_Create_No_Parameters(const char *commandName, Command_TextObject *receiver, no_parameter_operation operation)
Create a new Command object with the given parameters, creating a command that uses no additional par...
Command * Command_Create_Two_Parameters(const char *commandName, Command_TextObject *receiver, two_parameter_operation operation, const char *arg1, const char *arg2)
Create a new Command object with the given parameters, creating a command that uses two additional pa...
void Command_Execute(Command *commandObject)
Execute the given command on the Command_TextObject it knows about.
const char * Command_ToString(Command *commandObject)
Convert the given command object to a string representation.
void Command_Destroy(Command *commandObject)
Destroy the given command object, releasing it and any associated resources.
Declaration of the Command structure and associated functions as used in the Command Pattern.
void Command_Save_And_Execute(Command *command)
Save the given command on the undo list then execute the command on the text object with which the co...
static void Command_ApplyReplaceCommand(Command_TextObject *text, const char *searchPattern, const char *replaceText)
Helper function to create a Command object that replaces text in the given Command_TextObject,...
static StackEntry * _commandUndoList
The stack used to remember the commands for undo.
static void Command_Operation_Replace(Command_TextObject *source, const char *searchPattern, const char *replaceText)
An operation to search and replace text in a Command_TextObject.
void Command_Exercise(void)
Example of using the Command Pattern.
static void Command_ApplyReverseCommand(Command_TextObject *text)
Helper function to create a Command object that reverses the order of the characters in the given Com...
static void Command_Undo(Command_TextObject *text)
Perform an undo on the given Command_TextObject, using the commands in the "global" undo list....
static void Command_Operation_Reverse(Command_TextObject *source)
An operation to reverse the characters in the given Command_TextObject.
const char * Command_TextObject_ToString(Command_TextObject *textObject)
Converts the Command_TextObject to a string (basically, returns the current text from the Command_Tex...
void Command_TextObject_Clear(Command_TextObject *textObject)
Clear the contents of the specified Command_TextObject, releasing any allocated resources associated ...
bool Command_TextObject_Initialize(Command_TextObject *textObject, const char *startingText)
Initialize a Command_TextObject with the specified text.
void Command_TextObject_Reset(Command_TextObject *textObject)
Resets the Command_TextObject to the starting string.
char * Command_TextObject_GetText(Command_TextObject *textObject)
Gets the text in the specified Command_TextObject.
void Command_TextObject_SetText(Command_TextObject *textObject, const char *newText)
Sets the text in the specified Command_TextObject.
Declaration of the Command_Exercise() function as used in the Command Pattern.
char * replace_str(const char *s, const char *str1, const char *str2)
Replace all occurrences of narrow string str1 with narrow string str2 in s, using case-sensitive sear...
Definition: replace.c:127
bool Stack_IsEmpty(StackEntry **stack)
Determines if the given stack is empty.
Definition: stack.c:82
void Stack_Push(StackEntry **stack, void *item)
Push the given entry onto the given stack.
Definition: stack.c:40
void * Stack_Pop(StackEntry **stack)
Pop the last entry from the given stack, returning the item.
Definition: stack.c:63
Declaration of the StackEntry structure and the supporting functions that represents a simple stack.
Container for a string. Need to use a structure to keep the starting text and the current text togeth...
char * text
The text that can change.
Represents an operation that can be applied to a Command_TextObject. Can hold one of two kinds of ope...
Represents an entry on a simple stack that wraps an "item" represented by an opaque pointer.
Definition: stack.h:32