Task: Function frequency

C: #define _POSIX_SOURCE
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct functionInfo {
    char* name;
    int timesCalled;
    char marked;
};
void addToList(struct functionInfo** list, struct functionInfo toAdd, \
               size_t* numElements, size_t* allocatedSize)
{
    static const char* keywords[32] = {"auto", "break", "case", "char", "const", \
                                       "continue", "default", "do", "double", \
                                       "else", "enum", "extern", "float", "for", \
                                       "goto", "if", "int", "long", "register", \
                                       "return", "short", "signed", "sizeof", \
                                       "static", "struct", "switch", "typedef", \
                                       "union", "unsigned", "void", "volatile", \
                                       "while"
                                      };
    int i;
    
    for (i = 0; i < 32; i++) {
        if (!strcmp(toAdd.name, keywords[i])) {
            return;
        }
    }
    if (!*list) {
        *allocatedSize = 10;
        *list = calloc(*allocatedSize, sizeof(struct functionInfo));
        if (!*list) {
            printf("Failed to allocate %lu elements of %lu bytes each.\n", \
                   *allocatedSize, sizeof(struct functionInfo));
            abort();
        }
        (*list)[0].name = malloc(strlen(toAdd.name)+1);
        if (!(*list)[0].name) {
            printf("Failed to allocate %lu bytes.\n", strlen(toAdd.name)+1);
            abort();
        }
        strcpy((*list)[0].name, toAdd.name);
        (*list)[0].timesCalled = 1;
        (*list)[0].marked = 0;
        *numElements = 1;
    } else {
        char found = 0;
        unsigned int i;
        for (i = 0; i < *numElements; i++) {
            if (!strcmp((*list)[i].name, toAdd.name)) {
                found = 1;
                (*list)[i].timesCalled++;
                break;
            }
        }
        if (!found) {
            struct functionInfo* newList = calloc((*allocatedSize)+10, \
                                                  sizeof(struct functionInfo));
            if (!newList) {
                printf("Failed to allocate %lu elements of %lu bytes each.\n", \
                       (*allocatedSize)+10, sizeof(struct functionInfo));
                abort();
            }
            memcpy(newList, *list, (*allocatedSize)*sizeof(struct functionInfo));
            free(*list);
            *allocatedSize += 10;
            *list = newList;
            (*list)[*numElements].name = malloc(strlen(toAdd.name)+1);
            if (!(*list)[*numElements].name) {
                printf("Failed to allocate %lu bytes.\n", strlen(toAdd.name)+1);
                abort();
            }
            strcpy((*list)[*numElements].name, toAdd.name);
            (*list)[*numElements].timesCalled = 1;
            (*list)[*numElements].marked = 0;
            (*numElements)++;
        }
    }
}
void printList(struct functionInfo** list, size_t numElements)
{
    char maxSet = 0;
    unsigned int i;
    size_t maxIndex = 0;
    for (i = 0; i<10; i++) {
        maxSet = 0;
        size_t j;
        for (j = 0; j<numElements; j++) {
            if (!maxSet || (*list)[j].timesCalled > (*list)[maxIndex].timesCalled) {
                if (!(*list)[j].marked) {
                    maxSet = 1;
                    maxIndex = j;
                }
            }
        }
        (*list)[maxIndex].marked = 1;
        printf("%s() called %d times.\n", (*list)[maxIndex].name, \
               (*list)[maxIndex].timesCalled);
    }
}
void freeList(struct functionInfo** list, size_t numElements)
{
    size_t i;
    for (i = 0; i<numElements; i++) {
        free((*list)[i].name);
    }
    free(*list);
}
char* extractFunctionName(char* readHead)
{
    char* identifier = readHead;
    if (isalpha(*identifier) || *identifier == '_') {
        while (isalnum(*identifier) || *identifier == '_') {
            identifier++;
        }
    }
    
    char* toParen = identifier;
    if (toParen == readHead) return NULL;
    while (isspace(*toParen)) {
        toParen++;
    }
    if (*toParen != '(') return NULL;
    
    ptrdiff_t size = (ptrdiff_t)((ptrdiff_t)identifier) \
                     - ((ptrdiff_t)readHead)+1;
    char* const name = malloc(size);
    if (!name) {
        printf("Failed to allocate %lu bytes.\n", size);
        abort();
    }
    name[size-1] = '\0';
    memcpy(name, readHead, size-1);
    
    if (strcmp(name, "")) {
        return name;
    }
    free(name);
    return NULL;
}
int main(int argc, char** argv)
{
    int i;
    for (i = 1; i<argc; i++) {
        errno = 0;
        FILE* file = fopen(argv[i], "r");
        if (errno || !file) {
            printf("fopen() failed with error code \"%s\"\n", \
                   strerror(errno));
            abort();
        }
        char comment = 0;
#define DOUBLEQUOTE 1
#define SINGLEQUOTE 2
        int string = 0;
        struct functionInfo* functions = NULL;
        struct functionInfo toAdd;
        size_t numElements = 0;
        size_t allocatedSize = 0;
        struct stat metaData;
        errno = 0;
        if (fstat(fileno(file), &metaData) < 0) {
            printf("fstat() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        char* mmappedSource = (char*)mmap(NULL, metaData.st_size, PROT_READ, \
                                          MAP_PRIVATE, fileno(file), 0);
        if (errno) {
            printf("mmap() failed with error \"%s\"\n", strerror(errno));
            abort();
        }
        if (!mmappedSource) {
            printf("mmap() returned NULL.\n");
            abort();
        }
        char* readHead = mmappedSource;
        while (readHead < mmappedSource + metaData.st_size) {
            while (*readHead) {
                
                if (!string) {
                    if (*readHead == '/' && !strncmp(readHead, "", 2)) {
                        comment = 0;
                    }
                }
                
                if (!comment) {
                    if (*readHead == '"') {
                        if (!string) {
                            string = DOUBLEQUOTE;
                        } else if (string == DOUBLEQUOTE) {
                            
                            if (strncmp((readHead-1), "\\\"", 2)) {
                                string = 0;
                            }
                        }
                    }
                    if (*readHead == '\'') {
                        if (!string) {
                            string = SINGLEQUOTE;
                        } else if (string == SINGLEQUOTE) {
                            if (strncmp((readHead-1), "\\\'", 2)) {
                                string = 0;
                            }
                        }
                    }
                }
                
                if (!comment && !string) {
                    char* name = extractFunctionName(readHead);
                    
                    if (name) {
                        toAdd.name = name;
                        addToList(&functions, toAdd, &numElements, &allocatedSize);
                        readHead += strlen(name);
                    }
                    free(name);
                }
                readHead++;
            }
        }
        errno = 0;
        munmap(mmappedSource, metaData.st_size);
        if (errno) {
            printf("munmap() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        errno = 0;
        fclose(file);
        if (errno) {
            printf("fclose() returned error \"%s\"\n", strerror(errno));
            abort();
        }
        printList(&functions, numElements);
        freeList(&functions, numElements);
    }
    return 0;
}




Go: package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
    "io/ioutil"
    "os"
    "sort"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Println("usage ff <go source filename>")
        return
    }
    src, err := ioutil.ReadFile(os.Args[1])
    if err != nil {
        fmt.Println(err)
        return
    }
    fs := token.NewFileSet()
    a, err := parser.ParseFile(fs, os.Args[1], src, 0)
    if err != nil {
        fmt.Println(err)
        return
    }
    f := fs.File(a.Pos())
    m := make(map[string]int)
    ast.Inspect(a, func(n ast.Node) bool {
        if ce, ok := n.(*ast.CallExpr); ok {
            start := f.Offset(ce.Pos())
            end := f.Offset(ce.Lparen)
            m[string(src[start:end])]++
        }
        return true
    })
    cs := make(calls, 0, len(m))
    for k, v := range m {
        cs = append(cs, &call{k, v})
    }
    sort.Sort(cs)
    for i, c := range cs {
        fmt.Printf("%-20s %4d\n", c.expr, c.count)
        if i == 9 {
            break
        }
    }
}

type call struct {
    expr  string
    count int
}
type calls []*call

func (c calls) Len() int           { return len(c) }
func (c calls) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c calls) Less(i, j int) bool { return c[i].count > c[j].count }