#include <locale.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#define BUF BUFSIZ
#define MXFILES 16
char tempfile[32];
int tmpfd = -1;
char *keystr = "AD";
int multauth = 0;
int oneauth;
static int article(char *);
static void deliver(FILE *[], FILE *);
static int endcomma(char *);
static void error(char *);
static void eval(char []);
static void parse(char [], char fld[][BUF]);
static void sortbib(FILE *, FILE *, int);
static void onintr(void);
int
main(int argc, char *argv[])
{
FILE *fp[MXFILES], *tfp;
int i;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
if (argc == 1) {
puts(gettext("Usage: sortbib [-sKEYS] database [...]\n\
\t-s: sort by fields in KEYS (default is AD)"));
exit(1);
}
if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 's') {
if (argv[1][2] != '\0')
keystr = argv[1] + 2;
eval(keystr);
argv++; argc--;
}
if (argc > MXFILES+1) {
fprintf(stderr,
gettext("sortbib: More than %d databases specified\n"),
MXFILES);
exit(1);
}
for (i = 1; i < argc; i++)
if ((fp[i-1] = fopen(argv[i], "r")) == NULL)
error(argv[i]);
strcpy(tempfile, "/tmp/SbibXXXXXX");
if ((tmpfd = mkstemp(tempfile)) == -1)
error(tempfile);
(void) close(tmpfd);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, (void(*)())onintr);
if ((tfp = fopen(tempfile, "w")) == NULL) {
(void) unlink(tempfile);
error(tempfile);
}
for (i = 0; i < argc-1; i++)
sortbib(fp[i], tfp, i);
fclose(tfp);
deliver(fp, tfp);
(void) unlink(tempfile);
return (0);
}
int rsmode = 0;
static void
sortbib(FILE *fp, FILE *tfp, int i)
{
long offset, lastoffset = 0, ftell();
int length, newrec, recno = 0;
char line[BUF], fld[4][BUF];
while (offset = ftell(fp), fgets(line, BUF, fp)) {
if (recno == 0)
newrec = 1;
if (line[0] == '\n') {
if (!rsmode)
rsmode = 1;
if (rsmode == 1)
newrec = 1;
}
if (line[0] == '.' && line[1] == '[') {
if (!rsmode)
rsmode = 2;
if (rsmode == 2)
newrec = 1;
}
if (newrec) {
newrec = 0;
length = offset - lastoffset;
if (length > BUF*8) {
fprintf(stderr,
gettext("sortbib: record %d longer than %d "
"(%d)\n"), recno, BUF*8, length);
(void) unlink(tempfile);
exit(1);
}
if (recno++) {
fprintf(tfp, "%d %d %d : %s %s %s %s\n",
i, lastoffset, length,
fld[0], fld[1], fld[2], fld[3]);
if (ferror(tfp)) {
(void) unlink(tempfile);
error(tempfile);
}
}
*fld[0] = *fld[1] = *fld[2] = *fld[3] = '\0';
oneauth = 0;
lastoffset = offset;
}
if (line[0] == '%')
parse(line, fld);
}
offset = ftell(fp);
length = offset - lastoffset;
if (length > BUF*8) {
fprintf(stderr,
gettext("sortbib: record %d longer than %d (%d)\n"),
recno, BUF*8, length);
(void) unlink(tempfile);
exit(1);
}
if (line[0] != '\n') {
fprintf(tfp, "%d %d %d : %s %s %s %s\n",
i, lastoffset, length, fld[0], fld[1], fld[2], fld[3]);
if (ferror(tfp)) {
(void) unlink(tempfile);
error(tempfile);
}
}
}
static void
deliver(FILE *fp[], FILE *tfp)
{
char str[BUF], buff[BUF*8];
char cmd[80];
long int offset;
int i, length;
sprintf(cmd, "sort +4f +0n +1n %s -o %s", tempfile, tempfile);
if (system(cmd) == 127) {
(void) unlink(tempfile);
error("sortbib");
}
tfp = fopen(tempfile, "r");
while (fgets(str, sizeof (str), tfp)) {
if (sscanf(str, "%d %d %d :", &i, &offset, &length) != 3)
error(gettext("sortbib: sorting error"));
if (fseek(fp[i], offset, 0) == -1) {
(void) unlink(tempfile);
error("sortbib");
}
if (fread(buff, sizeof (*buff), length, fp[i]) == 0) {
(void) unlink(tempfile);
error("sortbib");
}
if (buff[0] != '\n' && rsmode == 1)
putchar('\n');
if (fwrite(buff, sizeof (*buff), length, stdout) == 0) {
(void) unlink(tempfile);
error("sortbib");
}
}
}
static void
parse(char line[], char fld[][BUF])
{
char wd[8][BUF/4], *strcat();
int n, i, j;
for (i = 0; i < 8; i++)
*wd[i] = '\0';
n = sscanf(line, "%s %s %s %s %s %s %s %s",
wd[0], wd[1], wd[2], wd[3], wd[4], wd[5], wd[6], wd[7]);
for (i = 0; i < 4; i++) {
if (wd[0][1] == keystr[i]) {
if (wd[0][1] == 'A') {
if (oneauth && !multauth)
break;
else if (oneauth)
strcat(fld[i], "~~");
if (!endcomma(wd[n-2]))
strcat(fld[i], wd[n-1]);
else {
strcat(fld[i], wd[n-2]);
n--;
}
strcat(fld[i], " ");
for (j = 1; j < n-1; j++)
strcat(fld[i], wd[j]);
oneauth = 1;
} else if (wd[0][1] == 'D') {
strcat(fld[i], wd[n-1]);
if (n > 2)
strcat(fld[i], wd[1]);
} else if (wd[0][1] == 'T' || wd[0][1] == 'J') {
j = 1;
if (article(wd[1]))
j++;
for (; j < n; j++)
strcat(fld[i], wd[j]);
} else
for (j = 1; j < n; j++)
strcat(fld[i], wd[j]);
}
else if (wd[0][1] == 'Q' && keystr[i] == 'A')
for (j = 1; j < n; j++)
strcat(fld[i], wd[j]);
}
}
static int
article(char *str)
{
if (strcmp("The", str) == 0)
return (1);
if (strcmp("A", str) == 0)
return (1);
if (strcmp("An", str) == 0)
return (1);
if (strcmp("Le", str) == 0)
return (1);
if (strcmp("La", str) == 0)
return (1);
if (strcmp("Der", str) == 0)
return (1);
if (strcmp("Die", str) == 0)
return (1);
if (strcmp("Das", str) == 0)
return (1);
if (strcmp("El", str) == 0)
return (1);
if (strcmp("Den", str) == 0)
return (1);
return (0);
}
static void
eval(char keystr[])
{
int i, j;
for (i = 0, j = 0; keystr[i]; i++, j++) {
if (keystr[i] == '+') {
multauth = 1;
i++;
}
if (keystr[i] == '\0')
break;
keystr[j] = keystr[i];
}
keystr[j] = '\0';
}
static void
error(char *s)
{
perror(s);
exit(1);
}
static void
onintr(void)
{
fprintf(stderr, gettext("\nInterrupt\n"));
unlink(tempfile);
exit(1);
}
static int
endcomma(char *str)
{
int n;
n = strlen(str) - 1;
if (str[n] == ',') {
str[n] = '\0';
return (1);
}
return (0);
}