sort5.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 2,442 行 · 第 1/4 页
C
2,442 行
* setfil -- return pointer to the name of next input/output file * * ATTENTION: The algorithm used here will cause problems for NFILES > 26! */char *setfil(i)register int i;{ static char *filep; if (filep == (char *)0) filep = &file[strlen(file) - 2]; if (i < eargc) if (eargv[i][0] == '-' && eargv[i][1] == '\0') return (char *)0; else return eargv[i]; i -= eargc; filep[0] = i/26 + 'a'; filep[1] = i%26 + 'a'; return file;}/* * output -- open an output file. If the argument passed is not the null * pointer, it is assumed that a temporary file is meant. */FILE *output(filename)char *filename;{ static char outbuf[BUFSIZ]; /* buffer to use for stdio */ FILE *fp; if (filename == (char *)0) { filename = setfil(nfiles); if ((fp = fopen(filename, "w")) == (FILE *)0) diag(TERM, catgets(_m_catd, NL_SETN, 15, "can't create"), filename); nfiles++; } else if (!strcmp(filename, "-")) fp = stdout; else if ((fp = fopen(filename, "w")) == (FILE *)0) diag(TERM, catgets(_m_catd, NL_SETN, 16, "can't create"), outfil); setbuf(fp, outbuf); return fp;}/* * input -- open a file for input */FILE *input(i, bp)int i;char *bp;{ FILE *fp; char *name; if ((name = setfil(i)) == (char *)0) fp = stdin; else if ((fp = fopen(name, "r")) == NULL) diag(TERM, catgets(_m_catd, NL_SETN, 17, "can't open input:"), name); if (bp != (char *)0) setbuf(fp, bp); return fp;}/* * doclose -- close an input/output file */voiddoclose(fp, msg)FILE *fp;char *msg;{ if (ferror(fp)) { if (fp == os) diag(TERM, catgets(_m_catd, NL_SETN, 18, "write error while"), msg); else diag(TERM, catgets(_m_catd, NL_SETN, 19, "read error on"), msg ? msg : catgets(_m_catd, NL_SETN, 20, "stdin")); } (void) fclose(fp);}/* * gettmpdir -- find a directory for the temp files */gettmpdir(){ int a = -1; char **dirs; static char file1[MAXPLEN]; for (dirs = dirtry; *dirs; dirs++) { (void)sprintf(file = file1, "%s/stm%.5uaa", *dirs, getpid()); /* * try to create a temporary temporary file */ if ((a = creat(file, 0600)) >= 0) break; } if (a < 0) diag(EXIT, catgets(_m_catd, NL_SETN, 21, "can't locate temp"), ""); /* * remove temporary temporary file */ (void) close(a); (void) unlink(file);}/* * getline -- get a line from a file and return amount read */intgetline(iop, s, amount, complete, tagged)FILE *iop; /* file to read from */register char *s; /* buffer to read into */int amount; /* max amount to read */int complete; /* TRUE if complete line has to be read */int tagged; /* TRUE if file is tagged */{ char *fgets(); char *saves = s; int offset = 0; int bias = 0; short len; if (tag) { if (tagged) { /* * we are reading in a line which was written with tags * simply pull it back in */ if (fread((char *)&len, sizeof(short), 1, iop) == 0) return 0; if (amount < len) diag(TERM, catgets(_m_catd, NL_SETN, 22, "getline tag read"), catgets(_m_catd, NL_SETN, 23, "too short")); *(short *)s = len; s += sizeof(short); if (fread(s, 1, (unsigned)len - sizeof(short), iop) != (int)len - sizeof(short)) diag(TERM, catgets(_m_catd, NL_SETN, 24, "getline tag read"), catgets(_m_catd, NL_SETN, 25, "short record")); return (int)len; } offset = (nfields + 2) * sizeof(short); /* * if previous getline failed restart */ if (getstate != OKAY) { saves = recstart + memmoved; bias = s - saves; memmoved = 0L; switch (getstate) { case INHEAD: s = saves; break; case INREAD: if (fgets(s, amount, iop) == (char *)0) *s = '\0'; goto do_tag; /* NOT REACHED */ case INTAG: s = saves + offset; goto do_tag; /* NOT REACHED */ } } /* * save start of record for possible restart */ recstart = s; if (amount - offset + bias < 1) { getstate = INHEAD; return amount - 1; } } if (amount < 2) diag(TERM, catgets(_m_catd, NL_SETN, 26, "BUG: getline"), catgets(_m_catd, NL_SETN, 27, "amount too small")); s += offset; if (fgets(s, amount - offset, iop) == (char *)0) { getstate = OKAY; return 0; }do_tag: while (*s) s++; if (s[-1] != '\n') { if (s - saves < amount - 1) { diag(WARN, catgets(_m_catd, NL_SETN, 28, "warning: missing NEWLINE added:"), saves); *s++ = '\n'; *s = '\0'; } else if (complete) diag(TERM, catgets(_m_catd, NL_SETN, 29, "fatal: line too long:"), saves); else { getstate = INREAD; return amount - 1; } } if (tag) if ((s = settag(saves, saves + offset, s, amount - (s - saves))) == (char *)0) { getstate = INTAG; return amount - 1; } getstate = OKAY; return s - saves - bias;}/* * putline -- output a line, ignoring tags if final output file */putline(buf, iop, cleartag)char *buf;FILE *iop;int cleartag;{ short len; if (tag) { if (cleartag) fputs(buf + (nfields + 2) * sizeof(short), iop); else { len = *(short *)buf; fwrite(buf, 1, (unsigned)len, iop); } } else fputs(buf, iop);}/*====================== memory management funcs ============================*/#define BLOCK 256#define round(what) (((what + BLOCK - 1) / BLOCK) * BLOCK)#define MAXMALLOC ((1L << (BITSPERBYTE * sizeof(unsigned))) - BLOCK)/* * getmem -- try to get memory and return amount allocated * * This function is quite critical. It may be changed to care for * different implementations of malloc/realloc (BE CAREFUL!) * At least one implementation of malloc/realloc has problems when * the amount to allocate is close to MAXUNSIGNED. Special care is * taken to avoid overflow problems! */unsignedgetmem(amount, got, whereto)register unsigned amount; /* how much memory we want */unsigned got; /* memory we already have */char **whereto; /* where we want the memory */{ static int nomoremem = 0; /* 1 when no more mem available */ unsigned saveamount; /* what we really want to have */ register char *cp; /* where we got it */ /* * if no more mem no use to try getting some */ if (nomoremem && got != 0) return (unsigned)0; amount = round(amount); if (got != 0) {#ifdef M80S30 long newsize = (long)got + (long)amount;#else unsigned long newsize = (long)got + (long)amount;#endif if (newsize > MAXMALLOC) { amount = MAXMALLOC - got; newsize = (long)got + (long)amount; } if (newsize > MAXMEM) amount = (unsigned)(MAXMEM - got); saveamount = amount; /* * The following code assumes that, even when realloc returns * (char *)0, *whereto still is valid! */ while (amount != 0 && (cp = realloc(*whereto, got + amount)) == (char *)0) amount -= BLOCK; if (amount == 0) cp = realloc(*whereto, got); memmoved = cp - *whereto; } else { nomoremem = 0; if (amount > MAXMALLOC) amount = (unsigned)MAXMALLOC; if (amount < MINMEM) amount = (unsigned)MINMEM; else if (amount > MAXMEM) amount = (unsigned)MAXMEM; saveamount = amount; while (amount != 0 && (cp = malloc(amount)) == (char *)0) amount -= BLOCK; *whereto = cp; } if (amount != saveamount) nomoremem = 1; return amount;}/* * safemem -- determine how many files can be merged at a time * and make sure we have enough mem available. * ATTENTION: Could be more cautious: no overflowcheck for malloc */intsafemem(reclen){ int nway; char *save; /* memory we need for save area in merge */ char *bufs; /* memory we need for line buffers */ char *fbufs; /* memory we need for filebuffers */ save = malloc(reclen); for (nway = N; nway >= 2; nway--) { bufs = malloc(nway * reclen); fbufs = malloc(nway * BUFSIZ); if (fbufs == (char *)0) if (bufs == (char *)0) continue; else free(bufs); else if (bufs != (char *)0) break; else free(fbufs); } if (nway < 2 || save == (char *)0) diag(TERM, catgets(_m_catd, NL_SETN, 30, "allocation error before merge"), ""); free(fbufs); free(bufs); free(save); return nway;}/*====================== general support funcs ==============================*//* * number -- convert number in string to int, advance string pointer */intnumber(ppa)char **ppa;{ register int n = 0; /* result accumulator */ register char *cp; /* temporary pointer to scan string */ for (cp = *ppa; isdigit(*cp); cp++) { n = n * 10 + *cp - '0'; *ppa = cp; } return n;}/* * field -- analyse a field specification * * ATTENTION: Some options require the treatment of a line as one field * (use of cmp instead of cmpa). These options are handled here too. */field(s, k)char *s; /* pointer to string to analyse */int k; /* 0 for +pos or global option, 1 for -pos */{ register struct field *p; /* ptr to current field */ register d; /* index add value */ p = &fields[nfields]; d = 0; for(; *s != 0; s++) { switch (*s) { case '\0': /* end of field spec */ return; case 'b': /* ignore blanks in field */ p->bflg[k]++; break; case 'd': /* dictionary order for field */ p->ignore = dict+128; break; case 'f': /* fold cases in field */ p->code = fold+128; break; case 'i': /* ignore nonprinting chars in field */ p->ignore = nonprint+128; break; case 'M': /* use month comparison in field */ p->fcmp = monthcmp; p->bflg[0]++; /* implies skip of leading blanks! */ break; case 'n': /* numeric comparison in field */ p->fcmp = numcmp; p->bflg[0]++; /* implies skip of leading blanks! */ break; case 'r': /* reverse sense of comparison */ p->rflg = -1; continue; case '.': /* handle field spec */ if (p->m[k] == -1) /* -m.n with m missing */ p->m[k] = 0; d = &fields[0].n[0]-&fields[0].m[0]; if (*++s == '\0') { --s; p->m[k+d] = 0; continue; } default: if (isdigit(*s)) p->m[k+d] = number(&s); else diag(EXIT, USE, ""); break; /* * The following two here because they require us * to treat the line as one field (cmp instead of cmpa) */ case 't': /* tabchar specified */ tabchar = *++s; if (tabchar == 0) s--; continue; case 'u': /* eliminate double keys */ uflg = 1; continue; } /* * for all of these we need to use the cmp function instead * of cmpa, but only if not using tagcmp! */ if (compare != tagcmp) compare = cmp; } /* 002 */ return;}/* * initree -- initialize tree */initree(){ register struct btree **tpp; register struct btree *tp; register int i; for (tp = &(tree[0]), tpp = &(treep[0]), i = TREEZ; --i >= 0;) *tpp++ = tp++;}/* * eol -- advance pointer to newline in string */char *eol(p)register char *p;{ while (*p != '\n') p++; return(p);}/* * safeoutfil -- assure a safe output file */safeoutfil(){ register int i; struct stat ostat; struct stat istat; if (!mflg || outfil == 0) return; if (stat(outfil, &ostat) < 0) return; if ((i = eargc - N) < 0) i = 0; /* -N is sufficient, not necessary */ for (; i < eargc; i++) { if (stat(eargv[i], &istat) < 0) continue; if (ostat.st_dev == istat.st_dev && ostat.st_ino == istat.st_ino) unsafeout++; }}/* * diag -- output a diagnostic message to stderr */diag(type, s, t)int type;char *s;char *t;{ fprintf(stderr, "sort: %s %s\n", s, t); if (type == TERM) term(1); else if (type == EXIT) exit(1);}/* * term -- terminate sort, either because of signal or normally */voidterm(exitcode)int exitcode;{ register i; (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); if (nfiles == eargc) nfiles++; /* * remove all temporary files (in case of signal termination) */ for (i = eargc; i <= nfiles; i++) (void) unlink(setfil(i)); /* * all exitcodes are mapped to the exit codes 0 and 1. This is done * because we want to remain compatible with SYS V sort even when * terminated because of signal. */ exit(exitcode != 0);}/* * disorder -- issue disordered message and exit */voiddisorder(s, t)char *s;char *t;{ register char *u; /* * make t a null terminated string */ for (u = t; *u != '\n'; u++) ; *u = 0; diag(TERM, s, t);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?