+ "/* The example %s, so fake function wrapper inserted */\n"
+ "int main(int argc, char *argv[])\n"
+ "{\n", why);
+}
+
+/* We only handle simple function definitions here. */
+static char *add_func(char *others, const char *line)
+{
+ const char *p, *end = strchr(line, '(') - 1;
+ while (isspace(*end)) {
+ end--;
+ if (end == line)
+ return others;
+ }
+
+ for (p = end; isalnum(*p) || *p == '_'; p--) {
+ if (p == line)
+ return others;
+ }
+
+ return talloc_asprintf_append(others, "printf(\"%%p\", %.*s);\n",
+ (unsigned)(end - p), p+1);
+}
+
+static void strip_leading_whitespace(char **lines)
+{
+ unsigned int i, min_span = -1U;
+
+ for (i = 0; lines[i]; i++) {
+ unsigned int span = strspn(lines[i], " \t");
+ /* All whitespace? Ignore */
+ if (!lines[i][span])
+ continue;
+ if (span < min_span)
+ min_span = span;
+ }
+
+ for (i = 0; lines[i]; i++)
+ if (strlen(lines[i]) >= min_span)
+ lines[i] += min_span;
+}
+
+static bool looks_internal(char **lines, char **why)
+{
+ unsigned int i;
+ bool last_ended = true; /* Did last line finish a statement? */
+
+ for (i = 0; lines[i]; i++) {
+ /* Skip leading whitespace. */
+ const char *line = lines[i] + strspn(lines[i], " \t");
+ unsigned len = strspn(line, IDENT_CHARS);
+
+ if (!line[0] || isspace(line[0]) || strstarts(line, "//"))
+ continue;
+
+ /* The winners. */
+ if (strstarts(line, "if") && len == 2) {
+ *why = "starts with if";
+ return true;
+ }
+ if (strstarts(line, "for") && len == 3) {
+ *why = "starts with for";
+ return true;
+ }
+ if (strstarts(line, "while") && len == 5) {
+ *why = "starts with while";
+ return true;
+ }
+ if (strstarts(line, "do") && len == 2) {
+ *why = "starts with do";
+ return true;
+ }
+
+ /* The losers. */
+ if (strstarts(line, "#include")) {
+ *why = "starts with #include";
+ return false;
+ }
+
+ if (last_ended && strchr(line, '(')) {
+ if (strstarts(line, "static")) {
+ *why = "starts with static and contains (";
+ return false;
+ }
+ if (strends(line, ")")) {
+ *why = "contains ( and ends with )";
+ return false;
+ }
+ }
+
+ /* Single identifier then operator == inside function. */
+ if (last_ended && len
+ && ispunct(line[len+strspn(line+len, " ")])) {
+ *why = "starts with identifier then punctuation";
+ return true;
+ }
+
+ last_ended = (strends(line, "}")
+ || strends(line, ";")
+ || streq(line, "..."));
+ }
+
+ /* No idea... Say yes? */
+ *why = "gave no clues";
+ return true;
+}
+
+/* Examples will often build on prior ones. Try combining them. */
+static char **combine(const void *ctx, char **lines, char **prev)
+{
+ unsigned int i, lines_total, prev_total, count;
+ char **ret;
+ const char *reasoning;
+ char *why = NULL;
+
+ if (!prev)
+ return NULL;
+
+ /* If it looks internal, put prev at start. */
+ if (looks_internal(lines, &why)) {
+ count = 0;
+ reasoning = "seemed to belong inside a function";
+ } else {
+ /* Try inserting in first elided position */
+ for (count = 0; lines[count]; count++) {
+ if (strcmp(lines[count], "...") == 0)
+ break;
+ }
+ if (!lines[count]) {
+ /* Try at start anyway? */
+ count = 0;
+ reasoning = "didn't seem to belong inside"
+ " a function, so we prepended the previous"
+ " example";
+ } else {
+ reasoning = "didn't seem to belong inside"
+ " a function, so we put the previous example"
+ " at the first ...";
+
+ count++;
+ }
+ }
+
+ for (i = 0; lines[i]; i++);
+ lines_total = i;
+
+ for (i = 0; prev[i]; i++);
+ prev_total = i;
+
+ ret = talloc_array(ctx, char *, 1 +lines_total + prev_total + 1);
+ ret[0] = talloc_asprintf(ret, "/* The example %s, thus %s */\n",
+ why, reasoning);
+ memcpy(ret+1, lines, count * sizeof(ret[0]));
+ memcpy(ret+1 + count, prev, prev_total * sizeof(ret[0]));
+ memcpy(ret+1 + count + prev_total, lines + count,
+ (lines_total - count + 1) * sizeof(ret[0]));
+ return ret;