Task: Inverted index

C: #include <stdio.h>
#include <stdlib.h>

char chr_legal[] = "abcdefghijklmnopqrstuvwxyz0123456789_-./";
int  chr_idx[256] = {0};
char idx_chr[256] = {0};

#define FNAME 0
typedef struct trie_t *trie, trie_t;
struct trie_t {
    trie next[sizeof(chr_legal)]; 
    int eow;
};

trie trie_new() { return calloc(sizeof(trie_t), 1); }

#define find_word(r, w) trie_trav(r, w, 1)

trie trie_trav(trie root, const char * str, int no_create)
{
    int c;
    while (root) {
        if ((c = str[0]) == '\0') {
            if (!root->eow && no_create) return 0;
            break;
        }
        if (! (c = chr_idx[c]) ) {
            str++;
            continue;
        }

        if (!root->next[c]) {
            if (no_create) return 0;
            root->next[c] = trie_new();
        }
        root = root->next[c];
        str++;
    }
    return root;
}


int trie_all(trie root, char path[], int depth, int (*callback)(char *))
{
    int i;
    if (root->eow && !callback(path)) return 0;

    for (i = 1; i < sizeof(chr_legal); i++) {
        if (!root->next[i]) continue;

        path[depth] = idx_chr[i];
        path[depth + 1] = '\0';
        if (!trie_all(root->next[i], path, depth + 1, callback))
            return 0;
    }
    return 1;
}

void add_index(trie root, const char *word, const char *fname)
{
    trie x = trie_trav(root, word, 0);
    x->eow = 1;

    if (!x->next[FNAME])
        x->next[FNAME] = trie_new();
    x = trie_trav(x->next[FNAME], fname, 0);
    x->eow = 1;
}

int print_path(char *path)
{
    printf(" %s", path);
    return 1;
}


const char *files[] = { "f1.txt", "source/f2.txt", "other_file" };
const char *text[][5] ={{ "it", "is", "what", "it", "is" },
                { "what", "is", "it", 0 },
                { "it", "is", "a", "banana", 0 }};

trie init_tables()
{
    int i, j;
    trie root = trie_new();
    for (i = 0; i < sizeof(chr_legal); i++) {
        chr_idx[(int)chr_legal[i]] = i + 1;
        idx_chr[i + 1] = chr_legal[i];
    }


#define USE_ADVANCED_FILE_HANDLING 0
#if USE_ADVANCED_FILE_HANDLING
    void read_file(const char * fname) {
        char cmd[1024];
        char word[1024];
        sprintf(cmd, "perl -p -e 'while(/(\\w+)/g) {print lc($1),\"\\n\"}' %s", fname);
        FILE *in = popen(cmd, "r");
        while (!feof(in)) {
            fscanf(in, "%1000s", word);
            add_index(root, word, fname);
        }
        pclose(in);
    };

    read_file("f1.txt");
    read_file("source/f2.txt");
    read_file("other_file");
#else
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 5; j++) {
            if (!text[i][j]) break;
            add_index(root, text[i][j], files[i]);
        }
    }
#endif 

    return root;
}

void search_index(trie root, const char *word)
{
    char path[1024];
    printf("Search for \"%s\": ", word);
    trie found = find_word(root, word);

    if (!found) printf("not found\n");
    else {
        trie_all(found->next[FNAME], path, 0, print_path);
        printf("\n");
    }
}

int main()
{
    trie root = init_tables();

    search_index(root, "what");
    search_index(root, "is");
    search_index(root, "banana");
    search_index(root, "boo");
    return 0;
}




Go: package main

import (
    "bufio"
    "bytes"
    "errors"
    "fmt"
    "io"
    "os"
)


var index map[string][]int 
var indexed []doc

type doc struct {
    file  string
    title string
}

func main() {
    
    index = make(map[string][]int)

    
    if err := indexDir("docs"); err != nil {
        fmt.Println(err)
        return
    }

    
    ui()
}

func indexDir(dir string) error {
    df, err := os.Open(dir)
    if err != nil {
        return err
    }
    fis, err := df.Readdir(-1)
    if err != nil {
        return err
    }
    if len(fis) == 0 {
        return errors.New(fmt.Sprintf("no files in %s", dir))
    }
    indexed := 0
    for _, fi := range fis {
        if !fi.IsDir() {
            if indexFile(dir + "/" + fi.Name()) {
                indexed++
            }
        }
    }
    return nil
}

func indexFile(fn string) bool {
    f, err := os.Open(fn)
    if err != nil {
        fmt.Println(err)
        return false 
    }

    
    x := len(indexed)
    indexed = append(indexed, doc{fn, fn})
    pdoc := &indexed[x]

    
    r := bufio.NewReader(f)
    lines := 0
    for {
        b, isPrefix, err := r.ReadLine()
        switch {
        case err == io.EOF:
            return true
        case err != nil:
            fmt.Println(err)
            return true
        case isPrefix:
            fmt.Printf("%s: unexpected long line\n", fn)
            return true
        case lines < 20 && bytes.HasPrefix(b, []byte("Title:")):
            
            
            
            pdoc.title = string(b[7:])
        }
        
        
        
    wordLoop:
        for _, bword := range bytes.Fields(b) {
            bword := bytes.Trim(bword, ".,-~?!\"'`;:()<>[]{}\\|/=_+*&^%$#@")
            if len(bword) > 0 {
                word := string(bword)
                dl := index[word]
                for _, d := range dl {
                    if d == x {
                        continue wordLoop
                    }
                }
                index[word] = append(dl, x)
            }
        }
    }
    return true
}

func ui() {
    fmt.Println(len(index), "words indexed in", len(indexed), "files")
    fmt.Println("enter single words to search for")
    fmt.Println("enter a blank line when done")
    var word string
    for {
        fmt.Print("search word: ")
        wc, _ := fmt.Scanln(&word)
        if wc == 0 {
            return
        }
        switch dl := index[word]; len(dl) {
        case 0:
            fmt.Println("no match")
        case 1:
            fmt.Println("one match:")
            fmt.Println("   ", indexed[dl[0]].file, indexed[dl[0]].title)
        default:
            fmt.Println(len(dl), "matches:")
            for _, d := range dl {
                fmt.Println("   ", indexed[d].file, indexed[d].title)
            }
        }
    }
}