tapas

[discontinued] A small program used for compiling refer output into the APA reference format.
git clone https://noxz.tech/git/tapas.git
Log | Files | README | LICENSE

commit: ea3d5264debd829e18beba3670306acc184fc6ab
parent: 
author: Chris Noxz <chris@noxz.tech>
date:   Fri, 8 Nov 2019 19:35:49 +0100
Initial commit (be aware, quick hack)
A.gitignore3+
ALICENSE21++
AMakefile51++++
AREADME.md31++
Aconfig.def.h10+
Aconfig.mk15+
Atapas.c311++++++++++++++++++++
7 files changed, 442 insertions(+)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,3 @@
+tapas
+config.h
+*.o
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+© 2019 Chris Noxz <chris@noxz.tech>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,51 @@
+.POSIX:
+
+include config.mk
+
+SRC = tapas.c
+OBJ = $(SRC:.c=.o)
+
+all: options tapas
+
+options:
+	@echo tapas build options:
+	@echo "VERSION = $(VERSION)"
+	@echo "CFLAGS  = $(STCFLAGS)"
+	@echo "LDFLAGS = $(STLDFLAGS)"
+	@echo "CC      = $(CC)"
+
+.c.o:
+	@echo CC $<
+	@$(CC) $(STCFLAGS) -c $<
+
+${OBJ}: config.h config.mk
+
+config.h:
+	@echo creating $@ from config.def.h
+	@cp config.def.h $@
+
+tapas: $(OBJ)
+	@echo CC -o $@
+	@$(CC) -o $@ $(OBJ) $(STLDFLAGS)
+
+clean:
+	@echo cleaning
+	@rm -f tapas $(OBJ)
+
+install: tapas
+	@echo installing executables to ${PREFIX}/bin
+	@mkdir -p ${PREFIX}/bin
+	@cp -f tapas ${PREFIX}/bin
+	@chmod 755 ${PREFIX}/bin/tapas
+#	@echo installing manual page to ${MANPREFIX}/man1
+#	@mkdir -p ${MANPREFIX}/man1
+#	@cp -f tapas.1 ${MANPREFIX}/man1
+#	@chmod 644 ${MANPREFIX}/man1/tapas.1
+
+uninstall:
+	@echo removing executable files from ${PREFIX}/bin
+	@rm -f ${PREFIX}/bin/tapas
+#	@echo removing manual page from ${MANPREFIX}/man1
+#	@rm -f ${MANPREFIX}/man1/tapas.1
+
+.PHONY: all options clean install uninstall
diff --git a/README.md b/README.md
@@ -0,0 +1,31 @@
+tapas
+=====
+The name stands for **t**o **APA**, and the *s* is for added deliciousness.
+It's a small program used for compiling refer output into the APA reference
+format.
+
+The program reads refer output from *stdin* and prints the compiled result to
+*stdout*.
+
+Installation
+------------
+Edit config.mk to match your local setup (tapas is installed into the
+/usr/local namespace by default), then simply enter the following command to
+install (if necessary as root):
+
+    make clean install
+
+Customization
+-------------
+tapas can be customized by creating a custom config.h and (re)compiling the
+source code.
+
+Usage
+-----
+Tapas is intended to run in a pipe chain directly after refer, like so:
+
+    ... | refer | tapas | ... | troff
+
+License
+-------
+The program is licensed under the MIT license.
diff --git a/config.def.h b/config.def.h
@@ -0,0 +1,10 @@
+#define BUF_SIZE    128
+#define BIB_START   ".]<\n"
+#define BIB_END     ".]>\n"
+#define REF_START   ".]-\n"
+#define REF_END     ".][ %d"
+#define REF_ATTR    ".ds [%c %127[^\n]"
+#define STR_HE      ".ds APA_HE %127[^\n]"
+#define STR_AN      ".ds APA_AN %127[^\n]"
+#define STR_IN      ".ds APA_IN %127[^\n]"
+#define STR_MS      ".ds APA_MS %127[^\n]"
diff --git a/config.mk b/config.mk
@@ -0,0 +1,15 @@
+# tapas version
+VERSION = 0.0.1
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+
+# flags
+CFLAGS = -Wall -Wno-format-truncation -pedantic -std=c99
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+STCFLAGS = $(CPPFLAGS) $(CFLAGS)
+STLDFLAGS = $(LDFLAGS)
+
+# compiler and linker
+CC = gcc
diff --git a/tapas.c b/tapas.c
@@ -0,0 +1,311 @@
+/*
+ * MIT License
+ *
+ * © 2019 Chris Noxz <chris@noxz.tech>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+struct Settings {
+    char heading[BUF_SIZE];
+    char and[BUF_SIZE];
+    char in[BUF_SIZE];
+    char ms[BUF_SIZE];
+};
+struct Settings settings;
+
+enum macrosets {
+    ms_ms,
+//    ms_mom,
+    /* add more macro sets here... */
+};
+
+typedef struct {
+    char author[BUF_SIZE];
+    char title[BUF_SIZE];
+    char book_title[BUF_SIZE];
+    char report_number[BUF_SIZE];
+    char journal_name[BUF_SIZE];
+    char editor[BUF_SIZE];
+    char edition[BUF_SIZE];
+    char volume[BUF_SIZE];
+    char journal_number[BUF_SIZE];
+    char series[BUF_SIZE];
+    char city[BUF_SIZE];
+    char publisher[BUF_SIZE];
+    char publication_date[BUF_SIZE];
+    char page_number[BUF_SIZE];
+    char gov_number[BUF_SIZE];
+    char other[BUF_SIZE];
+    char keywords[BUF_SIZE];
+    char original_pub_date[BUF_SIZE];
+    char additions[BUF_SIZE];
+    char reprint_title[BUF_SIZE];
+    char translator[BUF_SIZE];
+    char translator_editor[BUF_SIZE];
+    char site_name[BUF_SIZE];
+    char site_content[BUF_SIZE];
+    char organization[BUF_SIZE];
+    char url[BUF_SIZE];
+} Referece;
+
+void
+trim(char *source)
+{
+    char *ptr = source;
+
+    while (*ptr == ' ')
+        ptr++;
+    memmove(source, ptr, strlen(ptr) + 1);
+
+    ptr = source + strlen(source) - 1;
+
+    while (*ptr == ' ')
+        ptr--;
+    *(ptr + 1) = 0;
+
+    /* also, remove surounding quotes if existing */
+    if (source[0] == '"' && source[strlen(source) - 1] == '"') {
+        ptr = source + strlen(source) - 2;
+        memmove(source, source + 1, strlen(source));
+        *ptr = 0;
+    }
+}
+
+void
+findreplace(char *source, const char *find, const char *replace)
+{
+    char *dest = malloc(strlen(source) - strlen(find) + strlen(replace) + 1);
+    char *ptr;
+
+    strcpy(dest, source);
+
+    ptr = strstr(dest, find);
+    if (ptr) {
+        memmove(
+            ptr + strlen(replace),
+            ptr + strlen(find),
+            strlen(ptr+strlen(find)) + 1
+        );
+        strncpy(ptr, replace, strlen(replace));
+    }
+
+    *(source + strlen(dest)) = 0;
+    strncpy(source, dest, strlen(dest));
+}
+
+void
+wordsym(Referece *ref)
+{
+    char str_and[BUF_SIZE];
+
+    snprintf(str_and, BUF_SIZE, " %s ", settings.and);
+
+    if (ref->author[0])
+        findreplace(ref->author, " and ", str_and);
+    if (ref->editor[0])
+        findreplace(ref->editor, " and ", str_and);
+}
+
+void
+format_article(Referece *ref, int macroset)
+{
+    if (!ref->author
+        || !ref->publication_date
+        || !ref->title
+        || !ref->journal_name
+        || !ref->journal_number
+        || !ref->city
+        || !ref->publisher)
+        return;
+    switch (macroset) {
+    case ms_ms:
+        fprintf(stdout,
+            ".XP\n%s (%s). \n.I \"%s\" \" (%s, %s).\"\n%s: %s.\n",
+            ref->author,
+            ref->publication_date,
+            ref->title,
+            ref->journal_name,
+            ref->journal_number,
+            ref->city,
+            ref->publisher
+        ); break;
+    }
+}
+
+void
+format_book(Referece *ref, int macroset)
+{
+    if (!ref->author
+        || !ref->publication_date
+        || !ref->title
+        || !ref->city
+        || !ref->publisher)
+        return;
+    switch (macroset) {
+    case ms_ms:
+    fprintf(stdout,
+        ".XP\n%s (%s).\n.I \"%s\" .\n%s: %s.\n",
+        ref->author,
+        ref->publication_date,
+        ref->title,
+        ref->city,
+        ref->publisher
+        ); break;
+    }
+}
+
+void
+format_article_in_book(Referece *ref, int macroset)
+{
+    if (!ref->author
+        || !ref->publication_date
+        || !ref->title
+        || !ref->editor
+        || !ref->book_title
+        || !ref->page_number
+        || !ref->city
+        || !ref->publisher)
+        return;
+    switch (macroset) {
+    case ms_ms:
+    fprintf(stdout,
+        ".XP\n%s (%s). %s. %s %s, \n.I \"%s\" \" (s. %s).\"\n%s: %s.\n",
+        ref->author,
+        ref->publication_date,
+        ref->title,
+        settings.in,
+        ref->editor,
+        ref->book_title,
+        ref->page_number,
+        ref->city,
+        ref->publisher
+        ); break;
+    }
+}
+
+int
+loadstr(char *line)
+{
+    if (sscanf(line, STR_HE, &settings.heading) == 1)
+        trim(settings.heading);
+    else if (sscanf(line, STR_AN, &settings.and) == 1)
+        trim(settings.and);
+    else if (sscanf(line, STR_IN, &settings.in) == 1)
+        trim(settings.in);
+    else if (sscanf(line, STR_MS, &settings.ms) == 1)
+        trim(settings.ms);
+    else
+        return 0;
+    return 1;
+}
+
+int
+main(int arc, char *argv[])
+{
+    int inbib = 0;
+    int macroset = ms_ms;
+    int reftype;
+    char atype;
+    char aval[BUF_SIZE];
+    size_t size;
+    char *line;
+    Referece *ref = NULL;
+
+    /* default settings */
+    strcpy(settings.heading, "References");
+    strcpy(settings.and, "&");
+    strcpy(settings.in, "In");
+    strcpy(settings.ms, "");
+
+    while (getline(&line, &size, stdin) != EOF) {
+        if (loadstr(line))
+            continue;
+        if (!inbib && strcmp(line, BIB_START) == 0) {
+            inbib = 1;
+            switch (macroset) {
+            case ms_ms:
+                fprintf(stdout, ".SH\n%s\n", settings.heading); break;
+            } continue;
+        }
+        if (inbib && strcmp(line, BIB_END) == 0) {
+            inbib = 0;
+            if (strcmp(settings.ms, "ms"))
+                macroset = ms_ms;
+            //else if (strcmp(settings.ms, "mom"))
+            //    macroset = ms_mom;
+            /* add more macro sets here... */
+            else
+                macroset = ms_ms;
+            continue;
+        }
+        if (inbib) {
+            if (!ref && strcmp(line, REF_START) == 0) {
+                ref = (Referece*)calloc(1, sizeof(Referece));
+            } else if (ref && sscanf(line, REF_ATTR, &atype, &aval) == 2) {
+                switch (atype) {
+                case 'A': strcpy(ref->author, aval); break;
+                case 'T': strcpy(ref->title, aval); break;
+                case 'B': strcpy(ref->book_title, aval); break;
+                case 'R': strcpy(ref->report_number, aval); break;
+                case 'J': strcpy(ref->journal_name, aval); break;
+                case 'E': strcpy(ref->editor, aval); break;
+                case 'e': strcpy(ref->edition, aval); break;
+                case 'V': strcpy(ref->volume, aval); break;
+                case 'N': strcpy(ref->journal_number, aval); break;
+                case 'S': strcpy(ref->series, aval); break;
+                case 'C': strcpy(ref->city, aval); break;
+                case 'I': strcpy(ref->publisher, aval); break;
+                case 'D': strcpy(ref->publication_date, aval); break;
+                case 'P': strcpy(ref->page_number, aval); break;
+                case 'G': strcpy(ref->gov_number, aval); break;
+                case 'O': strcpy(ref->other, aval); break;
+                case 'K': strcpy(ref->keywords, aval); break;
+                case 'd': strcpy(ref->original_pub_date, aval); break;
+                case 'a': strcpy(ref->additions, aval); break;
+                case 't': strcpy(ref->reprint_title, aval); break;
+                case 'l': strcpy(ref->translator, aval); break;
+                case 'r': strcpy(ref->translator_editor, aval); break;
+                case 's': strcpy(ref->site_name, aval); break;
+                case 'c': strcpy(ref->site_content, aval); break;
+                case 'o': strcpy(ref->organization, aval); break;
+                case 'u': strcpy(ref->url, aval); break;
+                default: continue;
+                }
+            } else if (ref && sscanf(line, REF_END, &reftype) == 1) {
+                wordsym(ref);
+                switch (reftype) {
+                case 1: format_article(ref, macroset); break;
+                case 2: format_book(ref, macroset); break;
+                case 3: format_article_in_book(ref, macroset); break;
+                }
+                free(ref);
+                ref = NULL;
+            }
+            continue;
+        }
+        printf("%s", line);
+    }
+    return 0;
+}