#include #include "utils.h" #define MAXLINES 5000 #define MAXLEN 1000 #define NUMERIC 1 #define REVERSE 2 #define FOLD 4 /* turn on case "folding" (insensitiveness) */ #define DIR 8 /* "directory" order only counts letters, numbers, and blanks */ int flags; char *lineptr[MAXLINES]; void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *)); int getargs(int argc, char *argv[]); int numtest(char *s, char *t); int strtest(char *s, char *t); int dirtest(char *s, char *t); void fold(char *s); int isdir(char c); int getfield(char *s); void fields(char *s); int start = 0; /* beginning of field */ int stop = 0; /* end of field */ int main(int argc, char *argv[]) { int nlines; int (*srtfnc)(char *, char *); if (getargs(argc, argv) != 0) return 1; /* determine what kind of sort should be used */ if (flags & NUMERIC) srtfnc = numtest; else if (flags & DIR) srtfnc = dirtest; else srtfnc = strtest; /* read input for stdin and sort */ if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { qsort((void **) lineptr, 0, nlines-1, (int (*)(void *, void *)) srtfnc); writelines(lineptr, nlines); return 0; } else { printf("input too big to sort\n"); return 1; } /* what the hell are we doing _here_? */ return -1; } /* main() */ void qsort(void *v[], int left, int right, int (*comp)(void *, void *)) { int i, last; if (left >= right) return; pswap(&v[left], &v[(left + right)/2]); last = left; for (i = left+1; i <= right; i++) if ((*comp)(v[i], v[left]) < 0) { if (!(flags & REVERSE)) pswap(&v[++last], &v[i]); } else if ((*comp)(v[i], v[left]) > 0) if (flags & REVERSE) pswap(&v[++last], &v[i]); pswap(&v[left], &v[last]); qsort(v, left, last-1, comp); qsort(v, last+1, right, comp); } /* qsort() */ int getargs(int argc, char *argv[]) { while (--argc >= 1 && *(++argv)[0] == '-') { while (*++argv[0] != '\0') { switch (*argv[0]) { case 'n': flags |= NUMERIC; break; case 'r': flags |= REVERSE; break; case 'f': flags |= FOLD; break; case 'd': flags |= DIR; break; case 'k': /* if the next character is a number, take it */ if (isnum(*++argv[0])) { if (getfield(argv[0]) == -1) return -1; } else if ((++argv)[0] != NULL && isnum(*argv[0])) { argc--; if (getfield(argv[0]) == -1) return -1; } else { printf("Hey bitch, where does the field start?\n"); return -1; } /* get to the end of whatever argv we are on */ while (*(argv[0]+1) != '\0') argv[0]++; break; default: /* what the fuck is this shit? */ printf("Unrecognized argument: -%c\n", *argv[0]); return -1; break; } } } if (argc != 0) { /* means we got passed some invalid bullshit */ printf("What the fuck is this shit: %s\n", argv[0]); return -1; } /* the options -n and -d cannot coexist, -d takes precedence */ if (flags & DIR && flags & NUMERIC) flags ^= NUMERIC; return 0; } /* getargs() */ int numtest(char *s, char *t) { char su[MAXLEN]; char tu[MAXLEN]; strcopy(su, s); strcopy(tu, t); if (flags & FOLD) { fold(su); fold(tu); } fields(su); fields(tu); return numcom(su, tu); } /* numtest() */ int strtest(char *s, char *t) { char su[MAXLEN]; char tu[MAXLEN]; strcopy(su, s); strcopy(tu, t); if (flags & FOLD) { fold(su); fold(tu); } fields(su); fields(tu); return strcom(su, tu); } /* strtest() */ /* returns 0 if s==t, <0 if s0 if s>t */ int dirtest(char *s, char *t) { char su[MAXLEN]; char tu[MAXLEN]; int i = 0; int j = 0; strcopy(su, s); strcopy(tu, t); if (flags & FOLD) { fold(su); fold(tu); } fields(su); fields(tu); /* compare only integers, numbers, and blanks does not compare _values_ of numbers */ while (su[i] != '\0' && tu[j] != '\0') { if (isdir(su[i])) { if (isdir(su[j])) { if (su[i] != tu[j]) { return su[i] - tu[j]; } } else { j++; continue; } } else { i++; continue; } i++; j++; } if (su[i] == '\0' && tu[j] == '\0') return 0; else if (su[i] == '\0') return -1; else if (tu[j] == '\0') return 1; } /* dirtest() */ void fold(char *s) { while (*s != '\0') { *s = toupper(*s); s++; } } /* fold() */ /* returns 1 if character is a number, blank, or character */ int isdir(char c) { if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == ' ' || c == '\t') return 1; else return 0; } /* gets field information from specified string */ int getfield(char *s) { /* 0 is invalid */ if (*s == '0') { printf("Zero specifying motherfucker, you die NOW!\n"); return -1; } while (isnum(*s)) { start = start * 10 + (*s++ - '0'); } if (start == 0) { printf("Motherfucker! Specify a starting field or perish!\n"); return -1; } else if (*s++ == ',') { /* get second field */ while (isnum(*s)) stop = stop * 10 + (*s++ - '0'); if (stop == 0) { printf("What the hell? Commas must be followed by end fields!\n"); return -1; } } } /* getfield() */ /* chops string s into its fields */ void fields(char *s) { char *t = s; char *u = s; int i; /* find our first field */ for (i = 1; i < start; i++) { while (*s != ' ' && *s != '\0') { s++; } if (*s == ' ') s++; } /* slide it to the beginning */ while ((*t++ = *s++) != '\0'); /* mark off the second field if specified */ if (stop) { for (i = 0; i <= stop - start; i++) { while (*u != ' ' && *u != '\0') { u++; } if (*u == ' ') u++; } /* at this point, we are either sitting on top of a '\0', or the character behind us is a ' '. In the former case, we don't need to do shit, but in the latter, we need to backtrack and make that space a null. */ if (*(u - 1) == ' ') *(u - 1) = '\0'; } } /* fields() */