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 + -
显示快捷键?