/* **************************** NOTICE! ************************** * Contrary to the current trend in MS-DOS software this * * program, for whatever it is worth, is NOT copyrighted * * (with the exception of the runtime library from Borland * * International's Turbo C)! The program, in whole or in * * part, may be used freely in any fashion or environment * * desired. If you find this program to be useful to you, * * do NOT send any contribution to the author; in the words * * of Rick Conn, 'Enjoy!' However, if you make any * * improvements, I would enjoy receiving a copy of the * * modified source. I can be reached, usually within 24 * * hours, by messages on any of the Phoenix systems, * * particularly: * * * * Bob's Answering Machine [OPUS] * * (602) 242-3158 1200/2400 bps * * Radioactive West [PCBOARD] * * (602) 873-0810 1200/2400 bps * * The Tool Shop BBS [PCBOARD] * * (602) 279-2673 1200/2400/9600 bps * * (Good luck trying! VERY BUSY!) * * Technoids Anonymous [PCBOARD] * * (602) 899-4876 300/1200/2400 bps * * * * All can be reached through PC Pursuit. * * * * or: * * on GEnie, mail address: DON-WILL * * on CompuServ: 75410,543 * * * * Every effort has been made to avoid error and moderately * * extensive testing has been performed on this program, * * however, the author does not warrant it to be fit for any * * purpose or to be free from error and disclaims any * * liability for actual or any other damage arising from the * * use of this program. * ***************************************************************** */ #include #include #include #include #include "queue.h" #define LINE_LENGTH 256 #define OFF 0 #define ON 1 struct KeyEntry { int Begin; int Len; char Case; }; void GetArgs (int argc, char *argv[]); void InvalArgu (char *Msg); int KeyComp (char *Str1, char *Str2, QUE_DEF *Q); void Usage (void); char InName[65] = ""; FILE *F1 = NULL; FILE *F2; QUE_DEF *Keys; void main (int argc, char *argv[]) { char BakName[65]; char IntName[65]; char Line[LINE_LENGTH + 3]; char *OldLine = NULL; char *p; struct KeyEntry *t; int Lnno = 0; fprintf(stderr, "UNEEK- Version 1.0.0 May 21, 1990\n"); if (argc < 2) Usage(); Keys = malloc(sizeof(QUE_DEF)); InitQueue(Keys); GetArgs(argc, argv); if (F1 == NULL) { if (InName[0] == '\0') { fprintf(stderr, "You must supply an input file name.\n"); Usage(); } strcpy(BakName, InName); if ( (p = strrchr(BakName, '.')) != NULL) *p = '\0'; strcat(BakName, ".BAK"); strcpy(IntName, InName); if ( (p = strrchr(IntName, '\\')) == NULL) p = IntName; else ++p; strcpy(p, "UNIQUE.$$$"); if ( (F1 = fopen(InName, "r")) == NULL) { fprintf(stderr, "I can't open input file: %s", InName); perror(""); exit(1); } setvbuf(F1, NULL, _IOFBF, 16384); if ( (F2 = fopen(IntName, "w")) == NULL) { fprintf(stderr, "I can't create output file: %s", IntName); perror(""); exit(1); } setvbuf(F2, NULL, _IOFBF, 16384); } if (Keys->Count == 0) { t = malloc(sizeof(struct KeyEntry)); t->Begin = 0; t->Len = 0; Enque(Keys, t); } while (fgets(Line, LINE_LENGTH, F1) != NULL) { Lnno++; if (Line[strlen(Line)-1] != '\n') { fprintf(stderr, "File: %s Line #%d too long - truncated.\n", InName, Lnno); strcat(Line, "\n"); while (fgetc(F1) != '\n'); } if (OldLine == NULL) OldLine = malloc(LINE_LENGTH + 3); else { if (KeyComp(OldLine, Line, Keys)) fputs(OldLine, F2); } strcpy(OldLine, Line); } fputs(OldLine, F2); if (F1 != stdin) { fclose(F1); fclose(F2); unlink(BakName); if (rename(InName, BakName)) { fprintf(stderr, "Rename of file: %s failed", InName); perror(""); } if (rename(IntName, InName)) { fprintf(stderr, "Rename of file: %s failed", IntName); perror(""); } } } void GetArgs (int argc, char *argv[]) { int i; char *p1, *p2; struct KeyEntry *t; for (i=1; i < argc; ++i) { if (argv[i][0] != '-') continue; if (!strcmp(argv[i], "-")) { F1 = stdin; F2 = stdout; continue; } switch (tolower(argv[i][1])) { default: fprintf(stderr, "Invalid option: %s\n", argv[i]); Usage(); } } for (i=1; i < argc; ++i) { if (argv[i][0] == '-') continue; if ( (F1 == NULL) && (InName[0] == '\0') ) { if (InName[0] == '\0') { strcpy(InName, argv[i]); continue; } } p1 = argv[i]; if ( !isdigit(p1[0]) ) InvalArgu(argv[i]); p2 = &p1[strspn(p1, "0123456789")]; t =malloc( sizeof(struct KeyEntry) ); t->Case = OFF; t->Begin = atoi(p1) -1; if (*p2 == ':') t->Len = atoi(++p2); else if (*p2 == '-') t->Len = atoi(++p2) - t->Begin; else InvalArgu(argv[i]); p1 = p2; p2 = &p1[strspn(p1, "0123456789")]; if (*p2 == ':') { p1 = ++p2; while (*p1 != '\0') { switch (tolower(*p1++)) { case 'i': t->Case = OFF; break; case 'c': t->Case = ON; break; default: InvalArgu(argv[i]); } } } else if (*p2 != '\0') InvalArgu(argv[i]); Enque(Keys, t); } } void InvalArgu (char *Msg) { fprintf(stderr, "Invalid argument: %s.\n", Msg); Usage(); } int KeyComp (char *Str1, char *Str2, QUE_DEF *Q) { int Result, La, Lb; QUE_ENTRY *t; struct KeyEntry *p; char *S1, *S2, HoldA, HoldB; La = strlen(Str1); Lb = strlen(Str2); for (Result=0, t = Q->Head; (Result == 0) && (t != NULL); t = t->Next) { p = t->Body; if (p->Len == 0) { if (p->Case == OFF) Result = stricmp(Str1, Str2); else Result = strcmp(Str1, Str2); break; } else { if (p->Begin > La) S1 = ""; else S1 = &Str1[p->Begin]; if (p->Begin > Lb) S2 = ""; else S2 = &Str2[p->Begin]; if (S1[0] != '\0') { if (p->Begin + p->Len < La) { HoldA = S1[p->Len]; S1[p->Len] = '\0'; } } if (S2[0] != '\0') { if (p->Begin + p->Len < Lb) { HoldB = S2[p->Len]; S2[p->Len] = '\0'; } } if (p->Case == OFF) Result = stricmp(S1, S2); else Result = strcmp(S1, S2); if ( (S1[0] != '\0') && (p->Begin + p->Len < La) ) S1[p->Len] = HoldA; if ( (S2[0] != '\0') && (p->Begin + p->Len < Lb) ) S2[p->Len] = HoldB; } } return(Result); } void Usage (void) { fprintf(stderr, "USAGE: unique [- | file_name] [field_spec ...]\n"); fprintf(stderr, " field_spec = b:l[:o] or b-e[:o] where b is the beginning\n"); fprintf(stderr, " character position of the field and l is the length\n"); fprintf(stderr, " in characters or e is the ending character position\n"); fprintf(stderr, " of the field (inclusive). o, if supplied is 'i' for\n"); fprintf(stderr, " a case insensitive match (default) or 'c' for a case\n"); fprintf(stderr, " sensitive match.\n"); exit(1); }