143 lines
4.5 KiB
C
143 lines
4.5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <dlist.h>
|
|
|
|
/*
|
|
* Minimum working example for dlist.c that shows how the internal
|
|
* structure of a list can be visualized. In this version, the list
|
|
* "borrows" the payload memory, i.e., the user of the list is
|
|
* responsible for deallocating the payload memory. See dlist_mwe2i.c
|
|
* for a version where the list takes over the responsibility.
|
|
*
|
|
* Authors: Niclas Borlin (niclas@cs.umu.se)
|
|
*
|
|
* Version information:
|
|
* v1.0 2024-03-14: First public version.
|
|
* v1.1 2024-03-15: Moved printout of dot instructions to separate function.
|
|
*/
|
|
|
|
#define VERSION "v1.1"
|
|
#define VERSION_DATE "2024-03-15"
|
|
|
|
// Make a dynamic copy of the input string.
|
|
char *copy_string(char *str)
|
|
{
|
|
char *copy = calloc(strlen(str) + 1, sizeof(char));
|
|
strcpy(copy, str);
|
|
return copy;
|
|
}
|
|
|
|
// Return the memory occupied by the string
|
|
void kill_string(void *v)
|
|
{
|
|
char *p = v; // Convert to a char ptr, useful in a debugger
|
|
free(p);
|
|
}
|
|
|
|
// String print function.
|
|
void print_string(const void *value)
|
|
{
|
|
const char *s=value;
|
|
printf("\"%s\"", s);
|
|
}
|
|
|
|
void print_string_internal(const void *value)
|
|
{
|
|
const char *s=value;
|
|
// We must double-escape the double quotes since the output will
|
|
// be parsed a second time by graphviz.
|
|
printf("\\\"%s\\\"", s);
|
|
}
|
|
|
|
// Print cut lines before and after a call list_print_internal.
|
|
void print_internal_with_cut_lines(const dlist *l, const char *desc)
|
|
{
|
|
// Internal counter that will be remembered between calls.
|
|
|
|
// Used to generate sequentially numbered -- CUT HERE -- marker lines
|
|
// to enable automatic parsing of the output.
|
|
static int cut = 1;
|
|
|
|
// Print starting marker line.
|
|
printf("\n--- START CUT HERE %d ---\n", cut);
|
|
|
|
// Call the internal print function to get the actual dot code.
|
|
dlist_print_internal(l, print_string_internal, desc, 0);
|
|
|
|
// Print ending marker line
|
|
printf("--- END CUT HERE %d ---\n\n", cut);
|
|
|
|
// Increment the cut number. Will be remembered next time the
|
|
// function is called since cut is a static variable.
|
|
cut++;
|
|
}
|
|
|
|
// Print a message with intructions how to use the dot output. prog is
|
|
// the name of the executable.
|
|
void print_dot_usage(char *prog)
|
|
{
|
|
printf("\nGenerate dot code to visualize internal structure with GraphViz. ");
|
|
printf("Use\n\n%s ", prog);
|
|
printf("| sed -n '/START CUT HERE X/,/END CUT HERE X/{//!p}' | dot -Tsvg > /tmp/dot.svg\n\n");
|
|
printf("to generate an svg file of cut X (replace X by the requested cut number).\n");
|
|
printf("The generated file can then be visualized with\n\n");
|
|
printf("firefox /tmp/dot.svg\n\n");
|
|
printf("Use -Tpng to generate a .png file instead. "
|
|
"See graphviz.org and %s for documentation.\n", __FILE__);
|
|
|
|
printf("\n--- Start of normal output ---\n\n");
|
|
}
|
|
|
|
// Test program.
|
|
int main(int argc, char *argv[])
|
|
{
|
|
printf("%s, %s %s: Create list of strings without memfreehandler.\n",
|
|
__FILE__, VERSION, VERSION_DATE);
|
|
printf("Code base version %s (%s).\n\n", CODE_BASE_VERSION, CODE_BASE_RELEASE_DATE);
|
|
|
|
print_dot_usage(argv[0]);
|
|
|
|
// Names to insert in the list.
|
|
char *names[] = {"Alfons", "Bengt", "Cia", "David", "Florian", "Gunnar"};
|
|
|
|
// Create the list
|
|
dlist *l = dlist_empty(NULL);
|
|
|
|
printf("Empty list from the outside:\n");
|
|
dlist_print(l, print_string);
|
|
print_internal_with_cut_lines(l, "Empty list showing the internal structure");
|
|
|
|
dlist_pos p = dlist_first(l);
|
|
for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
|
|
// Insert dynamic copies of strings at last position.
|
|
p = dlist_insert(l, copy_string(names[i]), p);
|
|
p = dlist_next(l, p);
|
|
}
|
|
// Print the list.
|
|
printf("DList from the outside after inserting 6 strings:\n");
|
|
dlist_print(l, print_string);
|
|
const char *long_desc = __FILE__
|
|
": Internal structure of the DList after inserting 6 strings.\n"
|
|
"Red lines are used for the list payload.\n\n"
|
|
"The dashed red lines indicate that the payload memory is\n"
|
|
"BORROWED by the list, i.e., the payload\n"
|
|
"memory will NOT be deallocated by the list.\n\n"
|
|
"See dlist_mwe2i for a list example\nthat owns the payload memory.";
|
|
print_internal_with_cut_lines(l, long_desc);
|
|
|
|
// Traverse the list and deallocate each value.
|
|
p = dlist_first(l);
|
|
while (!dlist_is_end(l,p)) {
|
|
char *v=dlist_inspect(l,p);
|
|
kill_string(v);
|
|
p=dlist_remove(l,p);
|
|
}
|
|
// Destroy the list.
|
|
dlist_kill(l);
|
|
|
|
printf("\nNormal exit.\n\n");
|
|
return 0;
|
|
}
|