patterncMinor
Spun article reader
Viewed 0 times
readerarticlespun
Problem
This is a simple GTK+ program that takes a spun article as input and shows a random output every time the user clicks the "Spin" button.
It supports many levels of nested spinning like:
I tested it and it seems to be correct, but I would like to receive any suggestions on how to improve the code, specially if there's some bug I didn't notice.
`#include
#include
#include "dynamic_string.h"
#include
#define SUCCESS 1
#define ERROR 0
GtkWidget *output_text;
size_t get_size(const char *src)
{
const char *start = src;
while(++src && src != '}')
if(*src == '{')
src += get_size(src) - 1;
return (src - start) + 1;
}
size_t get_count(const char *src)
{
size_t count = 1;
while(*++src){
if(*src == '}')
break;
else
if(*src == '|')
++count;
else
if(*src == '{')
src += get_size(src) - 1;
}
return count;
}
const char get_word_n(const char start, size_t n)
{
size_t count = 0;
while(*++start){
if(count == n)
return start;
if(*start == '}')
break;
else
if(*start == '|')
++count;
else
if(*start == '{')
start += get_size(start) - 1;
}
puts("Invalid format or there are not as many words as you expected.");
return NULL;
}
int choose_one(const char src, Dynamic_String dest)
{
size_t count = get_count(src);
const char *str = get_word_n(src, rand() % count);
if(str == NULL)
return ERROR;
while(str && str != '}' && *str != '|'){
if(*str == '{'){
if(choose_one(str, dest) == ERROR)
return ERROR;
str += get_size(str) - 1;
}
else
if(ds_push_back(dest, *str) == DS_ERROR)
exit(1);
++str;
}
return SUCCESS;
}
gboolean spin(GtkButton
It supports many levels of nested spinning like:
The {car|automobile} is {{very |}fine|{really {pretty |}|}cool|all right}
I tested it and it seems to be correct, but I would like to receive any suggestions on how to improve the code, specially if there's some bug I didn't notice.
`#include
#include
#include "dynamic_string.h"
#include
#define SUCCESS 1
#define ERROR 0
GtkWidget *output_text;
size_t get_size(const char *src)
{
const char *start = src;
while(++src && src != '}')
if(*src == '{')
src += get_size(src) - 1;
return (src - start) + 1;
}
size_t get_count(const char *src)
{
size_t count = 1;
while(*++src){
if(*src == '}')
break;
else
if(*src == '|')
++count;
else
if(*src == '{')
src += get_size(src) - 1;
}
return count;
}
const char get_word_n(const char start, size_t n)
{
size_t count = 0;
while(*++start){
if(count == n)
return start;
if(*start == '}')
break;
else
if(*start == '|')
++count;
else
if(*start == '{')
start += get_size(start) - 1;
}
puts("Invalid format or there are not as many words as you expected.");
return NULL;
}
int choose_one(const char src, Dynamic_String dest)
{
size_t count = get_count(src);
const char *str = get_word_n(src, rand() % count);
if(str == NULL)
return ERROR;
while(str && str != '}' && *str != '|'){
if(*str == '{'){
if(choose_one(str, dest) == ERROR)
return ERROR;
str += get_size(str) - 1;
}
else
if(ds_push_back(dest, *str) == DS_ERROR)
exit(1);
++str;
}
return SUCCESS;
}
gboolean spin(GtkButton
Solution
This may be disappointing but: I didn't find much wrong with it. That said, there are a few small points that might be useful.
Reducing memory leaks
I almost didn't even write this one because the GTK library is notorious for leaking memory. With that said, there are a few things one can and should do. First, is that the top-level
There's a document that describes GTK memory management but consensus seems to be that if you use GTK your program WILL leak memory.
Use
Within the
Reconsider malformed strings
The program doesn't crash (good!) but it also doesn't like input of the form:
It prints to the console, but it could just as easily handle this input the same way that it handles
which is simply to print the trailing
Consolidate
The content of the
In all it seemed pretty solid code.
Reducing memory leaks
I almost didn't even write this one because the GTK library is notorious for leaking memory. With that said, there are a few things one can and should do. First, is that the top-level
GtkWidget *window is created as a floating reference and isn't "owned" by anything. To make sure it's properly freed after it's done you can add this:/* Main window */
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_object_ref_sink(window); /* create a reference to the window */
/* ... */
gtk_main();
gtk_widget_destroy(window); /* ask for window to be released */
g_object_unref(window); /* remove last reference to window */There's a document that describes GTK memory management but consensus seems to be that if you use GTK your program WILL leak memory.
Use
g_free for GTK allocated itemsWithin the
spin function, the gtk_text_buffer_get_text function is called which allocates a new UTF-8 buffer. You're freeing it, which is good, but with free rather than g_free. It probably doesn't matter in this case, but get in the habit of using g_free for GTK+-allocated items.Reconsider malformed strings
The program doesn't crash (good!) but it also doesn't like input of the form:
{big|fat} hog{It prints to the console, but it could just as easily handle this input the same way that it handles
{big|fat} hog}which is simply to print the trailing
} like any other character.Consolidate
get_count and get_word_nThe content of the
get_count and get_word_n functions is similar and overlapping and they are only called once back-to-back from within choose_one(). In all it seemed pretty solid code.
Code Snippets
/* Main window */
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_object_ref_sink(window); /* create a reference to the window */
/* ... */
gtk_main();
gtk_widget_destroy(window); /* ask for window to be released */
g_object_unref(window); /* remove last reference to window */{big|fat} hog{{big|fat} hog}Context
StackExchange Code Review Q#49000, answer score: 6
Revisions (0)
No revisions yet.