diff options
Diffstat (limited to 'examples/loadables')
-rw-r--r-- | examples/loadables/Makefile.in | 8 | ||||
-rw-r--r-- | examples/loadables/cut.c | 376 | ||||
-rw-r--r-- | examples/loadables/finfo.c | 6 | ||||
-rw-r--r-- | examples/loadables/getconf.c | 75 | ||||
-rw-r--r-- | examples/loadables/push.c | 95 | ||||
-rw-r--r-- | examples/loadables/realpath.c | 119 |
6 files changed, 675 insertions, 4 deletions
diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in index ab3c5d7e..95710890 100644 --- a/examples/loadables/Makefile.in +++ b/examples/loadables/Makefile.in @@ -67,7 +67,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \ ALLPROG = print truefalse sleep pushd finfo logname basename dirname \ tty pathchk tee head mkdir rmdir sprintf printenv id whoami \ - uname sync push ln unlink + uname sync push ln unlink cut realpath OTHERPROG = necho getconf hello cat all: $(SHOBJ_STATUS) @@ -164,6 +164,11 @@ ln: ln.o unlink: unlink.o $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS) +cut: cut.o + $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS) + +realpath: realpath.o + $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) # pushd is a special case. We use the same source that the builtin version # uses, with special compilation options. @@ -214,3 +219,4 @@ uname.o: uname.c sync.o: sync.c push.o: push.c mkdir.o: mkdir.c +realpath.o: realpath.c diff --git a/examples/loadables/cut.c b/examples/loadables/cut.c new file mode 100644 index 00000000..d874034a --- /dev/null +++ b/examples/loadables/cut.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static const char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95"; +#endif /* not lint */ + +#include <config.h> + +#include <ctype.h> +#include <stdio.h> +#include <errno.h> + +#include "bashansi.h" + +#ifdef HAVE_LIMITS_H +# include <limits.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" + +#if !defined (errno) +extern int errno; +#endif + +#if !defined (_POSIX2_LINE_MAX) +# define _POSIX2_LINE_MAX 2048 +#endif + +static int cflag; +static char dchar; +static int dflag; +static int fflag; +static int sflag; + +static int autostart, autostop, maxval; +static char positions[_POSIX2_LINE_MAX + 1]; + +static int c_cut __P((FILE *, char *)); +static int f_cut __P((FILE *, char *)); +static int get_list __P((char *)); +static char *_cut_strsep __P((char **, const char *)); + +int +cut_builtin(list) + WORD_LIST *list; +{ + FILE *fp; + int (*fcn) __P((FILE *, char *)) = NULL; + int ch; + + fcn = NULL; + dchar = '\t'; /* default delimiter is \t */ + + /* Since we don't support multi-byte characters, the -c and -b + options are equivalent, and the -n option is meaningless. */ + reset_internal_getopt (); + while ((ch = internal_getopt (list, "b:c:d:f:sn")) != -1) + switch(ch) { + case 'b': + case 'c': + fcn = c_cut; + if (get_list(list_optarg) < 0) + return (EXECUTION_FAILURE); + cflag = 1; + break; + case 'd': + dchar = *list_optarg; + dflag = 1; + break; + case 'f': + fcn = f_cut; + if (get_list(list_optarg) < 0) + return (EXECUTION_FAILURE); + fflag = 1; + break; + case 's': + sflag = 1; + break; + case 'n': + break; + case '?': + default: + builtin_usage(); + return (EX_USAGE); + } + + list = loptend; + + if (fflag) { + if (cflag) { + builtin_usage(); + return (EX_USAGE); + } + } else if (!cflag || dflag || sflag) { + builtin_usage(); + return (EX_USAGE); + } + + if (list) { + while (list) { + fp = fopen(list->word->word, "r"); + if (fp == 0) { + builtin_error("%s", list->word->word); + return (EXECUTION_FAILURE); + } + ch = (*fcn)(fp, list->word->word); + (void)fclose(fp); + if (ch < 0) + return (EXECUTION_FAILURE); + list = list->next; + } + } else { + ch = (*fcn)(stdin, "stdin"); + if (ch < 0) + return (EXECUTION_FAILURE); + } + + return (EXECUTION_SUCCESS); +} + +static int +get_list(list) + char *list; +{ + int setautostart, start, stop; + char *pos; + char *p; + + /* + * set a byte in the positions array to indicate if a field or + * column is to be selected; use +1, it's 1-based, not 0-based. + * This parser is less restrictive than the Draft 9 POSIX spec. + * POSIX doesn't allow lists that aren't in increasing order or + * overlapping lists. We also handle "-3-5" although there's no + * real reason too. + */ + for (; (p = _cut_strsep(&list, ", \t")) != NULL;) { + setautostart = start = stop = 0; + if (*p == '-') { + ++p; + setautostart = 1; + } + if (isdigit((unsigned char)*p)) { + start = stop = strtol(p, &p, 10); + if (setautostart && start > autostart) + autostart = start; + } + if (*p == '-') { + if (isdigit((unsigned char)p[1])) + stop = strtol(p + 1, &p, 10); + if (*p == '-') { + ++p; + if (!autostop || autostop > stop) + autostop = stop; + } + } + if (*p) { + builtin_error("[-cf] list: illegal list value"); + return -1; + } + if (!stop || !start) { + builtin_error("[-cf] list: values may not include zero"); + return -1; + } + if (stop > _POSIX2_LINE_MAX) { + builtin_error("[-cf] list: %d too large (max %d)", + stop, _POSIX2_LINE_MAX); + return -1; + } + if (maxval < stop) + maxval = stop; + for (pos = positions + start; start++ <= stop; *pos++ = 1); + } + + /* overlapping ranges */ + if (autostop && maxval > autostop) + maxval = autostop; + + /* set autostart */ + if (autostart) + memset(positions + 1, '1', autostart); + + return 0; +} + +/* ARGSUSED */ +static int +c_cut(fp, fname) + FILE *fp; + char *fname; +{ + int ch, col; + char *pos; + + ch = 0; + for (;;) { + pos = positions + 1; + for (col = maxval; col; --col) { + if ((ch = getc(fp)) == EOF) + return; + if (ch == '\n') + break; + if (*pos++) + (void)putchar(ch); + } + if (ch != '\n') { + if (autostop) + while ((ch = getc(fp)) != EOF && ch != '\n') + (void)putchar(ch); + else + while ((ch = getc(fp)) != EOF && ch != '\n'); + } + (void)putchar('\n'); + } + return (0); +} + +static int +f_cut(fp, fname) + FILE *fp; + char *fname; +{ + int ch, field, isdelim; + char *pos, *p, sep; + int output; + char lbuf[_POSIX2_LINE_MAX + 1]; + + for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) { + output = 0; + for (isdelim = 0, p = lbuf;; ++p) { + if (!(ch = *p)) { + builtin_error("%s: line too long.", fname); + return -1; + } + /* this should work if newline is delimiter */ + if (ch == sep) + isdelim = 1; + if (ch == '\n') { + if (!isdelim && !sflag) + (void)printf("%s", lbuf); + break; + } + } + if (!isdelim) + continue; + + pos = positions + 1; + for (field = maxval, p = lbuf; field; --field, ++pos) { + if (*pos) { + if (output++) + (void)putchar(sep); + while ((ch = *p++) != '\n' && ch != sep) + (void)putchar(ch); + } else { + while ((ch = *p++) != '\n' && ch != sep) + continue; + } + if (ch == '\n') + break; + } + if (ch != '\n') { + if (autostop) { + if (output) + (void)putchar(sep); + for (; (ch = *p) != '\n'; ++p) + (void)putchar(ch); + } else + for (; (ch = *p) != '\n'; ++p); + } + (void)putchar('\n'); + } + return (0); +} + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +static char * +_cut_strsep(stringp, delim) + register char **stringp; + register const char *delim; +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +static char *cut_doc[] = { + "Select portions of each line (as specified by LIST) from each FILE", + "(by default, the standard input), and write them to the standard output.", + "Items specified by LIST are either column positions or fields delimited", + "by a special character. Column numbering starts at 1.", + (char *)0 +}; + +struct builtin cut_struct = { + "cut", + cut_builtin, + BUILTIN_ENABLED, + cut_doc, + "cut -b list [-n] [file ...] OR cut -c list [file ...] OR cut -f list [-s] [-d delim] [file ...]", + 0 +}; diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c index ab3c9a41..5fdb6d43 100644 --- a/examples/loadables/finfo.c +++ b/examples/loadables/finfo.c @@ -9,6 +9,7 @@ #include <grp.h> #include <errno.h> +#include "bashansi.h" #include "shell.h" #include "builtins.h" #include "common.h" @@ -17,7 +18,6 @@ extern int errno; #endif -extern char *strrchr(); extern char **make_builtin_argv (); static int printst(); @@ -137,7 +137,11 @@ char *f; fd = lfd; r = fstat(fd, &st); } else +#ifdef HAVE_LSTAT + r = lstat(f, &st); +#else r = stat(f, &st); +#endif if (r < 0) { builtin_error("%s: cannot stat: %s", f, strerror(errno)); return ((struct stat *)0); diff --git a/examples/loadables/getconf.c b/examples/loadables/getconf.c index 64407cc9..cb8344ca 100644 --- a/examples/loadables/getconf.c +++ b/examples/loadables/getconf.c @@ -55,7 +55,7 @@ struct conf_variable { const char *name; - enum { SYSCONF, CONFSTR, PATHCONF, CONSTANT } type; + enum { SYSCONF, CONFSTR, PATHCONF, CONSTANT, G_UNDEF } type; long value; }; @@ -105,19 +105,55 @@ static const struct conf_variable conf_table[] = #endif /* _CS_XBS5_ILP32_OFF32_CFLAGS */ /* POSIX.2 Utility Limit Minimum Values */ +#ifdef _POSIX2_BC_BASE_MAX { "POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, +#else + { "POSIX2_BC_BASE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_DIM_MAX { "POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, +#else + { "POSIX2_BC_DIM_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_SCALE_MAX { "POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, +#else + { "POSIX2_BC_SCALE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_STRING_MAX { "POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, +#else + { "POSIX2_BC_STRING_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_COLL_WEIGHTS_MAX { "POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, +#else + { "POSIX2_COLL_WEIGHTS_MAX", G_UNDEF, -1 }, +#endif #if defined (_POSIX2_EQUIV_CLASS_MAX) { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, #endif +#ifdef _POSIX2_EXPR_NEST_MAX { "POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, +#else + { "POSIX2_EXPR_NEST_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_LINE_MAX { "POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, +#else + { "POSIX2_LINE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_RE_DUP_MAX { "POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, +#else + { "POSIX2_RE_DUP_MAX", G_UNDEF, -1 }, +#endif #if defined (_POSIX2_VERSION) { "POSIX2_VERSION", CONSTANT, _POSIX2_VERSION }, +#else +# if !defined (_SC_2_VERSION) + { "POSIX2_VERSION", G_UNDEF, -1 }, +# endif #endif /* POSIX.1 Minimum Values */ @@ -146,20 +182,50 @@ static const struct conf_variable conf_table[] = { "RE_DUP_MAX", SYSCONF, _SC_RE_DUP_MAX }, /* POSIX.2 Optional Facility Configuration Values */ +#ifdef _SC_2_C_BIND { "POSIX2_C_BIND", SYSCONF, _SC_2_C_BIND }, +#else + { "POSIX2_C_BIND", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_C_DEV { "POSIX2_C_DEV", SYSCONF, _SC_2_C_DEV }, +#else + { "POSIX2_C_DEV", G_UNDEF, -1 }, +#endif #if defined (_SC_2_C_VERSION) { "POSIX2_C_VERSION", SYSCONF, _SC_2_C_VERSION }, +#else + { "POSIX2_C_VERSION", G_UNDEF, -1 }, #endif #if defined (_SC_2_CHAR_TERM) { "POSIX2_CHAR_TERM", SYSCONF, _SC_2_CHAR_TERM }, +#else + { "POSIX2_CHAR_TERM", G_UNDEF, -1 }, #endif +#ifdef _SC_2_FORT_DEV { "POSIX2_FORT_DEV", SYSCONF, _SC_2_FORT_DEV }, +#else + { "POSIX2_FORT_DEV", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_FORT_RUN { "POSIX2_FORT_RUN", SYSCONF, _SC_2_FORT_RUN }, +#else + { "POSIX2_FORT_RUN", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_LOCALEDEF { "POSIX2_LOCALEDEF", SYSCONF, _SC_2_LOCALEDEF }, +#else + { "POSIX2_LOCALEDEF", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_SW_DEV { "POSIX2_SW_DEV", SYSCONF, _SC_2_SW_DEV }, +#else + { "POSIX2_SW_DEV", G_UNDEF, -1 }, +#endif #if defined (_SC2_UPE) { "POSIX2_UPE", SYSCONF, _SC_2_UPE }, +#else + { "POSIX2_UPE", G_UNDEF, -1 }, #endif #if !defined (_POSIX2_VERSION) && defined (_SC_2_VERSION) { "POSIX2_VERSION" SYSCONF, _SC_2_VERSION }, @@ -449,6 +515,10 @@ int all; size_t slen; switch (cp->type) { + case G_UNDEF: + printf("undefined\n"); + break; + case CONSTANT: printf("%ld\n", cp->value); break; @@ -508,7 +578,8 @@ int all; break; } - return (ferror(stdout) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); + return ((ferror(stdout) || cp->type == G_UNDEF) ? EXECUTION_FAILURE + : EXECUTION_SUCCESS); } static int diff --git a/examples/loadables/push.c b/examples/loadables/push.c new file mode 100644 index 00000000..497ecd0e --- /dev/null +++ b/examples/loadables/push.c @@ -0,0 +1,95 @@ +/* + * push - anyone remember TOPS-20? + * + */ + +#include <config.h> +#include <stdio.h> +#include <errno.h> + +#include "builtins.h" +#include "shell.h" +#include "jobs.h" +#include "bashgetopt.h" + +#ifndef errno +extern int errno; +#endif + +extern int dollar_dollar_pid; +extern int last_command_exit_value; + +int +push_builtin (list) + WORD_LIST *list; +{ + pid_t pid; + int xstatus, opt; + + xstatus = EXECUTION_SUCCESS; + reset_internal_getopt (); + while ((opt = internal_getopt (list, "")) != -1) + { + switch (opt) + { + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + pid = make_child (savestring ("push"), 0); + if (pid == -1) + { + builtin_error ("cannot fork: %s", strerror (errno)); + return (EXECUTION_FAILURE); + } + else if (pid == 0) + { + /* Shell variable adjustments: $SHLVL, $$, $PPID, $! */ + adjust_shell_level (1); + dollar_dollar_pid = getpid (); + set_ppid (); + + /* Clean up job control stuff. */ + stop_making_children (); + cleanup_the_pipeline (); + delete_all_jobs (0); + + last_asynchronous_pid = NO_PID; + + /* Make sure the job control code has the right values for + the shell's process group and tty process group, and that + the signals are set correctly for job control. */ + initialize_job_control (0); + initialize_job_signals (); + + /* And read commands until exit. */ + reader_loop (); + exit_shell (last_command_exit_value); + } + else + { + stop_pipeline (0, (COMMAND *)NULL); + xstatus = wait_for (pid); + return (xstatus); + } +} + +char *push_doc[] = { + "Create a child that is an exact duplicate of the running shell", + "and wait for it to exit. The $SHLVL, $!, $$, and $PPID variables", + "are adjusted in the child. The return value is the exit status", + "of the child.", + (char *)NULL +}; + +struct builtin push_struct = { + "push", + push_builtin, + BUILTIN_ENABLED, + push_doc, + "push", + 0 +}; diff --git a/examples/loadables/realpath.c b/examples/loadables/realpath.c new file mode 100644 index 00000000..16478b79 --- /dev/null +++ b/examples/loadables/realpath.c @@ -0,0 +1,119 @@ +/* + * realpath -- canonicalize pathnames, resolving symlinks + * + * usage: realpath [-csv] pathname [pathname...] + * + * options: -c check whether or not each resolved path exists + * -s no output, exit status determines whether path is valid + * -v produce verbose output + * + * + * exit status: 0 if all pathnames resolved + * 1 if any of the pathname arguments could not be resolved + * + * + * Bash loadable builtin version + * + * Chet Ramey + * chet@po.cwru.edu + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include "bashansi.h" +#include <maxpath.h> +#include <errno.h> + +#include "builtins.h" +#include "shell.h" +#include "bashgetopt.h" + +#ifndef errno +extern int errno; +#endif + +extern char *sh_realpath(); + +realpath_builtin(list) +WORD_LIST *list; +{ + int opt, cflag, vflag, sflag, es; + char *r, realbuf[PATH_MAX], *p; + struct stat sb; + + if (list == 0) { + builtin_usage(); + return (EX_USAGE); + } + + vflag = cflag = sflag = 0; + reset_internal_getopt(); + while ((opt = internal_getopt (list, "csv")) != -1) { + switch (opt) { + case 'c': + cflag = 1; + break; + case 's': + sflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + usage(); + } + } + + list = loptend; + + if (list == 0) + usage(); + + for (es = EXECUTION_SUCCESS; list; list = list->next) { + p = list->word->word; + r = sh_realpath(p, realbuf); + if (r == 0) { + es = EXECUTION_FAILURE; + if (sflag == 0) + builtin_error("%s: cannot resolve: %s", p, strerror(errno)); + continue; + } + if (cflag && (stat(realbuf, &sb) < 0)) { + es = EXECUTION_FAILURE; + if (sflag == 0) + builtin_error("%s: %s", p, strerror(errno)); + continue; + } + if (sflag == 0) { + if (vflag) + printf ("%s -> ", p); + printf("%s\n", realbuf); + } + } + return es; +} + +char *realpath_doc[] = { + "Display the canonicalized version of each PATHNAME argument, resolving", + "symbolic links. The -c option checks whether or not each resolved name", + "exists. The -s option produces no output; the exit status determines the", + "valididty of each PATHNAME. The -v option produces verbose output. The", + "exit status is 0 if each PATHNAME was resolved; non-zero otherwise.", + (char *)NULL +}; + +struct builtin realpath_struct = { + "realpath", /* builtin name */ + realpath_builtin, /* function implementing the builtin */ + BUILTIN_ENABLED, /* initial flags for builtin */ + realpath_doc, /* array of long documentation strings */ + "realpath [-csv] pathname [pathname...]", /* usage synopsis */ + 0 /* reserved for internal use */ +}; |