blob: eee321a1b8fb466624dddfe7671a7342c1c37f8a [file] [log] [blame] [edit]
/* A "brutally minimal" example?
*
* 1. It searches a (disk) block that contains entries of varying
* length.
* 2. It returns a structure from a function.
* 3. It points to a structure within a structure.
* 4. It does pointer arithmetic.
*
* If this functionality had been generated by Cogent,
*
* (A) Would each Entry in block have to be copied somewhere before its
* name could be accessed to see whether it’s "wombat"? (Here, there is
* no copy.)
*
* (B) Would the thisEntry->stuff struct in a successful search have to
* be copied onto the stack, to reach the caller? (Here, a pointer is
* returned.)
*
* (C) Can thisEntry->stuff be pointed-to at all?
*
* (D) Would there be further difficulties if theStuff->b were to be
* -updated- by the caller, rather than simply read? (In that case, the
* overlap of block theStuff might cause problems with linear
* reasoning.)
*
* Created by Craig McLaughlin from Carroll Morgan's "brutally minimal"
* example.
*/
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#define SIZE 4096
struct Stuff { // The data sought, item b in particular.
int a,b,c;
};
struct Entry { // ... of varying length.
int len; // Length in bytes of the whole entry.
struct Stuff stuff; // What the caller wants.
char name[]; // The name of this particular "stuff";
// a flexible array member.
};
char block[SIZE]; // Contains Entry’s jammed together; terminated by
// len==0.
/* Look for Entry with the specified name. */
struct Stuff *find_stuff(char name[]) {
struct Entry *e = (struct Entry *)&block;
for (;;) {
if (e->len == 0 || ((uintptr_t)e - (uintptr_t)block) >= SIZE)
break;
if (strcmp(name, e->name) == 0)
return &e->stuff;
e = (struct Entry *) ((uintptr_t)e + e->len);
}
return NULL;
}
int in_range(struct Entry *e, unsigned long nlen) {
unsigned long p = (uintptr_t)e + offsetof(struct Entry,name) + nlen;
return (p - (uintptr_t)block) < SIZE;
}
/* Initialise our block of entries. */
/* Not translated into Cogent. */
void init(void) {
FILE *fp;
struct Entry *e, *d;
int a, b, c, len;
char buf[80];
memset(block, 0, SIZE);
if ((fp = fopen("entries.txt", "r")) != NULL) {
e = (struct Entry *)block;
while (fscanf(fp, "%s%d%d%d\n", buf, &a, &b, &c) == 4) {
len = strlen(buf)+1;
if (!in_range(e, len)) {
break;
}
strcpy(e->name, buf);
e->stuff.a = a;
e->stuff.b = b;
e->stuff.c = c;
e->len = ((uintptr_t)e->name + len) - (uintptr_t)e;
e = (struct Entry *) ((uintptr_t)e + e->len);
}
fclose(fp);
}
}
int main() { // Print "b" attribute of Entry "wombat", if it’s there.
struct Stuff *s;
init();
s = find_stuff("wombat");
if (s)
printf("Wombat’s b is %d.\n", s->b);
else
printf("Wombat was not found.\n");
return 0;
}