HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Spun article reader

Submitted by: @import:stackexchange-codereview··
0
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:

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 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 items

Within 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_n

The 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.