| /* 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 *)█ |
| 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; |
| } |