summaryrefslogtreecommitdiff
path: root/examples/dte/tag.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/dte/tag.c')
-rw-r--r--examples/dte/tag.c322
1 files changed, 0 insertions, 322 deletions
diff --git a/examples/dte/tag.c b/examples/dte/tag.c
deleted file mode 100644
index bd030c0..0000000
--- a/examples/dte/tag.c
+++ /dev/null
@@ -1,322 +0,0 @@
-#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "tag.h"
-#include "error.h"
-#include "util/debug.h"
-#include "util/log.h"
-#include "util/path.h"
-#include "util/str-util.h"
-#include "util/xmalloc.h"
-#include "util/xreadwrite.h"
-
-static const char *current_filename; // For sorting tags
-
-static int visibility_cmp(const Tag *a, const Tag *b)
-{
- bool a_this_file = false;
- bool b_this_file = false;
-
- if (!a->local && !b->local) {
- return 0;
- }
-
- // Is tag visibility limited to the current file?
- if (a->local) {
- a_this_file = current_filename && strview_equal_cstring(&a->filename, current_filename);
- }
- if (b->local) {
- b_this_file = current_filename && strview_equal_cstring(&b->filename, current_filename);
- }
-
- // Tags local to other file than current are not interesting
- if (a->local && !a_this_file) {
- // a is not interesting
- if (b->local && !b_this_file) {
- // b is equally uninteresting
- return 0;
- }
- // b is more interesting, sort it before a
- return 1;
- }
- if (b->local && !b_this_file) {
- // b is not interesting
- return -1;
- }
-
- // Both are NOT UNinteresting
-
- if (a->local && a_this_file) {
- if (b->local && b_this_file) {
- return 0;
- }
- // a is more interesting because it is local symbol
- return -1;
- }
- if (b->local && b_this_file) {
- // b is more interesting because it is local symbol
- return 1;
- }
- return 0;
-}
-
-static int kind_cmp(const Tag *a, const Tag *b)
-{
- if (a->kind == b->kind) {
- return 0;
- }
-
- // Struct member (m) is not very interesting
- if (a->kind == 'm') {
- return 1;
- }
- if (b->kind == 'm') {
- return -1;
- }
-
- // Global variable (v) is not very interesting
- if (a->kind == 'v') {
- return 1;
- }
- if (b->kind == 'v') {
- return -1;
- }
-
- // Struct (s), union (u)
- return 0;
-}
-
-static int tag_cmp(const void *ap, const void *bp)
-{
- const Tag *const *a = ap;
- const Tag *const *b = bp;
- int r = visibility_cmp(*a, *b);
- return r ? r : kind_cmp(*a, *b);
-}
-
-// Find "tags" file from directory path and its parent directories
-static int open_tag_file(char *path)
-{
- static const char tags[] = "tags";
- while (*path) {
- size_t len = strlen(path);
- char *slash = strrchr(path, '/');
- if (slash != path + len - 1) {
- path[len++] = '/';
- }
- memcpy(path + len, tags, sizeof(tags));
- int fd = xopen(path, O_RDONLY | O_CLOEXEC, 0);
- if (fd >= 0) {
- return fd;
- }
- if (errno != ENOENT) {
- return -1;
- }
- *slash = '\0';
- }
- errno = ENOENT;
- return -1;
-}
-
-static bool tag_file_changed (
- const TagFile *tf,
- const char *filename,
- const struct stat *st
-) {
- return tf->mtime != st->st_mtime || !streq(tf->filename, filename);
-}
-
-// Note: does not free `tf` itself
-void tag_file_free(TagFile *tf)
-{
- free(tf->filename);
- free(tf->buf);
- *tf = (TagFile){.filename = NULL};
-}
-
-static bool load_tag_file(TagFile *tf)
-{
- char path[4096];
- if (unlikely(!getcwd(path, sizeof(path) - STRLEN("/tags")))) {
- LOG_ERRNO("getcwd");
- return false;
- }
-
- int fd = open_tag_file(path);
- if (fd < 0) {
- return false;
- }
-
- struct stat st;
- if (unlikely(fstat(fd, &st) != 0)) {
- LOG_ERRNO("fstat");
- xclose(fd);
- return false;
- }
-
- if (unlikely(st.st_size <= 0)) {
- xclose(fd);
- return false;
- }
-
- if (tf->filename) {
- if (!tag_file_changed(tf, path, &st)) {
- xclose(fd);
- return true;
- }
- tag_file_free(tf);
- BUG_ON(tf->filename);
- }
-
- char *buf = malloc(st.st_size);
- if (unlikely(!buf)) {
- LOG_ERRNO("malloc");
- xclose(fd);
- return false;
- }
-
- ssize_t size = xread_all(fd, buf, st.st_size);
- xclose(fd);
- if (size < 0) {
- free(buf);
- return false;
- }
-
- *tf = (TagFile) {
- .filename = xstrdup(path),
- .buf = buf,
- .size = size,
- .mtime = st.st_mtime,
- };
-
- return true;
-}
-
-static void free_tags_cb(Tag *t)
-{
- free_tag(t);
- free(t);
-}
-
-static void free_tags(PointerArray *tags)
-{
- ptr_array_free_cb(tags, FREE_FUNC(free_tags_cb));
-}
-
-// Both parameters must be absolute and clean
-static const char *path_slice_relative(const char *filename, const StringView dir)
-{
- if (strncmp(filename, dir.data, dir.length) != 0) {
- // Filename doesn't start with dir
- return NULL;
- }
- switch (filename[dir.length]) {
- case '\0': // Equal strings
- return ".";
- case '/':
- return filename + dir.length + 1;
- }
- return NULL;
-}
-
-static void tag_file_find_tags (
- const TagFile *tf,
- const char *filename,
- const StringView *name,
- PointerArray *tags
-) {
- Tag *t = xnew(Tag, 1);
- size_t pos = 0;
- while (next_tag(tf->buf, tf->size, &pos, name, true, t)) {
- ptr_array_append(tags, t);
- t = xnew(Tag, 1);
- }
- free(t);
-
- if (!filename) {
- current_filename = NULL;
- } else {
- StringView dir = path_slice_dirname(tf->filename);
- current_filename = path_slice_relative(filename, dir);
- }
- ptr_array_sort(tags, tag_cmp);
- current_filename = NULL;
-}
-
-// Note: this moves ownership of tag->pattern to the generated Message
-// and assigns NULL to the old pointer
-void add_message_for_tag(MessageArray *messages, Tag *tag, const StringView *dir)
-{
- BUG_ON(dir->length == 0);
- BUG_ON(dir->data[0] != '/');
-
- static const char prefix[] = "Tag ";
- size_t prefix_len = sizeof(prefix) - 1;
- size_t msg_len = prefix_len + tag->name.length;
- Message *m = xmalloc(sizeof(*m) + msg_len + 1);
-
- memcpy(m->msg, prefix, prefix_len);
- memcpy(m->msg + prefix_len, tag->name.data, tag->name.length);
- m->msg[msg_len] = '\0';
-
- m->loc = xnew0(FileLocation, 1);
- m->loc->filename = path_join_sv(dir, &tag->filename, false);
-
- if (tag->pattern) {
- m->loc->pattern = tag->pattern; // Message takes ownership
- tag->pattern = NULL;
- } else {
- m->loc->line = tag->lineno;
- }
-
- add_message(messages, m);
-}
-
-size_t tag_lookup(TagFile *tf, const StringView *name, const char *filename, MessageArray *messages)
-{
- clear_messages(messages);
- if (!load_tag_file(tf)) {
- error_msg("No tags file");
- return 0;
- }
-
- // Filename helps to find correct tags
- PointerArray tags = PTR_ARRAY_INIT;
- tag_file_find_tags(tf, filename, name, &tags);
-
- size_t ntags = tags.count;
- if (ntags == 0) {
- error_msg("Tag '%.*s' not found", (int)name->length, name->data);
- return 0;
- }
-
- StringView tf_dir = path_slice_dirname(tf->filename);
- for (size_t i = 0; i < ntags; i++) {
- Tag *tag = tags.ptrs[i];
- add_message_for_tag(messages, tag, &tf_dir);
- }
-
- free_tags(&tags);
- return ntags;
-}
-
-void collect_tags(TagFile *tf, PointerArray *a, const StringView *prefix)
-{
- if (!load_tag_file(tf)) {
- return;
- }
-
- Tag t;
- size_t pos = 0;
- StringView prev = STRING_VIEW_INIT;
- while (next_tag(tf->buf, tf->size, &pos, prefix, false, &t)) {
- BUG_ON(t.name.length == 0);
- if (prev.length == 0 || !strview_equal(&t.name, &prev)) {
- ptr_array_append(a, xstrcut(t.name.data, t.name.length));
- prev = t.name;
- }
- free_tag(&t);
- }
-}