#include #include #define MAXLINES 10000 #define MAXLEN 1024 #define LEVE_OPEN 1 #define INDEXNAME "\\indexentry" /* Zeilen mit diesem Kopf "ubergehen. */ #define INDEXNAMELEN 11 /* L"ange von INDEXNAME. */ /* F"ur solche Zeilen ist MakeIndex */ /* zust"andig. */ #define KILLNAME "\\Ikillname{}" /* -K: Damit wird ARG1 und ARG2 einer */ /* Zeile ersetzt, falls diese in der */ /* vorausgehenden Zeile gleich sind. */ char *lineptr[MAXLINES]; FILE *infile, *outfile; /*--------------------------------------------------------------------------*/ void info(){ char p[]="%"; printf(" %s%s +-----------------------------------------------------------------+\n", p, p); printf(" %s%s | GBIBSORT sorts the lines of a file following german rules. |\n", p, p); printf(" %s%s | GBIBSORT is part of BIBARTS, Version 1.3. |\n", p, p); printf(" %s%s | (c) Timo Baumann <28.Mar.1998> |\n", p, p); printf(" %s%s | |\n", p, p); printf(" %s%s | BIBARTS.STY ist eine LaTeX-Dokumenten-Stil-Option; siehe dazu |\n", p, p); printf(" %s%s | BIBARTS.TEX. (LaTeX erzeugt mit BIBARTS.STY ein [File].BAR.) |\n", p, p); printf(" %s%s | |\n", p, p); printf(" %s%s | GBIBSORT sortiert zeilenweise: Es liest das angegebene File und |\n", p, p); printf(" %s%s | sortiert Zeichen vor Buchstaben (a vor A ...), dann Zahlen. |\n", p, p); printf(" %s%s | ABER: Die LaTeX-Sonderzeichen \\\"a und \"a werden als ae usw. |\n", p, p); printf(" %s%s | sortiert und \'\\\', \'{\', \'}\', \'^\', \'`\', \'-\', \' \' nicht gewichtet. |\n", p, p); printf(" %s%s | {RELEVANT}@ wird wie RELEVANT sortiert, aber nicht ausgegeben. |\n", p, p); printf(" %s%s | Option -K ersetzt mehrfach genannte Autoren ab dem 2. Mal. |\n", p, p); printf(" %s%s | |\n", p, p); printf(" %s%s | BENUTZUNG: gbibsort [File].BAR [[Schreib-File].PHY] |\n", p, p); printf(" %s%s | Autor Killing: gbibsort [File].BAR [[Schreib-File].PHY] -k |\n", p, p); printf(" %s%s | |\n", p, p); printf(" %s%s | Falls GBIB209.BAT oder GBIB2E.BAT fehlen --- sie enthalten: |\n", p, p); printf(" %s%s | IF EXIST %s1.bar GBIBSORT %s1.bar %s1.phy |\n", p, p, p, p, p); printf(" %s%s | IF EXIST %s1.bar MAKEINDX %s1.bar |\n", p, p, p, p); printf(" %s%s | IF EXIST %s1.tex CALL [LaTeX] %s1 |\n", p, p, p, p); printf(" %s%s +-----------------------------------------------------------------+\n", p, p); } /*--------------------------------------------------------------------------*/ /* CopyLeft: a) Verantwortung - b) Benutzung - c) Distribuntion */ /* a) Keinerlei Haftung ! */ /* b) Keine Funktions-Garantie ! */ /* Der Anwender erkennt die Punkte a) - c) an. */ /* c) GBIBSORT.C und damit erstellte ausf"uhrbare */ /* Dateien d"urfen nur weitergegeben werden, wenn */ /* 1. daf"ur keine Kosten erhoben werden, */ /* die "uber diejenigen f"ur ihren */ /* Transfer hinausgehen ! */ /* 2. vorgenommene "Anderungen */ /* kommentiert sind ! */ /*--------------------------------------------------------------------------*/ /* Neugewichtung der Zeichen 48 - 126 des ASCII-Codes. */ /* 1-47 [und ggf. 127-254] bleiben gleich! -> default. */ /* 127-254 kommen in FILE.bar aber auch niemals vor! */ /* Im Deutschen werden Zeichen vor Buchstaben und */ /* Buchstaben vor Zahlen einsortiert. */ /* Im Konfliktfall stehen Kleinbuchstaben vor grossen. */ /* Da der ASCII-Code eine andere Reihenfolge hat, */ /* muss den Zeichen innerhalb des angegebenen Bereichs */ /* eine neue INTEGER-Zahl zugeordnet werden. */ int bewerten(char zz) { switch(zz) { case ':': return 48; /* ASCII 58 \ */ case ';': return 49; /* ASCII 59 | */ case '<': return 50; /* ASCII 60 | */ case '=': return 51; /* ASCII 61 | */ case '>': return 52; /* ASCII 62 | */ case '?': return 53; /* ASCII 63 | */ case '@': return 54; /* ASCII 64 | */ /* | */ case '[': return 55; /* ASCII 91 \ */ case '\\':return 56; /* ASCII 92 > Zeichen vor Buchstaben */ case ']': return 57; /* ASCII 93 / */ case '^': return 58; /* ASCII 94 | */ case '_': return 59; /* ASCII 95 | */ case '`': return 60; /* ASCII 96 | */ /* | */ case '{': return 61; /* ASCII 123 | */ case '|': return 62; /* ASCII 124 | */ case '}': return 63; /* ASCII 125 | */ case '~': return 64; /* ASCII 126 / */ case 'a': return 65; /* ASCII 97 \ */ case 'A': return 66; /* ASCII 65 | */ case 'b': return 67; /* ASCII 98 | */ case 'B': return 68; /* ASCII 66 | */ case 'c': return 69; /* ASCII 99 | */ case 'C': return 70; /* ASCII 67 | */ case 'd': return 71; /* ASCII 100 | */ case 'D': return 72; /* ASCII 68 | */ case 'e': return 73; /* ASCII 101 | */ case 'E': return 74; /* ASCII 69 | */ case 'f': return 75; /* ASCII 102 | */ case 'F': return 76; /* ASCII 70 | */ case 'g': return 77; /* ASCII 103 | */ case 'G': return 78; /* ASCII 71 | */ case 'h': return 79; /* ASCII 104 | */ case 'H': return 80; /* ASCII 72 | */ case 'i': return 81; /* ASCII 105 | */ case 'I': return 82; /* ASCII 73 | */ case 'j': return 83; /* ASCII 106 | */ case 'J': return 84; /* ASCII 74 | */ case 'k': return 85; /* ASCII 107 | */ case 'K': return 86; /* ASCII 75 | */ case 'l': return 87; /* ASCII 108 | */ case 'L': return 88; /* ASCII 76 | */ case 'm': return 89; /* ASCII 109 | */ case 'M': return 90; /* ASCII 77 | */ case 'n': return 91; /* ASCII 110 | */ case 'N': return 92; /* ASCII 78 | */ case 'o': return 93; /* ASCII 111 | */ case 'O': return 94; /* ASCII 79 | */ case 'p': return 95; /* ASCII 112 \ */ case 'P': return 96; /* ASCII 80 > Buchstaben: a, A, ... */ case 'q': return 97; /* ASCII 113 / */ case 'Q': return 98; /* ASCII 81 | */ case 'r': return 99; /* ASCII 114 | */ case 'R': return 100; /* ASCII 82 | */ case 's': return 101; /* ASCII 115 | */ case 'S': return 102; /* ASCII 83 | */ case 't': return 103; /* ASCII 116 | */ case 'T': return 104; /* ASCII 84 | */ case 'u': return 105; /* ASCII 117 | */ case 'U': return 106; /* ASCII 85 | */ case 'v': return 107; /* ASCII 118 | */ case 'V': return 108; /* ASCII 86 | */ case 'w': return 109; /* ASCII 119 | */ case 'W': return 110; /* ASCII 87 | */ case 'x': return 111; /* ASCII 120 | */ case 'X': return 112; /* ASCII 88 | */ case 'y': return 113; /* ASCII 121 | */ case 'Y': return 114; /* ASCII 89 | */ case 'z': return 115; /* ASCII 122 | */ case 'Z': return 116; /* ASCII 90 / */ case '0': return 117; /* ASCII 48 \ */ case '1': return 118; /* ASCII 49 | */ case '2': return 119; /* ASCII 50 | */ case '3': return 120; /* ASCII 51 | */ case '4': return 121; /* ASCII 52 \ */ case '5': return 122; /* ASCII 53 > Zahlen */ case '6': return 123; /* ASCII 54 / */ case '7': return 124; /* ASCII 55 | */ case '8': return 125; /* ASCII 56 | */ case '9': return 126; /* ASCII 57 / */ default : return zz; } } /*--------------------------------------------------------------------------*/ /* Dies ist die eigentliche Sortier-Funktion. */ /* Sie zerteilt das Sortierproblem in viele triviale: */ /* Wie sind z w e i Eintr"age zu sortieren? */ void QQsort(void *v[], int left, int right, int (*comp)(void *, void *)) { int i, last; void swap (void *v[], int, int); if (left >= right) return; swap(v, left, (left + right)/2); last = left; for (i = left + 1; i <= right; i++) if ((*comp)(v[i], v[left]) < 0) swap(v, ++last, i); swap(v, left, last); QQsort(v, left, last - 1, comp); QQsort(v, last + 1, right, comp); } /*--------------------------------------------------------------------------*/ /* Wenn zwei Eintr"age in der falschen Reihenfolge */ /* sortiert sind, werden die Zeiger, die auf sie */ /* weisen, ausgetauscht. */ void swap(void *v[], int i, int j) { void *temp; temp = v[i]; v[i] = v[j]; v[j] = temp; } /*--------------------------------------------------------------------------*/ /* Hier werden Leerzeichen, Backslash, geschweifte */ /* Klammern, Tilden und Minus-Zeichen gleich "uber- */ /* gangen, um \"a und "a, \ss und \ss{}, a~b und a b, */ /* Info und In\-fo gleich gewichtet zu bekommen. */ /* \ss und "s werden als ss, "[x] und \"[x] als [x]e */ /* sortiert, aber original ausgedruckt. */ /* `[x], ^[x] und '[x] werden als [x] gewichtet. */ /* \newumlaut muss nicht beachtet werden, denn mit */ /* dem GBIBARTS.STY-Makro \@sIcHerUnG konnte es unter- */ /* dr"uckt werden, dass dies in [File].BAR erscheint. */ /* Da in [File].BAR die Umlaute und "s immer expan- */ /* diert sind, muss auf die Ein-Zeichen-Umlaute, wie */ /* sie im erweiterten ASCII-Code definiert sind, */ /* keine R"ucksicht genommen werden. */ int vergleich(const void *s1,const void *s2) { int a1=1, b1=1, a2=1, b2=1, a3=1, b3=1, a=1, b=1; while (a == b) { while (overjump(*((char *)s1)) > 0) s1 = (char *)s1 + 1; while (overjump(*((char *)s2)) > 0) s2 = (char *)s2 + 1; a3 = a2; b3 = b2; a2 = a1; b2 = b1; a1 = bewerten(*((char *)s1)); b1 = bewerten(*((char *)s2)); s1 = (char *)s1 + 1; s2 = (char *)s2 + 1; a = a2 ; b = b2 ; if ( /* Abpr"ufen, ob ein Um- */ ( a2 == bewerten('\"') ) /* laut vorhanden ist */ ) { a = a1; } if ( ( b2 == bewerten('\"') ) ) { b = b1; } if ( ( a3 == bewerten('\"') ) && ( a2 != bewerten('s') ) /* "s ist kein Umlaut */ ) { a = bewerten('e'); } /* "a als ae etc. */ if ( ( b3 == bewerten('\"') ) && ( b2 != bewerten('s') ) ) { b = bewerten('e'); } } if (a > b ) {return 1;} else {return -1;} } /*--------------------------------------------------------------------------*/ int getline(char s[], int lim) { int c,i; i=0; while(--lim > 0 && (c=fgetc(infile)) != EOF && c != '\n') s[i++] = c; if (c == '\n') s[i++] = c; s[i] = '\0'; return i; } /*--------------------------------------------------------------------------*/ /* Definiert f"ur vergleich, welche Zeichen "uber- */ /* gangen werden sollen in der Frage, ob zwei */ /* Zeilen gleich sind. */ int overjump(int a) { if ( a == ' ' /* Leerzeichen */ || a == '\\' /* Backslash */ || a == '{' /* { */ || a == '}' /* } */ || a == '~' /* Tilde */ || a == '-' /* \- */ || a == '\'' /* \' */ || a == '`' /* \` */ || a == '^' /* \^ */ || a == '@' /* {...}@ */ ) return 1; else return -1; } /*--------------------------------------------------------------------------*/ /* Definiert f"ur TeXvergleich, welche Zeichen */ /* nicht gewichtet werden sollen in der Frage, ob */ /* zwei Zeilen gleich sind. */ int vergljump(int a) { if ( a == ' ' /* Leerzeichen */ || a == '\\' /* Backslash */ || a == '~' /* Tilde */ || a == '-' /* \- */ || a == '\'' /* \' */ || a == '`' /* \` */ || a == '^' /* \^ */ || a == '@' /* {...}@ */ ) return 1; else return -1; } /*--------------------------------------------------------------------------*/ /* {...}@ wird aus der Zeile gel"oscht. */ void killsort(char *lineptr[], int nlines) { char a[MAXLEN], b[MAXLEN]; int i, j, m; while(nlines-- > 0) { strcpy(a, *lineptr); i = 0; j = 0; m = 0; while(a[i]!='\0') { if (a[i] == '{') m = j; if (a[i] == '}' && a[i+1] == '@' && a[i+2] != '\0') { j = m; ++i; ++i; } b[j] = a[i]; ++i; ++j; } b[j++] = '\0'; free(*lineptr); *lineptr = (char *)malloc(j*sizeof(char)); strcpy(*lineptr++, b); } } /*--------------------------------------------------------------------------*/ void writelines(char *lineptr[], int nlines) { while(nlines-- > 0) fprintf(outfile,"%s\n", *lineptr++); } /*--------------------------------------------------------------------------*/ /* Hier wird f"ur doubleauthor bestimmt, ob Name */ /* und Vorname zweier Zeilen gleich sind. */ int TeXvergleich(const void *s1,const void *s2) { int i = 0, j = 0, k = 0, l = 0; while(1) { while (vergljump(*((char *)s1)) > 0) ++s1; while (vergljump(*((char *)s2)) > 0) ++s2; if (*(char *)s1 == '{') ++i; else if (*(char *)s1 == '}') { --i; if (i==LEVE_OPEN) ++j; } if (*(char *)s1 == '{') ++k; else if (*(char *)s1 == '}') { --k; if (k==LEVE_OPEN) ++l; } if (*(char *)s1 == '\0' && *(char *)s2 == '\0') return 0; else if (j == 2 && l == 2) return 2; if (*(char *)s1 == '\0') return 1; else if (*(char *)s2 == '\0') return -1; if (*(char *)s1 == *(char *)s2) { ++s1; ++s2; } else if (*(char *)s1 > *(char *)s2) return 1; else if (*(char *)s1 < *(char *)s2) return -1; } } /*--------------------------------------------------------------------------*/ /* Autoren, die mehrfach vorkommen, werden einmal */ /* genannt, und dann durch KILLNAME ersetzt. */ void doubleauthor(char *lineptr[], int nlines) { int j, i, h; char a[MAXLEN]; while(--nlines > 0) { if (TeXvergleich(lineptr[nlines], lineptr[nlines-1]) == 2) { strcpy(a, lineptr[nlines]); j = 0; h = 0; i = 0; while(1) { if(a[j]=='{') ++i; else if(a[j]=='}') { --i; if (i==LEVE_OPEN) ++h; } ++j; if (h==2 || a[j]=='\0') break; } if (h==2) { i = 0; while(a[i]!='\0' && a[i]!='{') ++i; a[i+1]='\0'; /* '{' soll bleiben! */ strcat(a, KILLNAME); i = i + strlen(KILLNAME); while(a[j]!='\0') a[++i] = a[j++]; a[++i] = '\0'; free(lineptr[nlines]); lineptr[nlines] = (char *)malloc((++i)*sizeof(char)); strcpy(lineptr[nlines], a); } } } } /*--------------------------------------------------------------------------*/ /* Zeilen, die mit INDEXNAME beginnen, werden */ /* nicht aufgenommen. */ int readlines(char *Lineptr[], int maxlines) { int len, nlines; char *p, line[MAXLEN]; nlines = 0; while ((len = getline(line,MAXLEN)) > 0) if (strncmp(line, INDEXNAME, INDEXNAMELEN)==0) continue; else if (nlines >= maxlines || (p = (char *)malloc(len*sizeof(char))) == NULL) return -1; else { line[len-1] = '\0'; strcpy(p, line); Lineptr[nlines++] = p; } return nlines; } /*--------------------------------------------------------------------------*/ /* Kehrt mit -argc+1 zur"uck, wenn Option da ist. */ int single_option(int argc, char *argv[], char a[]) { int l = 1, c; int _found = 0; while (l < argc) { if (strcmp(argv[l], a) == 0) { _found = 1; /* free(argv[l]); */ --argc; c = l; while (c < argc) { argv[c] = argv[c+1]; ++c; } --l; } ++l; } if (_found == 1) return -argc; else return argc; } /*--------------------------------------------------------------------------*/ /* Erkennt unbekannte Optionen. */ int surp_option(int argc, char *argv[]) { char p[]=" %% "; int l = 1, c; char a[2]; while (l < argc) { strncpy(a, argv[l], 1); if (a[0] == '-') { printf("\n%s *** BREAK: Get unknown option \"%s\"!\n", p, argv[l]); /* free(argv[l]); */ --argc; c = l; while (c < argc) { argv[c] = argv[c+1]; ++c; } --l; } ++l; } return argc; } /*--------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { char p[]=" %% "; int nlines=0; int i; int kill = 0; argc = single_option(argc, argv, "-K"); if (argc < 0) { argc = -argc; kill = 1; } argc = single_option(argc, argv, "-k"); if (argc < 0) { argc = -argc; kill = 1; } if (argc == 1) { info(); exit(1); } if (argc != surp_option(argc, argv)) exit(1); if (argc == 2) { infile = fopen(argv[1],"r"); outfile = stdout; } else if (argc == 3) { if (strcmp(argv[1], argv[2]) == 0) { printf("\n%s Quelle und Ziel d\"urfen nicht identisch sein.\n", p); exit(1); } infile = fopen(argv[1],"r"); outfile = fopen(argv[2],"w"); } else { printf("\n%s Zu viele Argumente.\n", p); exit(1); } if (infile == NULL) { printf("\n%s \"%s\" kann nicht gelesen werden.\n", p, argv[1]); exit(1); } if (outfile == NULL) { printf("\n%s Betriebsystem verhindert Ausgabe in \"%s\".\n", p, argv[2]); printf("%s Gegebenenfalls Schutz gegen \"Uberschreiben entfernen.\n", p); exit(1); } if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { printf("\n%s GBIBSORT sortiert \"%s\" alphabetisch", p, argv[1]); QQsort((void **) lineptr, 0, nlines-1, (int (*)(void*,void*))(vergleich)); killsort(lineptr, nlines); if (kill == 1) { printf("\n%s --- wobei mehrfach genannte Autoren bei wiederholter Nennung\n", p, KILLNAME); printf("%s durch %s ersetzt werden", p, KILLNAME); doubleauthor(lineptr, nlines); } printf(".\n"); printf("%s Ausgabe ", p); if (argc == 2) printf("auf die Standard-Ausgabe.\n"); else printf("in \"%s\".\n", argv[2]); writelines(lineptr, nlines); return 0; } else { printf("Fehler: Datei zu gross.\n"); return 1; } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/