⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subst.c

📁 早期freebsd实现
💻 C
字号:
/*  $Revision: 1.12 $****  A C version of Henry Spencer's "subst" script.*/#include <stdio.h>#include <signal.h>#include <errno.h>#define LINESIZE		1024#define FNAMESIZE		1024#define PARAMSIZE		128#define WHITE(c)		((c) == ' ' || (c) == '\t')/***  AFS doesn't support hard links, so enable this #define.#define USE_RENAME*//***  If you don't have getopt in your C library, enable this #define.#define NEED_GETOPT*/typedef struct _PAIR {    char	*Name;    int		Length;    char	*Value;} PAIR;static char	*argv0;extern char	*optarg;extern int	optind;extern void	exit();extern char	*malloc();extern char	*strcpy();/***  Local implementations of common C library functions.*//***  Return string represtation of errno.*/static char *xstrerror(){    extern char *strerror();    return strerror(errno);}/***  Return the first occurrence of 'c' in 'p' or NULL if not there.*/static char *xstrchr(p, c)    register char	*p;    register char	c;{    extern char *strchr();    return strchr(p, c);}/***  Return the last occurrence of 'c' in 'p' or NULL if not there.*/static char *xstrrchr(p, c)    register char	*p;    register char	c;{    extern char *strrchr();    return strrchr(p, c);}/***  Copy a string to malloc'd memory or exit.*/static char *xstrdup(p)    char	*p;{    char	*new;    if ((new = malloc(strlen(p) + 1)) == NULL) {	(void)fprintf(stderr, "%s: Can't copy \"%s\", %s\n",		argv0, p, xstrerror());	exit(1);    }    return strcpy(new, p);}#if	defined(NEED_GETOPT)#define TYPE	int#define ERR(s, c)					\    if (opterr) {					\	char buff[2];					\	buff[0] = c; buff[1] = '\n';			\	(void)write(2, av[0], (TYPE)strlen(av[0]));	\	(void)write(2, s, (TYPE)strlen(s));		\	(void)write(2, buff, 2);			\    }int	 opterr = 1;int	 optind = 1;int	 optopt;char	*optarg;/***  Return options and their values from the command line.**  This comes from the AT&T public-domain getopt published in mod.sources**  (i.e., comp.sources.unix before the great Usenet renaming).*/intgetopt(ac, av, opts)    int		ac;    char	*av[];    char	*opts;{    static int	i = 1;    char	*p;    /* Move to next value from argv? */    if (i == 1) {	if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0')	    return EOF;	if (strcmp(av[optind], "--") == 0) {	    optind++;	    return EOF;	}    }    /* Get next option character. */    if ((optopt = av[optind][i]) == ':' || (p = IDX(opts,  optopt)) == NULL) {	ERR(": illegal option -- ", optopt);	if (av[optind][++i] == '\0') {	    optind++;	    i = 1;	}	return '?';    }    /* Snarf argument? */    if (*++p == ':') {	if (av[optind][i + 1] != '\0')	    optarg = &av[optind++][i + 1];	else {	    if (++optind >= ac) {		ERR(": option requires an argument -- ", optopt);		i = 1;		return '?';	    }	    optarg = av[optind++];	}	i = 1;    }    else {	if (av[optind][++i] == '\0') {	    i = 1;	    optind++;	}	optarg = NULL;    }    return optopt;}#endif	/* defined(NEED_GETOPT) *//***  Simulate "mv $from $to" -- return no useful status.  We know that**  the $from and $to are on the same filesystem.*/static voidmv(from, to)    char	*from;    char	*to;{    if (unlink(to) < 0 && errno != ENOENT) {	(void)fprintf(stderr, "%s: Can't unlink %s, %s\n",	    argv0, to, xstrerror());	return;    }#if	defined(USE_RENAME)    if (rename(from, to) < 0) {	(void)fprintf(stderr, "%s: Can't rename %s to %s, %s\n",		argv0, from, to, xstrerror());	return;    }#else    if (link(from, to) < 0) {	(void)fprintf(stderr, "%s: Can't link %s to %s, %s\n",		argv0, from, to, xstrerror());	return;    }    if (unlink(from) < 0)	(void)fprintf(stderr, "%s: Can't unlink %s, %s\n",	    argv0, from, xstrerror());#endif	/* defined(USE_RENAME) */}/***  Simulate "cmp -s $n1 $n2" -- return 0 if files are the same.*/static intcmp(n1, n2)    char	*n1;    char	*n2;{    FILE	*f1;    FILE	*f2;    int		c;    if ((f1 = fopen(n1, "r")) == NULL)	return 1;    if ((f2 = fopen(n2, "r")) == NULL) {	(void)fclose(f1);	return 1;    }    while ((c = getc(f1)) != EOF)	if (getc(f2) != c) {	    (void)fclose(f1);	    (void)fclose(f2);	    return 1;	}    if (getc(f2) != EOF) {	(void)fclose(f1);	(void)fclose(f2);	return 1;    }    (void)fclose(f1);    (void)fclose(f2);    return 0;}/***  If line does not look like a template, return NULL, otherwise modify**  it to delete the trailing gunk and return the start of the template.*/static char *istemplate(line)    char	*line;{    char	*p;    char	*start;    /* Find "=()<" and remember where it starts. */    for (p = line; (p = xstrchr(p, '=')) != NULL; p++)	if (p[1] == '(' && p[2] == ')' && p[3] == '<')	    break;    if (p == NULL)	return NULL;    start = &p[4];    /* Now find ">()=" and nip it off. */    for (p = start; (p = xstrchr(p, '>')) != NULL; p++)	if (p[1] == '(' && p[2] == ')' && p[3] == '=') {	    *p++ = '\n';	    *p = '\0';	    return start;	}    return NULL;}/***  Splice three strings together, returning an allocated copy.*/static char *splice(s1, s2, s3)    char	*s1;    char	*s2;    char	*s3;{    int		i;    char	*new;    i = strlen(s1) + strlen(s2) + strlen(s3) + 1;    if ((new = malloc(i)) == NULL) {	(void)fprintf(stderr, "%s: Can't splice %s+%s+%s, %s\n",	    argv0, s1, s2, s3, xstrerror());	exit(1);    }    (void)sprintf(new, "%s%s%s", s1, s2, s3);    return new;}/***  Substitute all found patterns in the line and print it.  Using the goto**  makes the code more clear than using do/while.*/static intdoline(f, out, line, tp, end)    char	*f;    FILE	*out;    char	*line;    PAIR	*tp;    PAIR	*end;{    char	*p;    char	*new;    char	save;    int		count;    for (count = 0, line = xstrdup(line); tp < end; tp++) {Again:	for (p = line; (p = xstrchr(p, tp->Name[0])) != NULL; p++)	    if (strncmp(p, tp->Name, tp->Length) == 0) {		save = *p;		*p = '\0';		count++;		new = splice(line, tp->Value, p + tp->Length);		*p = save;		if (strcmp(new, line) == 0) {		    (void)fprintf(stderr, "%s:  subst loop in %s:\n\t%s\n",			    argv0, f, line);		    free(new);		    break;		}		free(line);		line = new;		goto Again;	    }    }    if (count > 0 && fputs(line, out) == EOF) {	(void)fprintf(stderr, "%s:  can't write %s, %s\n",		argv0, f, xstrerror());	free(line);	return -1;    }    free(line);    return count;}/***  Process one file, carefully substituting it in place.*/static voidProcess(f, Table, end)    char	*f;    PAIR	*Table;    PAIR	*end;{    char	new[FNAMESIZE];    char	old[FNAMESIZE];    char	line[LINESIZE];    int		bad;    int		i;    int		count;    FILE	*in;    FILE	*out;    FILE	*temp;    char	*p;    /* First, figure out temporary names. */    if ((p = xstrrchr(f, '/')) == NULL) {	(void)strcpy(new, "substtmp.new");	(void)strcpy(old, "substtmp.old");    }    else {	*p = '\0';	(void)sprintf(new, "%s/substtmp.new", f);	(void)sprintf(old, "%s/substtmp.old", f);	*p = '/';    }    /* Test existences. */    if ((in = fopen(f, "r")) == NULL) {	(void)fprintf(stderr, "%s: can't open %s, %s\n",		argv0, f, xstrerror());	return;    }    if ((temp = fopen(new, "r")) != NULL) {	(void)fclose(in);	(void)fprintf(stderr, "%s: %s exists, cannot proceed\n",		argv0, new);	exit(1);    }    if ((temp = fopen(old, "r")) != NULL) {	(void)fprintf(stderr, "%s: %s exists, cannot proceed\n",		argv0, old);	exit(1);    }    temp = fopen(old, "w");    out = fopen(new, "w");    if (out == NULL || temp == NULL) {	if (temp != NULL)	    (void)fclose(temp);	(void)unlink(old);	if (out != NULL)	    (void)fclose(out);	(void)unlink(new);	(void)fprintf(stderr, "%s: cannot create temporaries %s and %s\n",		argv0, old, new);	exit(1);    }    (void)fclose(temp);    /* Generate the new version. */    for (i = 1, bad = 0; fgets(line, sizeof line, in) != NULL; i++) {	if ((p = xstrchr(line, '\n')) == NULL) {	    (void)fprintf(stderr,	      "%s: Line %d of %s is too long (or doesn't end with a newline)\n",		    argv0, i, f);	    bad++;	    break;	}	(void)fputs(line, out);	if ((p = istemplate(line)) != NULL) {	    if ((count = doline(f, out, p, Table, end)) < 0) {		bad++;		break;	    }	    if (count > 0) {		(void)fgets(line, sizeof line, in);		i++;	    }	    else		(void)fprintf(stderr,			"%s: %s:%d unknown parameter or bad line:\n\t%s",			argv0, f, i, p);	}    }    (void)fclose(in);    if (fflush(out) == EOF || fclose(out) == EOF) {	(void)fprintf(stderr, "%s: can't close %s, %s\n",		argv0, f, xstrerror());	bad++;    }    if (bad || cmp(new, f) == 0) {	(void)unlink(old);	(void)unlink(new);	(void)printf("%s: unchanged\n", f);	return;    }    /* Substitute new for old the only safe way -- ignore signals. */    (void)signal(SIGHUP, SIG_IGN);    (void)signal(SIGINT, SIG_IGN);    (void)signal(SIGTERM, SIG_IGN);    mv(f, old);    mv(new, f);    (void)signal(SIGHUP, SIG_DFL);    (void)signal(SIGINT, SIG_DFL);    (void)signal(SIGTERM, SIG_DFL);    (void)printf("%s: updated\n", f);    (void)unlink(old);}/***  Print usage message and exit.*/static voidUsage(){    (void)fprintf(stderr, "Usage: %s -f file victims...\n", argv0);    exit(1);}intmain(ac, av)    int		ac;    char	*av[];{    static char	NIL[] = "";    char	*ctlfile;    char	*p;    char	*dest;    FILE	*F;    int		i;    char	buff[LINESIZE];    char	name[PARAMSIZE];    PAIR	*Table;    PAIR	*tp;    /* Set defaults. */    ctlfile = NULL;    argv0 = av[0];    /* Parse JCL. */    while ((i = getopt(ac, av, "f:")) != EOF)	switch (i) {	default:	    Usage();	    /* NOTREACHED */	case 'f':	    if (ctlfile != NULL)		Usage();	    ctlfile = optarg;	    break;	}    ac -= optind;    av += optind;    /* Open control file, count lines, allocate table. */    if ((F = fopen(ctlfile, "r")) == NULL) {	(void)fprintf(stderr, "%s: Can't open %s to read it, %s\n",		argv0, ctlfile, xstrerror());	exit(1);    }    for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)	continue;    if ((Table = (PAIR *)malloc(i * sizeof *Table)) == NULL) {	(void)fprintf(stderr, "%s: Can't allocate %d table elements, %s\n",		argv0, i, xstrerror());	exit(1);    }    /* Now parse the table. */    (void)fseek(F, 0L, 0);    for (i = 1, tp = Table; fgets(buff, sizeof buff, F) != NULL; i++) {	if ((p = xstrchr(buff, '\n')) == NULL) {	    (void)fprintf(stderr, "%s: Line %d of %s is too long\n",		    argv0, i, ctlfile);	    exit(1);	}	*p = '\0';	/* Skip empty lines, comment lines, and all-blank lines. */	if (buff[0] == '\0' || buff[0] == '#')	    continue;	for (p = buff; WHITE(*p); p++)	    continue;	if (*p == '\0')	    continue;	/* Find end of first word, copy second word (or empty string) */	for (p = buff; *p && !WHITE(*p); p++)	    continue;	if (*p == '\0')	    tp->Value = NIL;	else {	    for (*p++ = '\0'; *p && WHITE(*p); p++)		continue;	    tp->Value = xstrdup(p);	    /* Turn things like \& into &. */	    for (p = dest = tp->Value; *p; p++)		*dest++ = (*p == '\\' && p[1] != '\0') ? *++p : *p;	    *dest = '\0';	}	/* Turn first word into something directly searchable. */	if (strlen(buff) > sizeof name - 4) {	    (void)fprintf(stderr, "%s: Parameter %s is too long\n",		    argv0, buff);	    exit(1);	}	(void)sprintf(name, "@<%s>@", buff);	tp->Name = xstrdup(name);	tp->Length = strlen(tp->Name);	tp++;    }    (void)fclose(F);    while (*av != NULL)	Process(*av++, Table, tp);    exit(0);    /* NOTREACHED */}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -