commit bash-20040107 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 12:52:47 -05:00
parent d3a24ed242
commit 5e13499c55
522 changed files with 295985 additions and 19526 deletions
+4
View File
@@ -0,0 +1,4 @@
cmp
wc
mkfifo
paste
+191
View File
@@ -0,0 +1,191 @@
#include <stdio.h>
#include <limits.h>
#include <locale.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "stdc.h"
#include "common.h"
#include "bashgetopt.h"
char *this_command_name = (char *)NULL;
void
builtin_error (const char *format, ...)
{
va_list args;
char *name;
name = get_name_for_error ();
fprintf (stderr, "%s: ", name);
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
int
no_options(list)
WORD_LIST *list;
{
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage ();
return (1);
}
return (0);
}
int
legal_number (string, result)
char *string;
long *result;
{
long value;
char *ep;
if (result)
*result = 0;
value = strtol (string, &ep, 10);
/* If *string is not '\0' but *ep is '\0' on return, the entire string
is valid. */
if (string && *string && *ep == '\0')
{
if (result)
*result = value;
/* The SunOS4 implementation of strtol() will happily ignore
overflow conditions, so this cannot do overflow correctly
on those systems. */
return 1;
}
return (0);
}
/* Return the number of elements in LIST, a generic list. */
int
list_length (list)
GENERIC_LIST *list;
{
register int i;
for (i = 0; list; list = list->next, i++);
return (i);
}
GENERIC_LIST *
reverse_list (list)
GENERIC_LIST *list;
{
register GENERIC_LIST *next, *prev;
for (prev = (GENERIC_LIST *)NULL; list; )
{
next = list->next;
list->next = prev;
prev = list;
list = next;
}
return (prev);
}
WORD_DESC *
make_bare_word (string)
char *string;
{
WORD_DESC *temp;
temp = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
if (*string)
temp->word = savestring (string);
else
{
temp->word = xmalloc (1);
temp->word[0] = '\0';
}
temp->flags = 0;
return (temp);
}
WORD_LIST *
make_word_list (word, link)
WORD_DESC *word;
WORD_LIST *link;
{
WORD_LIST *temp;
temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
temp->word = word;
temp->next = link;
return (temp);
}
void
builtin_usage()
{
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: usage: %s args\n", this_command_name, this_command_name);
fflush (stderr);
}
char *
xmalloc(s)
size_t s;
{
return (malloc (s));
}
WORD_LIST *
argv_to_word_list (array, copy, starting_index)
char **array;
int copy, starting_index;
{
WORD_LIST *list;
WORD_DESC *w;
int i, count;
if (array == 0 || array[0] == 0)
return (WORD_LIST *)NULL;
for (count = 0; array[count]; count++)
;
for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
{
w = make_bare_word (copy ? "" : array[i]);
if (copy)
{
free (w->word);
w->word = array[i];
}
list = make_word_list (w, list);
}
return (REVERSE_LIST(list, WORD_LIST *));
}
/* Convert a WORD_LIST into a C-style argv. Return the number of elements
in the list in *IP, if IP is non-null. A convenience function for
loadable builtins; also used by `test'. */
char **
make_builtin_argv (list, ip)
WORD_LIST *list;
int *ip;
{
char **argv;
argv = strvec_from_word_list (list, 0, 1, ip);
argv[0] = this_command_name;
return argv;
}
+10 -3
View File
@@ -247,10 +247,17 @@ struct stat *st;
struct passwd *pw;
struct group *gr;
char *owner;
int ma, mi, d;
ma = major (st->st_rdev);
mi = minor (st->st_rdev);
#if defined (makedev)
d = makedev (ma, mi);
#else
d = st->st_rdev & 0xFF;
#endif
printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
printf("Device (major/minor): %d (%d/%d)\n", (int) (st->st_dev & 0xFF),
(int) major (st->st_dev),
(int) minor (st->st_dev));
printf("Inode: %d\n", (int) st->st_ino);
printf("Mode: (%o) ", (int) st->st_mode);
printmode((int) st->st_mode);
+1
View File
@@ -0,0 +1 @@
/usr/local/build/chet/bash/bash-current/examples/loadables/perl/Makefile
+611
View File
@@ -0,0 +1,611 @@
This file is pushd.def, from which is created pushd.c. It implements the
builtins "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
$PRODUCES pushd.c
$BUILTIN pushd
$FUNCTION pushd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC pushd [dir | +N | -N] [-n]
Adds a directory to the top of the directory stack, or rotates
the stack, making the new top of the stack the current working
directory. With no arguments, exchanges the top two directories.
+N Rotates the stack so that the Nth directory (counting
from the left of the list shown by `dirs', starting with
zero) is at the top.
-N Rotates the stack so that the Nth directory (counting
from the right of the list shown by `dirs', starting with
zero) is at the top.
-n suppress the normal change of directory when adding directories
to the stack, so only the stack is manipulated.
dir adds DIR to the directory stack at the top, making it the
new current working directory.
You can see the directory stack with the `dirs' command.
$END
$BUILTIN popd
$FUNCTION popd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC popd [+N | -N] [-n]
Removes entries from the directory stack. With no arguments,
removes the top directory from the stack, and cd's to the new
top directory.
+N removes the Nth entry counting from the left of the list
shown by `dirs', starting with zero. For example: `popd +0'
removes the first directory, `popd +1' the second.
-N removes the Nth entry counting from the right of the list
shown by `dirs', starting with zero. For example: `popd -0'
removes the last directory, `popd -1' the next to last.
-n suppress the normal change of directory when removing directories
from the stack, so only the stack is manipulated.
You can see the directory stack with the `dirs' command.
$END
$BUILTIN dirs
$FUNCTION dirs_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC dirs [-clpv] [+N] [-N]
Display the list of currently remembered directories. Directories
find their way onto the list with the `pushd' command; you can get
back up through the list with the `popd' command.
The -l flag specifies that `dirs' should not print shorthand versions
of directories which are relative to your home directory. This means
that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag
causes `dirs' to print the directory stack with one entry per line,
prepending the directory name with its position in the stack. The -p
flag does the same thing, but the stack position is not prepended.
The -c flag clears the directory stack by deleting all of the elements.
+N displays the Nth entry counting from the left of the list shown by
dirs when invoked without options, starting with zero.
-N displays the Nth entry counting from the right of the list shown by
dirs when invoked without options, starting with zero.
$END
#include <config.h>
#if defined (PUSHD_AND_POPD)
#include <stdio.h>
#include <sys/param.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../maxpath.h"
#include "common.h"
#include "builtext.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
static char *m_badarg = "%s: bad argument";
/* The list of remembered directories. */
static char **pushd_directory_list = (char **)NULL;
/* Number of existing slots in this list. */
static int directory_list_size;
/* Offset to the end of the list. */
static int directory_list_offset;
static void pushd_error ();
static void clear_directory_stack ();
static int cd_to_string ();
static int change_to_temp ();
static int get_dirstack_index ();
static void add_dirstack_element ();
#define NOCD 0x01
#define ROTATE 0x02
#define LONGFORM 0x04
#define CLEARSTAK 0x08
int
pushd_builtin (list)
WORD_LIST *list;
{
char *temp, *current_directory, *top;
int j, flags;
long num;
char direction;
/* If there is no argument list then switch current and
top of list. */
if (list == 0)
{
if (directory_list_offset == 0)
{
builtin_error ("no other directory");
return (EXECUTION_FAILURE);
}
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = directory_list_offset - 1;
temp = pushd_directory_list[j];
pushd_directory_list[j] = current_directory;
j = change_to_temp (temp);
free (temp);
return j;
}
for (flags = 0; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
/* Let `pushd -' work like it used to. */
break;
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &num) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
if (direction == '-')
num = directory_list_offset - num;
if (num > directory_list_offset || num < 0)
{
pushd_error (directory_list_offset, list->word->word);
return (EXECUTION_FAILURE);
}
flags |= ROTATE;
}
else if (*list->word->word == '-')
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (flags & ROTATE)
{
/* Rotate the stack num times. Remember, the current
directory acts like it is part of the stack. */
temp = get_working_directory ("pushd");
if (num == 0)
{
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
do
{
top = pushd_directory_list[directory_list_offset - 1];
for (j = directory_list_offset - 2; j > -1; j--)
pushd_directory_list[j + 1] = pushd_directory_list[j];
pushd_directory_list[j + 1] = temp;
temp = top;
num--;
}
while (num);
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
if (list == 0)
return (EXECUTION_SUCCESS);
/* Change to the directory in list->word->word. Save the current
directory on the top of the stack. */
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS;
if (j == EXECUTION_SUCCESS)
{
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
dirs_builtin ((WORD_LIST *)NULL);
if (flags & NOCD)
free (current_directory);
return (EXECUTION_SUCCESS);
}
else
{
free (current_directory);
return (EXECUTION_FAILURE);
}
}
/* Pop the directory stack, and then change to the new top of the stack.
If LIST is non-null it should consist of a word +N or -N, which says
what element to delete from the stack. The default is the top one. */
int
popd_builtin (list)
WORD_LIST *list;
{
register int i;
long which;
int flags;
char direction;
char *which_word;
which_word = (char *)NULL;
for (flags = 0, which = 0L, direction = '+'; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &which) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
which_word = list->word->word;
}
else if (*list->word->word == '-')
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
/* Handle case of no specification, or top of stack specification. */
if ((direction == '+' && which == 0) ||
(direction == '-' && which == directory_list_offset))
{
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
: EXECUTION_SUCCESS;
if (i != EXECUTION_SUCCESS)
return (i);
free (pushd_directory_list[--directory_list_offset]);
}
else
{
/* Since an offset other than the top directory was specified,
remove that directory from the list and shift the remainder
of the list into place. */
i = (direction == '+') ? directory_list_offset - which : which;
free (pushd_directory_list[i]);
directory_list_offset--;
/* Shift the remainder of the list into place. */
for (; i < directory_list_offset; i++)
pushd_directory_list[i] = pushd_directory_list[i + 1];
}
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
/* Print the current list of directories on the directory stack. */
int
dirs_builtin (list)
WORD_LIST *list;
{
int flags, desired_index, index_flag, vflag;
long i;
char *temp, *w;
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
{
if (ISOPTION (list->word->word, 'l'))
{
flags |= LONGFORM;
}
else if (ISOPTION (list->word->word, 'c'))
{
flags |= CLEARSTAK;
}
else if (ISOPTION (list->word->word, 'v'))
{
vflag |= 2;
}
else if (ISOPTION (list->word->word, 'p'))
{
vflag |= 1;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (*list->word->word == '+' || *list->word->word == '-')
{
int sign;
if (legal_number (w = list->word->word + 1, &i) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
sign = (*list->word->word == '+') ? 1 : -1;
desired_index = get_dirstack_index (i, sign, &index_flag);
}
else
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
if (flags & CLEARSTAK)
{
clear_directory_stack ();
return (EXECUTION_SUCCESS);
}
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
{
pushd_error (directory_list_offset, w);
return (EXECUTION_FAILURE);
}
#define DIRSTACK_FORMAT(temp) \
(flags & LONGFORM) ? temp : polite_directory_format (temp)
/* The first directory printed is always the current working directory. */
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
{
temp = get_working_directory ("dirs");
if (temp == 0)
temp = savestring ("<no current directory>");
if (vflag & 2)
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
else
printf ("%s", DIRSTACK_FORMAT (temp));
free (temp);
if (index_flag)
{
putchar ('\n');
return EXECUTION_SUCCESS;
}
}
#define DIRSTACK_ENTRY(i) \
(flags & LONGFORM) ? pushd_directory_list[i] \
: polite_directory_format (pushd_directory_list[i])
/* Now print the requested directory stack entries. */
if (index_flag)
{
if (vflag & 2)
printf ("%2d %s", directory_list_offset - desired_index,
DIRSTACK_ENTRY (desired_index));
else
printf ("%s", DIRSTACK_ENTRY (desired_index));
}
else
for (i = directory_list_offset - 1; i >= 0; i--)
if (vflag >= 2)
printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
else
printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
putchar ('\n');
fflush (stdout);
return (EXECUTION_SUCCESS);
}
static void
pushd_error (offset, arg)
int offset;
char *arg;
{
if (offset == 0)
builtin_error ("directory stack empty");
else if (arg)
builtin_error ("%s: bad directory stack index", arg);
else
builtin_error ("bad directory stack index");
}
static void
clear_directory_stack ()
{
register int i;
for (i = 0; i < directory_list_offset; i++)
free (pushd_directory_list[i]);
directory_list_offset = 0;
}
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
so if the result is EXECUTION_FAILURE then an error message has already
been printed. */
static int
cd_to_string (name)
char *name;
{
WORD_LIST *tlist;
int result;
tlist = make_word_list (make_word (name), NULL);
result = cd_builtin (tlist);
dispose_words (tlist);
return (result);
}
static int
change_to_temp (temp)
char *temp;
{
int tt;
tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
if (tt == EXECUTION_SUCCESS)
dirs_builtin ((WORD_LIST *)NULL);
return (tt);
}
static void
add_dirstack_element (dir)
char *dir;
{
int j;
if (directory_list_offset == directory_list_size)
{
j = (directory_list_size += 10) * sizeof (char *);
pushd_directory_list = (char **)xrealloc (pushd_directory_list, j);
}
pushd_directory_list[directory_list_offset++] = dir;
}
static int
get_dirstack_index (ind, sign, indexp)
int ind, sign, *indexp;
{
if (indexp)
*indexp = sign > 0 ? 1 : 2;
/* dirs +0 prints the current working directory. */
/* dirs -0 prints last element in directory stack */
if (ind == 0 && sign > 0)
return 0;
else if (ind == directory_list_offset)
{
if (indexp)
*indexp = sign > 0 ? 2 : 1;
return 0;
}
else
return (sign > 0 ? directory_list_offset - ind : ind);
}
char *
get_dirstack_element (ind, sign)
int ind, sign;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
return (i < 0 || i > directory_list_offset) ? (char *)NULL
: pushd_directory_list[i];
}
void
set_dirstack_element (ind, sign, value)
int ind, sign;
char *value;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
if (ind == 0 || i < 0 || i > directory_list_offset)
return;
free (pushd_directory_list[i]);
pushd_directory_list[i] = savestring (value);
}
WORD_LIST *
get_directory_stack ()
{
register int i;
WORD_LIST *ret;
char *d, *t;
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
{
d = polite_directory_format (pushd_directory_list[i]);
ret = make_word_list (make_word (d), ret);
}
/* Now the current directory. */
d = get_working_directory ("dirstack");
i = 0; /* sentinel to decide whether or not to free d */
if (d == 0)
d = ".";
else
{
t = polite_directory_format (d);
/* polite_directory_format sometimes returns its argument unchanged.
If it does not, we can free d right away. If it does, we need to
mark d to be deleted later. */
if (t != d)
{
free (d);
d = t;
}
else /* t == d, so d is what we want */
i = 1;
}
ret = make_word_list (make_word (d), ret);
if (i)
free (d);
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
}
#endif /* PUSHD_AND_POPD */
+90
View File
@@ -0,0 +1,90 @@
static char *dirs_doc[] = {
"Display the list of currently remembered directories. Directories",
"find their way onto the list with the `pushd' command; you can get",
"back up through the list with the `popd' command.",
"",
"The -l flag specifies that `dirs' should not print shorthand versions",
"of directories which are relative to your home directory. This means",
"that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag",
"causes `dirs' to print the directory stack with one entry per line,",
"prepending the directory name with its position in the stack. The -p",
"flag does the same thing, but the stack position is not prepended.",
"The -c flag clears the directory stack by deleting all of the elements.",
"",
"+N displays the Nth entry counting from the left of the list shown by",
" dirs when invoked without options, starting with zero.",
"",
"-N displays the Nth entry counting from the right of the list shown by",
" dirs when invoked without options, starting with zero.",
(char *)NULL
};
static char *pushd_doc[] = {
"Adds a directory to the top of the directory stack, or rotates",
"the stack, making the new top of the stack the current working",
"directory. With no arguments, exchanges the top two directories.",
"",
"+N Rotates the stack so that the Nth directory (counting",
" from the left of the list shown by `dirs', starting with"
" zero) is at the top.",
"",
"-N Rotates the stack so that the Nth directory (counting",
" from the right of the list shown by `dirs', starting with"
" zero) is at the top.",
"",
"-n suppress the normal change of directory when adding directories",
" to the stack, so only the stack is manipulated.",
"",
"dir adds DIR to the directory stack at the top, making it the",
" new current working directory.",
"",
"You can see the directory stack with the `dirs' command.",
(char *)NULL
};
static char *popd_doc[] = {
"Removes entries from the directory stack. With no arguments,",
"removes the top directory from the stack, and cd's to the new",
"top directory.",
"",
"+N removes the Nth entry counting from the left of the list",
" shown by `dirs', starting with zero. For example: `popd +0'",
" removes the first directory, `popd +1' the second.",
"",
"-N removes the Nth entry counting from the right of the list",
" shown by `dirs', starting with zero. For example: `popd -0'",
" removes the last directory, `popd -1' the next to last.",
"",
"-n suppress the normal change of directory when removing directories",
" from the stack, so only the stack is manipulated.",
"",
"You can see the directory stack with the `dirs' command.",
(char *)NULL
};
struct builtin pushd_struct = {
"pushd",
pushd_builtin,
BUILTIN_ENABLED,
pushd_doc,
"pushd [+N | -N] [-n] [dir]",
0
};
struct builtin popd_struct = {
"popd",
popd_builtin,
BUILTIN_ENABLED,
popd_doc,
"popd [+N | -N] [-n]",
0
};
struct builtin dirs_struct = {
"dirs",
dirs_builtin,
BUILTIN_ENABLED,
dirs_doc,
"dirs [-clpv] [+N] [-N]",
0
};
+514
View File
@@ -0,0 +1,514 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
*/
#if !defined(BUILTIN) && !defined(SHELL)
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#endif
#ifndef lint
static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
#endif /* not lint */
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "stdc.h"
#if !defined (errno)
extern int errno;
#endif
static char sbuf[1024];
static int sblen;
/* Gee, I wish sprintf could be reliably counted upon to return the
number of characters written :-( */
#define PF(f, func) \
do { \
if (fieldwidth) \
if (precision) \
sprintf(sbuf, f, fieldwidth, precision, func); \
else \
sprintf(sbuf, f, fieldwidth, func); \
else if (precision) \
sprintf(sbuf, f, precision, func); \
else \
sprintf(sbuf, f, func); \
spaddstr (sbuf, strlen (sbuf)); \
} while (0)
static int asciicode __P((void));
static void escape __P((char *));
static int getchr __P((void));
static double getdouble __P((void));
static int getint __P((int *));
static int getlong __P((long *));
static char *getstr __P((void));
static char *mklong __P((char *, int));
static void usage __P((void));
static char **gargv;
static char *outstr;
static int outsize;
static int outind;
int sprintf_builtin ();
static int sprintf_main ();
static void spaddstr ();
extern char *this_command_name;
extern char *single_quote ();
extern char **make_builtin_argv ();
static char *sprintf_doc[] = {
"sprintf formats and outputs its arguments, after the second, under control",
"of the format and assigns the result to the variable named by its first",
"argument. The format is a character string which contains three types",
"of objects: plain characters, which are simply copied to the output string,",
"character escape sequences which are converted and copied to the output",
"string, and format specifications, each of which causes printing of the",
"next successive argument. In addition to the standard sprintf(3) formats,",
"%b means to expand escapes in the corresponding argument, and %q means",
"to quote the argument in a way that can be reused as shell input. Each",
"one of the format specifications must not expand to more than 1024",
"characters, though there is no limit on the total size of the output",
"string.",
(char *)NULL
};
struct builtin sprintf_struct = {
"sprintf",
sprintf_builtin,
BUILTIN_ENABLED,
sprintf_doc,
"sprintf var format [arguments]",
(char *)0
};
int
sprintf_builtin (list)
WORD_LIST *list;
{
int c, r;
char **v, *varname;
WORD_LIST *l;
SHELL_VAR *var;
if (list == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
}
varname = list->word->word;
list = list->next;
if (legal_identifier (varname) == 0)
{
builtin_error ("%s: not a legal variable name", varname);
return (EXECUTION_FAILURE);
}
outind = 0;
if (outstr == 0)
outstr = xmalloc (outsize = 64);
outstr[0] = '\0';
v = make_builtin_argv (list, &c);
r = sprintf_main (c, v);
free (v);
var = bind_variable (varname, outstr);
if (readonly_p (var))
{
builtin_error ("%s: readonly variable", varname);
return (EXECUTION_FAILURE);
}
return r;
}
static void
spaddstr(str, len)
char *str;
int len;
{
RESIZE_MALLOCED_BUFFER (outstr, outind, len, outsize, 64);
strcpy (outstr + outind, str);
outind += len;
}
static int
sprintf_main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
static char *skip1, *skip2;
int ch, end, fieldwidth, precision;
char convch, nextch, *format, *fmt, *start;
while ((ch = getopt(argc, argv, "")) != EOF)
switch (ch) {
case '?':
default:
usage();
return (1);
}
argc -= optind;
argv += optind;
if (argc < 1) {
usage();
return (1);
}
/*
* Basic algorithm is to scan the format string for conversion
* specifications -- once one is found, find out if the field
* width or precision is a '*'; if it is, gather up value. Note,
* format strings are reused as necessary to use up the provided
* arguments, arguments of zero/null string are provided to use
* up the format string.
*/
skip1 = "#-+ 0";
skip2 = "*0123456789";
escape(fmt = format = *argv); /* backslash interpretation */
gargv = ++argv;
for (;;) {
end = 0;
/* find next format specification */
next: for (start = fmt;; ++fmt) {
if (!*fmt) {
/* avoid infinite loop */
if (end == 1) {
warnx("missing format character",
NULL, NULL);
return (1);
}
end = 1;
if (fmt > start)
(void)printf("%s", start);
if (!*gargv)
return (0);
fmt = format;
goto next;
}
/* %% prints a % */
if (*fmt == '%') {
if (*++fmt != '%')
break;
*fmt++ = '\0';
(void)printf("%s", start);
goto next;
}
}
/* skip to field width */
for (; strchr(skip1, *fmt); ++fmt);
if (*fmt == '*') {
if (getint(&fieldwidth))
return (1);
} else
fieldwidth = 0;
/* skip to possible '.', get following precision */
for (; strchr(skip2, *fmt); ++fmt);
if (*fmt == '.')
++fmt;
if (*fmt == '*') {
if (getint(&precision))
return (1);
} else
precision = 0;
/* skip to conversion char */
for (; strchr(skip2, *fmt); ++fmt);
if (!*fmt) {
warnx("missing format character", NULL, NULL);
return (1);
}
convch = *fmt;
nextch = *++fmt;
*fmt = '\0';
switch(convch) {
case 'c': {
char p;
p = getchr();
PF(start, p);
break;
}
case 's': {
char *p;
p = getstr();
PF(start, p);
break;
}
case 'b': { /* expand escapes in argument */
char *p;
p = getstr();
escape(p);
PF("%s", p);
break;
}
case 'q': { /* print with shell single quoting */
char *p, *p2;
p = getstr();
p2 = single_quote(p);
PF("%s", p2);
free(p2);
break;
}
case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
long p;
char *f;
if ((f = mklong(start, convch)) == NULL)
return (1);
if (getlong(&p))
return (1);
PF(f, p);
break;
}
case 'e': case 'E': case 'f': case 'g': case 'G': {
double p;
p = getdouble();
PF(start, p);
break;
}
default:
warnx("illegal format character", NULL, NULL);
return (1);
}
*fmt = nextch;
}
/* NOTREACHED */
}
static char *
mklong(str, ch)
char *str;
int ch;
{
static char copy[64];
int len;
len = strlen(str) + 2;
memmove(copy, str, len - 3);
copy[len - 3] = 'l';
copy[len - 2] = ch;
copy[len - 1] = '\0';
return (copy);
}
static void
escape(fmt)
register char *fmt;
{
register char *store;
register int value, c;
for (store = fmt; c = *fmt; ++fmt, ++store) {
if (c != '\\') {
*store = c;
continue;
}
switch (*++fmt) {
case '\0': /* EOS, user error */
*store = '\\';
*++store = '\0';
return;
case '\\': /* backslash */
case '\'': /* single quote */
*store = *fmt;
break;
case 'a': /* bell/alert */
*store = '\7';
break;
case 'b': /* backspace */
*store = '\b';
break;
case 'c':
return;
case 'e':
case 'E':
*store = '\033';
break;
case 'f': /* form-feed */
*store = '\f';
break;
case 'n': /* newline */
*store = '\n';
break;
case 'r': /* carriage-return */
*store = '\r';
break;
case 't': /* horizontal tab */
*store = '\t';
break;
case 'v': /* vertical tab */
*store = '\13';
break;
/* octal constant */
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
for (c = 3, value = 0;
c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
value <<= 3;
value += *fmt - '0';
}
--fmt;
*store = value;
break;
default:
*store = *fmt;
break;
}
}
*store = '\0';
}
static int
getchr()
{
if (!*gargv)
return ('\0');
return ((int)**gargv++);
}
static char *
getstr()
{
if (!*gargv)
return ("");
return (*gargv++);
}
static char *Number = "+-.0123456789";
static int
getint(ip)
int *ip;
{
long val;
if (getlong(&val))
return (1);
if (val > INT_MAX) {
warnx("%s: %s", *gargv, strerror(ERANGE));
return (1);
}
*ip = val;
return (0);
}
static int
getlong(lp)
long *lp;
{
long val;
char *ep;
if (!*gargv) {
*lp = 0;
return (0);
}
if (strchr(Number, **gargv)) {
errno = 0;
val = strtol(*gargv, &ep, 0);
if (*ep != '\0') {
warnx("%s: illegal number", *gargv, NULL);
return (1);
}
if (errno == ERANGE)
if (val == LONG_MAX) {
warnx("%s: %s", *gargv, strerror(ERANGE));
return (1);
}
if (val == LONG_MIN) {
warnx("%s: %s", *gargv, strerror(ERANGE));
return (1);
}
*lp = val;
++gargv;
return (0);
}
*lp = (long)asciicode();
return (0);
}
static double
getdouble()
{
if (!*gargv)
return ((double)0);
if (strchr(Number, **gargv))
return (atof(*gargv++));
return ((double)asciicode());
}
static int
asciicode()
{
register int ch;
ch = **gargv;
if (ch == '\'' || ch == '"')
ch = (*gargv)[1];
++gargv;
return (ch);
}
static void
usage()
{
(void)fprintf(stderr, "usage: printf format [arg ...]\n");
}
+183
View File
@@ -0,0 +1,183 @@
/*
* Originally from
* http://www.excessus.demon.co.uk/misc-hacks/index.html#xtitle
*/
/*
* Made into a loadable builtin by chet@po.cwru.edu.
*/
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#ifdef BASH_BUILTIN
#include "shell.h"
#include "builtins.h"
#include "bashgetopt.h"
#endif
#ifdef BASH_BUILTIN
int xtitle_builtin(WORD_LIST *list)
#else
int main(int argc, char *argv[])
#endif
{
int query = 0;
int fd;
int openned = 0;
#ifdef BASH_BUILTIN
reset_internal_getopt();
#endif
for (;;) {
#ifdef BASH_BUILTIN
int i;
i = internal_getopt(list, "q");
#else
int i = getopt(argc, argv, "q");
#endif
if (i < 0)
break;
switch (i) {
case 'q':
query = 1;
break;
default:
#ifdef BASH_BUILTIN
builtin_usage();
#else
fprintf(stderr, "usage: xtitle [-q] [string]\n");
#endif
return (1);
}
}
#ifdef BASH_BUILTIN
if (!query && loptend == 0) {
#else
if (!query && optind == argc) {
#endif
fprintf(stderr, "xtitle: no string to set\n");
return (1);
}
{
char *t = getenv("TERM");
if (!t || strncmp(t, "xterm", 5))
return (0);
}
if (isatty(0))
fd = 0;
else {
fd = open("/dev/tty", O_RDWR);
if (fd < 0) {
fprintf(stderr, "xtitle: couldn't open terminal: %s", strerror(errno));
return (1);
}
openned = 1;
}
if (!query) {
#ifdef BASH_BUILTIN
WORD_LIST *l = loptend;
char sp = ' ';
write(fd, "\33]0;", 4);
while (l) {
write(fd, l->word->word, strlen(l->word->word));
if (l->next)
write(fd, &sp, 1);
l = l->next;
}
write(fd, "\33\\", 2);
#else
int i;
char sp = ' ';
write(fd, "\33]0;", 4);
for (i = optind; i < argc; i++) {
write(fd, argv[i], strlen(argv[i]));
if (i < argc - 1)
write(fd, &sp, 1);
}
write(fd, "\33\\", 2);
#endif
} else {
struct termios o, n;
char hack;
int state = 0;
tcgetattr(fd, &o);
n = o;
n.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
n.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
n.c_cflag &= ~(CSIZE|PARENB);
n.c_cflag |= CS8;
tcsetattr(fd, TCSAFLUSH, &n);
write(fd, "\33[21t", 5);
while (state != -1) {
if (read(fd, &hack, 1) < 1)
break;
switch (state) {
case 0:
if (hack == '\33') state = 1;
break;
case 1:
if (hack == ']') state = 2; else state = 0;
break;
case 2:
if (hack == 'l') state = 3; else state = 0;
break;
case 3:
if (hack == '\33') state = 4; else putchar(hack);
break;
case 4:
if (hack == '\\') { state = -1; putchar('\n'); }
else { putchar('\33'); putchar(hack); state = 3; }
break;
}
}
tcsetattr(fd, TCSAFLUSH, &o);
}
if (openned)
close(fd);
return (0);
}
#ifdef BASH_BUILTIN
static char *xtitle_doc[] = {
"Either set or read the title of the current xterm window. With the",
"-q option, writes the current xterm title to standard output. Without",
"the -q option, sets the xterm title to be the arguments given,",
"separated by space characters. [By Mark Wooding, mdw@nsict.org]",
0
};
struct builtin xtitle_struct = {
"xtitle",
xtitle_builtin,
BUILTIN_ENABLED,
xtitle_doc,
"xtitle [-q] [arguments]",
0
};
#endif