tapas.c (13575B)
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 if (!state.ref->other) 329 strncpy(state.ref->other, "", BUF_SIZE); 330 switch (settings.macroset) { 331 case ms_ms: 332 fprintf(stdout, 333 ".XP\n%s (%s). %s.\n.I \"%s\" \", %s, %s. %s\"\n", 334 state.ref->author, 335 state.ref->publication_date, 336 state.ref->title, 337 state.ref->journal_name, 338 state.ref->journal_number, 339 state.ref->page_number, 340 state.ref->other /* assume doi to be stored in other */ 341 ); break; 342 } 343 } 344 345 void 346 format_book() 347 { 348 if (!state.ref->author 349 || !state.ref->publication_date 350 || !state.ref->title 351 || !state.ref->city 352 || !state.ref->publisher) 353 return; 354 switch (settings.macroset) { 355 case ms_ms: 356 fprintf(stdout, 357 ".XP\n%s (%s).\n.I \"%s\" .\n%s: %s.\n", 358 state.ref->author, 359 state.ref->publication_date, 360 state.ref->title, 361 state.ref->city, 362 state.ref->publisher 363 ); break; 364 } 365 } 366 367 void 368 format_article_in_book() 369 { 370 if (!state.ref->author 371 || !state.ref->publication_date 372 || !state.ref->title 373 || !state.ref->editor 374 || !state.ref->book_title 375 || !state.ref->page_number 376 || !state.ref->city 377 || !state.ref->publisher) 378 return; 379 switch (settings.macroset) { 380 case ms_ms: 381 fprintf(stdout, 382 ".XP\n%s (%s). %s. %s %s, \n.I \"%s\" \" (s. %s).\"\n%s: %s.\n", 383 state.ref->author, 384 state.ref->publication_date, 385 state.ref->title, 386 settings.in, 387 state.ref->editor, 388 state.ref->book_title, 389 state.ref->page_number, 390 state.ref->city, 391 state.ref->publisher 392 ); break; 393 } 394 } 395 396 int 397 loadstr(char *line) 398 { 399 if (readstr(line, STR_HE, settings.heading, BUF_SIZE)) 400 trim(settings.heading); 401 else if (readstr(line, STR_AN, settings.and, BUF_SIZE)) 402 trim(settings.and); 403 else if (readstr(line, STR_IN, settings.in, BUF_SIZE)) 404 trim(settings.in); 405 else if (readstr(line, STR_FR, settings.from, BUF_SIZE)) 406 trim(settings.from); 407 else if (readstr(line, STR_RE, settings.retrieved, BUF_SIZE)) 408 trim(settings.retrieved); 409 else if (readstr(line, STR_HC, settings.hrefcolor, BUF_SIZE)) 410 trim(settings.hrefcolor); 411 else if (readstr(line, STR_MS, settings.ms, BUF_SIZE)) 412 trim(settings.ms); 413 else 414 return 0; 415 return 1; 416 } 417 418 void 419 beginbib(void) 420 { 421 state.inbib = 1; 422 423 if (strcmp(settings.ms, "ms")) 424 settings.macroset = ms_ms; 425 else 426 settings.macroset = ms_ms; 427 428 switch (settings.macroset) { 429 case ms_ms: 430 fprintf(stdout, ".SH\n%s\n", settings.heading); break; 431 } 432 } 433 434 int 435 main(int arc, char *argv[]) 436 { 437 char type, val[BUF_SIZE]; 438 char *line; 439 size_t size; 440 int reftype; 441 442 /* default settings */ 443 strcpy(settings.heading, "References"); 444 strcpy(settings.and, "&"); 445 strcpy(settings.in, "In"); 446 strcpy(settings.from, "from"); 447 strcpy(settings.retrieved, "Retrieved"); 448 strcpy(settings.hrefcolor, "rgb 0f 0.325f 0.525f"); 449 strcpy(settings.ms, ""); 450 451 /* default state */ 452 state.inbib = 0; 453 state.ref = NULL; 454 455 /* handle lines */ 456 while (getline(&line, &size, stdin) != EOF) { 457 /* handle strings */ 458 if (loadstr(line)) 459 continue; 460 461 /* handle states */ 462 if (!state.inbib && strcmp(line, BIB_START) == 0) { 463 beginbib(); 464 continue; 465 } else if (state.inbib && strcmp(line, BIB_END) == 0) { 466 state.inbib = 0; 467 continue; 468 } 469 470 /* print line if not in bibliography */ 471 if (!state.inbib) { 472 printf("%s", line); 473 continue; 474 } 475 476 /* handle bibliography */ 477 if (!state.ref && strcmp(line, REF_START) == 0) 478 state.ref = (Referece*)calloc(1, sizeof(Referece)); 479 else if (state.ref && readattr(line, REF_ATTR, &type, val, BUF_SIZE)) 480 setattr(type, val); 481 else if (state.ref && sscanf(line, REF_END, &reftype) == 1) 482 printref(reftype); 483 } 484 return 0; 485 }