tapas

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

tapas.c (13427B)


      1 /*
      2  * MIT License
      3  *
      4  * © 2019 Chris Noxz <chris@noxz.tech>
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 
     28 #include "config.h"
     29 
     30 #define BIB_START   ".]<\n"
     31 #define BIB_END     ".]>\n"
     32 #define REF_START   ".]-\n"
     33 #define REF_END     ".][ %d"
     34 #define REF_ATTR    ".ds [%c"
     35 #define STR_HE      ".ds APA_HE "
     36 #define STR_AN      ".ds APA_AN "
     37 #define STR_IN      ".ds APA_IN "
     38 #define STR_FR      ".ds APA_FR "
     39 #define STR_RE      ".ds APA_RE "
     40 #define STR_MS      ".ds APA_MS "
     41 #define STR_HC      ".ds APA_HC "
     42 
     43 typedef struct {
     44     char author[BUF_SIZE];
     45     char title[BUF_SIZE];
     46     char book_title[BUF_SIZE];
     47     char report_number[BUF_SIZE];
     48     char journal_name[BUF_SIZE];
     49     char editor[BUF_SIZE];
     50     char edition[BUF_SIZE];
     51     char volume[BUF_SIZE];
     52     char journal_number[BUF_SIZE];
     53     char series[BUF_SIZE];
     54     char city[BUF_SIZE];
     55     char publisher[BUF_SIZE];
     56     char publication_date[BUF_SIZE];
     57     char page_number[BUF_SIZE];
     58     char gov_number[BUF_SIZE];
     59     char other[BUF_SIZE];
     60     char keywords[BUF_SIZE];
     61     char original_pub_date[BUF_SIZE];
     62     char additions[BUF_SIZE];
     63     char reprint_title[BUF_SIZE];
     64     char translator[BUF_SIZE];
     65     char translator_editor[BUF_SIZE];
     66     char site_name[BUF_SIZE];
     67     char site_content[BUF_SIZE];
     68     char organization[BUF_SIZE];
     69     char url[BUF_SIZE];
     70     char url_raw[BUF_SIZE];
     71 } Referece;
     72 
     73 struct State {
     74     int inbib;
     75     Referece *ref;
     76 };
     77 struct State state;
     78 
     79 struct Settings {
     80     int macroset;
     81     char heading[BUF_SIZE];
     82     char and[BUF_SIZE];
     83     char in[BUF_SIZE];
     84     char from[BUF_SIZE];
     85     char retrieved[BUF_SIZE];
     86     char hrefcolor[BUF_SIZE];
     87     char ms[BUF_SIZE];
     88 };
     89 struct Settings settings;
     90 
     91 enum macrosets {
     92     ms_ms,
     93 //    ms_mom,
     94     /* add more macro sets here... */
     95 };
     96 
     97 static void trim(char*);
     98 static int readstr(const char*, const char*, char*, int);
     99 static int readattr(const char*, const char*, char*, char*, int);
    100 static void setattr(char, char*);
    101 static void printref(int);
    102 static int matchcount(char*, const char*);
    103 static void findreplace(char*, const char*, const char*, int);
    104 static void wordsym();
    105 static void format_other();
    106 static void format_article();
    107 static void format_book();
    108 static void format_article_in_book();
    109 static int loadstr(char*);
    110 static void beginbib(void);
    111 
    112 void
    113 trim(char *source)
    114 {
    115     char *ptr = source;
    116 
    117     while (*ptr == ' ')
    118         ptr++;
    119     memmove(source, ptr, strlen(ptr) + 1);
    120 
    121     ptr = source + strlen(source) - 1;
    122 
    123     while (*ptr == ' ')
    124         ptr--;
    125     *(ptr + 1) = 0;
    126 
    127     /* also, remove surounding quotes if existing */
    128     if (source[0] == '"' && source[strlen(source) - 1] == '"') {
    129         ptr = source + strlen(source) - 2;
    130         memmove(source, source + 1, strlen(source));
    131         *ptr = 0;
    132     }
    133 }
    134 
    135 int
    136 readstr(const char *src, const char *pre, char *str, int length)
    137 {
    138     int c = 0;
    139     const char *p;
    140 
    141     if (strncmp(src, pre, strlen(pre)) != 0)
    142         return 0;
    143 
    144     memset(str, 0, length);
    145     p = (src + strlen(pre));
    146 
    147     while (*p != '\n' && c < length)
    148         str[c++] = *p++;
    149 
    150     return 1;
    151 }
    152 
    153 int
    154 readattr(const char *src, const char *fmt, char *t, char *val, int length)
    155 {
    156     int c = 0;
    157     const char *p;
    158 
    159     if (sscanf(src, fmt, t) == 0)
    160         return 0;
    161 
    162     memset(val, 0, length);
    163     p = (src + strlen(fmt));
    164 
    165     while (*p != '\n' && c < length)
    166         val[c++] = *p++;
    167 
    168     return 1;
    169 }
    170 
    171 void
    172 setattr(char type, char *val)
    173 {
    174     switch (type) {
    175     case 'A': strncpy(state.ref->author, val, BUF_SIZE); break;
    176     case 'T': strncpy(state.ref->title, val, BUF_SIZE); break;
    177     case 'B': strncpy(state.ref->book_title, val, BUF_SIZE); break;
    178     case 'R': strncpy(state.ref->report_number, val, BUF_SIZE); break;
    179     case 'J': strncpy(state.ref->journal_name, val, BUF_SIZE); break;
    180     case 'E': strncpy(state.ref->editor, val, BUF_SIZE); break;
    181     case 'e': strncpy(state.ref->edition, val, BUF_SIZE); break;
    182     case 'V': strncpy(state.ref->volume, val, BUF_SIZE); break;
    183     case 'N': strncpy(state.ref->journal_number, val, BUF_SIZE); break;
    184     case 'S': strncpy(state.ref->series, val, BUF_SIZE); break;
    185     case 'C': strncpy(state.ref->city, val, BUF_SIZE); break;
    186     case 'I': strncpy(state.ref->publisher, val, BUF_SIZE); break;
    187     case 'D': strncpy(state.ref->publication_date, val, BUF_SIZE); break;
    188     case 'P': strncpy(state.ref->page_number, val, BUF_SIZE); break;
    189     case 'G': strncpy(state.ref->gov_number, val, BUF_SIZE); break;
    190     case 'O': strncpy(state.ref->other, val, BUF_SIZE); break;
    191     case 'K': strncpy(state.ref->keywords, val, BUF_SIZE); break;
    192     case 'd': strncpy(state.ref->original_pub_date, val, BUF_SIZE); break;
    193     case 'a': strncpy(state.ref->additions, val, BUF_SIZE); break;
    194     case 't': strncpy(state.ref->reprint_title, val, BUF_SIZE); break;
    195     case 'l': strncpy(state.ref->translator, val, BUF_SIZE); break;
    196     case 'r': strncpy(state.ref->translator_editor, val, BUF_SIZE); break;
    197     case 's': strncpy(state.ref->site_name, val, BUF_SIZE); break;
    198     case 'c': strncpy(state.ref->site_content, val, BUF_SIZE); break;
    199     case 'o': strncpy(state.ref->organization, val, BUF_SIZE); break;
    200     case 'u': strncpy(state.ref->url, val, BUF_SIZE);
    201               strncpy(state.ref->url_raw, val, BUF_SIZE); break;
    202     }
    203 }
    204 
    205 void
    206 printref(int type)
    207 {
    208     wordsym();
    209     switch (type) {
    210     case 0: format_other(); break;
    211     case 1: format_article(); break;
    212     case 2: format_book(); break;
    213     case 3: format_article_in_book(); break;
    214     }
    215 
    216     free(state.ref);
    217     state.ref = NULL;
    218 }
    219 
    220 int
    221 matchcount(char *source, const char *find)
    222 {
    223     int i, j, m, c;
    224     int slen = strlen(source),
    225         flen = strlen(find);
    226 
    227     for (i = 0, c = 0; i <= slen - flen; i++) {
    228         for (j = 0, m = 1; j < flen; j++) {
    229             if (source[i + j] != find[j] && (m = 0) == 0)
    230                 break;
    231         }
    232         if (m == 1)
    233             c++;
    234     }
    235     return c;
    236 }
    237 
    238 void
    239 findreplace(char *source, const char *find, const char *replace, int start)
    240 {
    241     char *dest;
    242     char *ptr;
    243     int count = matchcount(source + start, find);
    244     int size = (strlen(source) + (strlen(replace) - strlen(find)) * count + 1);
    245     int i;
    246 
    247     dest = malloc(size);
    248     strcpy(dest, source);
    249     ptr = dest + start;
    250 
    251     for (i = 0; i < count; i++) {
    252         if ((ptr = strstr(ptr, find))) {
    253             memmove(
    254                 ptr + strlen(replace),
    255                 ptr + strlen(find),
    256                 strlen(ptr+strlen(find)) + 1
    257             );
    258             strncpy(ptr, replace, strlen(replace));
    259         }
    260         ptr++;
    261     }
    262 
    263     *(source + strlen(dest)) = 0;
    264     strncpy(source, dest, strlen(dest));
    265 }
    266 
    267 void
    268 wordsym()
    269 {
    270     char str_and[BUF_SIZE];
    271 
    272     snprintf(str_and, BUF_SIZE, " %s ", settings.and);
    273 
    274     if (state.ref->author[0])
    275         findreplace(state.ref->author, " and ", str_and, 0);
    276     if (state.ref->editor[0])
    277         findreplace(state.ref->editor, " and ", str_and, 0);
    278 }
    279 
    280 void /* TODO :: Check type of other, website etc. */
    281 format_other()
    282 {
    283     char *proto;
    284 
    285     if (!state.ref->author
    286         || !state.ref->publication_date
    287         || !state.ref->additions    /* access date */
    288         || !state.ref->site_name
    289         || !state.ref->url)
    290         return;
    291 
    292     proto = strstr(state.ref->url, "://");
    293     findreplace(state.ref->url, "/", "/\\:\\%",
    294         proto ? (proto - state.ref->url) + 3: 0);
    295     switch (settings.macroset) {
    296     case ms_ms:
    297         fprintf(stdout, ".rm PDFHREF.TEXT.COLOUR\n");
    298         fprintf(stdout, ".ds PDFHREF.TEXT.COLOUR apa:h\n");
    299         fprintf(stdout,
    300             "%s%s\n.XP\n%s (%s). \n.I \"%s\" \".\"\n%s %s, %s \n"
    301             ".pdfhref W -D \"%s\" -A \"\\c\" -- \"%s\"\n.\n",
    302             ".defcolor apa:h ",
    303             settings.hrefcolor,
    304             state.ref->author,
    305             state.ref->publication_date,
    306             state.ref->site_name,
    307             settings.retrieved,
    308             state.ref->additions,
    309             settings.from,
    310             state.ref->url_raw,
    311             state.ref->url
    312         );
    313         fprintf(stdout, ".als PDFHREF.TEXT.COLOUR PDFHREF.TEXT.COLOR\n"); break;
    314         break;
    315     }
    316 }
    317 
    318 void
    319 format_article()
    320 {
    321     if (!state.ref->author
    322         || !state.ref->publication_date
    323         || !state.ref->title
    324         || !state.ref->journal_name
    325         || !state.ref->journal_number
    326         || !state.ref->page_number)
    327         return;
    328     switch (settings.macroset) {
    329     case ms_ms:
    330         fprintf(stdout,
    331             ".XP\n%s (%s). %s.\n.I \"%s\" \", %s, %s.\"\n",
    332             state.ref->author,
    333             state.ref->publication_date,
    334             state.ref->title,
    335             state.ref->journal_name,
    336             state.ref->journal_number,
    337             state.ref->page_number
    338         ); break;
    339     }
    340 }
    341 
    342 void
    343 format_book()
    344 {
    345     if (!state.ref->author
    346         || !state.ref->publication_date
    347         || !state.ref->title
    348         || !state.ref->city
    349         || !state.ref->publisher)
    350         return;
    351     switch (settings.macroset) {
    352     case ms_ms:
    353     fprintf(stdout,
    354         ".XP\n%s (%s).\n.I \"%s\" .\n%s: %s.\n",
    355         state.ref->author,
    356         state.ref->publication_date,
    357         state.ref->title,
    358         state.ref->city,
    359         state.ref->publisher
    360         ); break;
    361     }
    362 }
    363 
    364 void
    365 format_article_in_book()
    366 {
    367     if (!state.ref->author
    368         || !state.ref->publication_date
    369         || !state.ref->title
    370         || !state.ref->editor
    371         || !state.ref->book_title
    372         || !state.ref->page_number
    373         || !state.ref->city
    374         || !state.ref->publisher)
    375         return;
    376     switch (settings.macroset) {
    377     case ms_ms:
    378     fprintf(stdout,
    379         ".XP\n%s (%s). %s. %s %s, \n.I \"%s\" \" (s. %s).\"\n%s: %s.\n",
    380         state.ref->author,
    381         state.ref->publication_date,
    382         state.ref->title,
    383         settings.in,
    384         state.ref->editor,
    385         state.ref->book_title,
    386         state.ref->page_number,
    387         state.ref->city,
    388         state.ref->publisher
    389         ); break;
    390     }
    391 }
    392 
    393 int
    394 loadstr(char *line)
    395 {
    396     if (readstr(line, STR_HE, settings.heading, BUF_SIZE))
    397         trim(settings.heading);
    398     else if (readstr(line, STR_AN, settings.and, BUF_SIZE))
    399         trim(settings.and);
    400     else if (readstr(line, STR_IN, settings.in, BUF_SIZE))
    401         trim(settings.in);
    402     else if (readstr(line, STR_FR, settings.from, BUF_SIZE))
    403         trim(settings.from);
    404     else if (readstr(line, STR_RE, settings.retrieved, BUF_SIZE))
    405         trim(settings.retrieved);
    406     else if (readstr(line, STR_HC, settings.hrefcolor, BUF_SIZE))
    407         trim(settings.hrefcolor);
    408     else if (readstr(line, STR_MS, settings.ms, BUF_SIZE))
    409         trim(settings.ms);
    410     else
    411         return 0;
    412     return 1;
    413 }
    414 
    415 void
    416 beginbib(void)
    417 {
    418     state.inbib = 1;
    419 
    420     if (strcmp(settings.ms, "ms"))
    421         settings.macroset = ms_ms;
    422     else
    423         settings.macroset = ms_ms;
    424 
    425     switch (settings.macroset) {
    426     case ms_ms:
    427         fprintf(stdout, ".SH\n%s\n", settings.heading); break;
    428     }
    429 }
    430 
    431 int
    432 main(int arc, char *argv[])
    433 {
    434     char type, val[BUF_SIZE];
    435     char *line;
    436     size_t size;
    437     int reftype;
    438 
    439     /* default settings */
    440     strcpy(settings.heading, "References");
    441     strcpy(settings.and, "&");
    442     strcpy(settings.in, "In");
    443     strcpy(settings.from, "from");
    444     strcpy(settings.retrieved, "Retrieved");
    445     strcpy(settings.hrefcolor, "rgb 0f 0.325f 0.525f");
    446     strcpy(settings.ms, "");
    447 
    448     /* default state */
    449     state.inbib = 0;
    450     state.ref = NULL;
    451 
    452     /* handle lines */
    453     while (getline(&line, &size, stdin) != EOF) {
    454         /* handle strings */
    455         if (loadstr(line))
    456             continue;
    457 
    458         /* handle states */
    459         if (!state.inbib && strcmp(line, BIB_START) == 0) {
    460             beginbib();
    461             continue;
    462         } else if (state.inbib && strcmp(line, BIB_END) == 0) {
    463             state.inbib = 0;
    464             continue;
    465         }
    466 
    467         /* print line if not in bibliography */
    468         if (!state.inbib) {
    469             printf("%s", line);
    470             continue;
    471         }
    472 
    473         /* handle bibliography */
    474         if (!state.ref && strcmp(line, REF_START) == 0)
    475             state.ref = (Referece*)calloc(1, sizeof(Referece));
    476         else if (state.ref && readattr(line, REF_ATTR, &type, val, BUF_SIZE))
    477             setattr(type, val);
    478         else if (state.ref && sscanf(line, REF_END, &reftype) == 1)
    479             printref(reftype);
    480     }
    481     return 0;
    482 }