mirror of
https://github.com/coreutils/coreutils.git
synced 2024-11-26 11:23:47 +08:00
Initial revision
This commit is contained in:
parent
144b82c6c2
commit
ccbd1d7dc5
194
lib/alloca.c
Normal file
194
lib/alloca.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
alloca -- (mostly) portable public-domain implementation -- D A Gwyn
|
||||
|
||||
last edit: 86/05/30 rms
|
||||
include config.h, since on VMS it renames some symbols.
|
||||
Use xmalloc instead of malloc.
|
||||
|
||||
This implementation of the PWB library alloca() function,
|
||||
which is used to allocate space off the run-time stack so
|
||||
that it is automatically reclaimed upon procedure exit,
|
||||
was inspired by discussions with J. Q. Johnson of Cornell.
|
||||
|
||||
It should work under any C implementation that uses an
|
||||
actual procedure stack (as opposed to a linked list of
|
||||
frames). There are some preprocessor constants that can
|
||||
be defined when compiling for your specific system, for
|
||||
improved efficiency; however, the defaults should be okay.
|
||||
|
||||
The general concept of this implementation is to keep
|
||||
track of all alloca()-allocated blocks, and reclaim any
|
||||
that are found to be deeper in the stack than the current
|
||||
invocation. This heuristic does not reclaim storage as
|
||||
soon as it becomes invalid, but it will do so eventually.
|
||||
|
||||
As a special case, alloca(0) reclaims storage without
|
||||
allocating any. It is a good idea to use alloca(0) in
|
||||
your main control loop, etc. to force garbage collection.
|
||||
*/
|
||||
#ifndef lint
|
||||
static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
|
||||
#endif
|
||||
|
||||
#ifdef emacs
|
||||
#include "config.h"
|
||||
#ifdef static
|
||||
/* actually, only want this if static is defined as ""
|
||||
-- this is for usg, in which emacs must undefine static
|
||||
in order to make unexec workable
|
||||
*/
|
||||
#ifndef STACK_DIRECTION
|
||||
you
|
||||
lose
|
||||
-- must know STACK_DIRECTION at compile-time
|
||||
#endif /* STACK_DIRECTION undefined */
|
||||
#endif /* static */
|
||||
#endif /* emacs */
|
||||
|
||||
#ifndef alloca /* If compiling with GCC, this file's not needed. */
|
||||
|
||||
#ifdef __STDC__
|
||||
typedef void *pointer; /* generic pointer type */
|
||||
#else
|
||||
typedef char *pointer; /* generic pointer type */
|
||||
#endif
|
||||
|
||||
#define NULL 0 /* null pointer constant */
|
||||
|
||||
extern void free();
|
||||
extern pointer xmalloc();
|
||||
|
||||
/*
|
||||
Define STACK_DIRECTION if you know the direction of stack
|
||||
growth for your system; otherwise it will be automatically
|
||||
deduced at run-time.
|
||||
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown
|
||||
*/
|
||||
|
||||
#ifndef STACK_DIRECTION
|
||||
#define STACK_DIRECTION 0 /* direction unknown */
|
||||
#endif
|
||||
|
||||
#if STACK_DIRECTION != 0
|
||||
|
||||
#define STACK_DIR STACK_DIRECTION /* known at compile-time */
|
||||
|
||||
#else /* STACK_DIRECTION == 0; need run-time code */
|
||||
|
||||
static int stack_dir; /* 1 or -1 once known */
|
||||
#define STACK_DIR stack_dir
|
||||
|
||||
static void
|
||||
find_stack_direction (/* void */)
|
||||
{
|
||||
static char *addr = NULL; /* address of first
|
||||
`dummy', once known */
|
||||
auto char dummy; /* to get stack address */
|
||||
|
||||
if (addr == NULL)
|
||||
{ /* initial entry */
|
||||
addr = &dummy;
|
||||
|
||||
find_stack_direction (); /* recurse once */
|
||||
}
|
||||
else /* second entry */
|
||||
if (&dummy > addr)
|
||||
stack_dir = 1; /* stack grew upward */
|
||||
else
|
||||
stack_dir = -1; /* stack grew downward */
|
||||
}
|
||||
|
||||
#endif /* STACK_DIRECTION == 0 */
|
||||
|
||||
/*
|
||||
An "alloca header" is used to:
|
||||
(a) chain together all alloca()ed blocks;
|
||||
(b) keep track of stack depth.
|
||||
|
||||
It is very important that sizeof(header) agree with malloc()
|
||||
alignment chunk size. The following default should work okay.
|
||||
*/
|
||||
|
||||
#ifndef ALIGN_SIZE
|
||||
#define ALIGN_SIZE sizeof(double)
|
||||
#endif
|
||||
|
||||
typedef union hdr
|
||||
{
|
||||
char align[ALIGN_SIZE]; /* to force sizeof(header) */
|
||||
struct
|
||||
{
|
||||
union hdr *next; /* for chaining headers */
|
||||
char *deep; /* for stack depth measure */
|
||||
} h;
|
||||
} header;
|
||||
|
||||
/*
|
||||
alloca( size ) returns a pointer to at least `size' bytes of
|
||||
storage which will be automatically reclaimed upon exit from
|
||||
the procedure that called alloca(). Originally, this space
|
||||
was supposed to be taken from the current stack frame of the
|
||||
caller, but that method cannot be made to work for some
|
||||
implementations of C, for example under Gould's UTX/32.
|
||||
*/
|
||||
|
||||
static header *last_alloca_header = NULL; /* -> last alloca header */
|
||||
|
||||
pointer
|
||||
alloca (size) /* returns pointer to storage */
|
||||
unsigned size; /* # bytes to allocate */
|
||||
{
|
||||
auto char probe; /* probes stack depth: */
|
||||
register char *depth = &probe;
|
||||
|
||||
#if STACK_DIRECTION == 0
|
||||
if (STACK_DIR == 0) /* unknown growth direction */
|
||||
find_stack_direction ();
|
||||
#endif
|
||||
|
||||
/* Reclaim garbage, defined as all alloca()ed storage that
|
||||
was allocated from deeper in the stack than currently. */
|
||||
|
||||
{
|
||||
register header *hp; /* traverses linked list */
|
||||
|
||||
for (hp = last_alloca_header; hp != NULL;)
|
||||
if ((STACK_DIR > 0 && hp->h.deep > depth)
|
||||
|| (STACK_DIR < 0 && hp->h.deep < depth))
|
||||
{
|
||||
register header *np = hp->h.next;
|
||||
|
||||
free ((pointer) hp); /* collect garbage */
|
||||
|
||||
hp = np; /* -> next header */
|
||||
}
|
||||
else
|
||||
break; /* rest are not deeper */
|
||||
|
||||
last_alloca_header = hp; /* -> last valid storage */
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return NULL; /* no allocation required */
|
||||
|
||||
/* Allocate combined header + user data storage. */
|
||||
|
||||
{
|
||||
register pointer new = xmalloc (sizeof (header) + size);
|
||||
/* address of header */
|
||||
|
||||
((header *)new)->h.next = last_alloca_header;
|
||||
((header *)new)->h.deep = depth;
|
||||
|
||||
last_alloca_header = (header *)new;
|
||||
|
||||
/* User storage begins just after header. */
|
||||
|
||||
return (pointer)((char *)new + sizeof(header));
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* no alloca */
|
35
lib/basename.c
Normal file
35
lib/basename.c
Normal file
@ -0,0 +1,35 @@
|
||||
/* basename.c -- return the last element in a path
|
||||
Copyright (C) 1990 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#if defined(USG) || defined(STDC_HEADERS)
|
||||
#include <string.h>
|
||||
#define rindex strrchr
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Return NAME with any leading path stripped off. */
|
||||
|
||||
char *
|
||||
basename (name)
|
||||
char *name;
|
||||
{
|
||||
char *base;
|
||||
|
||||
base = rindex (name, '/');
|
||||
return base ? base + 1 : name;
|
||||
}
|
105
lib/error.c
Normal file
105
lib/error.c
Normal file
@ -0,0 +1,105 @@
|
||||
/* error.c -- error handler for noninteractive utilities
|
||||
Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by David MacKenzie. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_VPRINTF
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#define VA_START(args, lastarg) va_start(args, lastarg)
|
||||
#else /* !__STDC__ */
|
||||
#include <varargs.h>
|
||||
#define VA_START(args, lastarg) va_start(args)
|
||||
#endif /* !__STDC__ */
|
||||
|
||||
#else /* !HAVE_VPRINTF */
|
||||
|
||||
#ifdef HAVE_DOPRNT
|
||||
#define va_alist args
|
||||
#define va_dcl int args;
|
||||
#else /* !HAVE_DOPRNT */
|
||||
#define va_alist a1, a2, a3, a4, a5, a6, a7, a8
|
||||
#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
|
||||
#endif /* !HAVE_DOPRNT */
|
||||
|
||||
#endif /* !HAVE_VPRINTF */
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#else /* !STDC_HEADERS */
|
||||
void exit ();
|
||||
#endif /* !STDC_HEADERS */
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
static char *
|
||||
private_strerror (errnum)
|
||||
int errnum;
|
||||
{
|
||||
extern char *sys_errlist[];
|
||||
extern int sys_nerr;
|
||||
|
||||
if (errnum > 0 && errnum <= sys_nerr)
|
||||
return sys_errlist[errnum];
|
||||
return "Unknown system error";
|
||||
}
|
||||
#define strerror private_strerror
|
||||
#endif /* !HAVE_STRERROR */
|
||||
|
||||
/* Print the program name and error message MESSAGE, which is a printf-style
|
||||
format string with optional args.
|
||||
If ERRNUM is nonzero, print its corresponding system error message.
|
||||
Exit with status STATUS if it is nonzero. */
|
||||
/* VARARGS */
|
||||
void
|
||||
#if defined (HAVE_VPRINTF) && __STDC__
|
||||
error (int status, int errnum, char *message, ...)
|
||||
#else /* !HAVE_VPRINTF or !__STDC__ */
|
||||
error (status, errnum, message, va_alist)
|
||||
int status;
|
||||
int errnum;
|
||||
char *message;
|
||||
va_dcl
|
||||
#endif /* !HAVE_VPRINTF or !__STDC__ */
|
||||
{
|
||||
extern char *program_name;
|
||||
#ifdef HAVE_VPRINTF
|
||||
va_list args;
|
||||
#endif /* HAVE_VPRINTF */
|
||||
|
||||
fprintf (stderr, "%s: ", program_name);
|
||||
#ifdef HAVE_VPRINTF
|
||||
VA_START (args, message);
|
||||
vfprintf (stderr, message, args);
|
||||
va_end (args);
|
||||
#else /* !HAVE_VPRINTF */
|
||||
#ifdef HAVE_DOPRNT
|
||||
_doprnt (message, &args, stderr);
|
||||
#else /* !HAVE_DOPRNT */
|
||||
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
#endif /* !HAVE_DOPRNT */
|
||||
#endif /* !HAVE_VPRINTF */
|
||||
if (errnum)
|
||||
fprintf (stderr, ": %s", strerror (errnum));
|
||||
putc ('\n', stderr);
|
||||
fflush (stderr);
|
||||
if (status)
|
||||
exit (status);
|
||||
}
|
965
lib/getdate.y
Normal file
965
lib/getdate.y
Normal file
@ -0,0 +1,965 @@
|
||||
%{
|
||||
/* $Revision: 2.1 $
|
||||
**
|
||||
** Originally written by Steven M. Bellovin <smb@research.att.com> while
|
||||
** at the University of North Carolina at Chapel Hill. Later tweaked by
|
||||
** a couple of people on Usenet. Completely overhauled by Rich $alz
|
||||
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
|
||||
** send any email to Rich.
|
||||
**
|
||||
** This grammar has eight shift/reduce conflicts.
|
||||
**
|
||||
** This code is in the public domain and has no copyright.
|
||||
*/
|
||||
/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
|
||||
/* SUPPRESS 288 on yyerrlab *//* Label unused */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else
|
||||
#ifdef sparc
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifdef _AIX /* for Bison */
|
||||
#pragma alloca
|
||||
#else
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* The code at the top of get_date which figures out the offset of the
|
||||
current time zone checks various CPP symbols to see if special
|
||||
tricks are need, but defaults to using the gettimeofday system call.
|
||||
Include <sys/time.h> if that will be used. */
|
||||
|
||||
#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if defined(vms)
|
||||
|
||||
#include <types.h>
|
||||
#include <time.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(USG) || !defined(HAVE_FTIME)
|
||||
/*
|
||||
** If you need to do a tzset() call to set the
|
||||
** timezone, and don't have ftime().
|
||||
*/
|
||||
struct timeb {
|
||||
time_t time; /* Seconds since the epoch */
|
||||
unsigned short millitm; /* Field not used */
|
||||
short timezone;
|
||||
short dstflag; /* Field not used */
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#endif /* defined(USG) && !defined(HAVE_FTIME) */
|
||||
|
||||
#if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#if defined(_AIX)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#endif /* defined(BSD4_2) */
|
||||
|
||||
#endif /* defined(vms) */
|
||||
|
||||
#if defined (STDC_HEADERS) || defined (USG)
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if sgi
|
||||
#undef timezone
|
||||
#endif
|
||||
|
||||
extern struct tm *localtime();
|
||||
|
||||
#define yyparse getdate_yyparse
|
||||
#define yylex getdate_yylex
|
||||
#define yyerror getdate_yyerror
|
||||
|
||||
#if !defined(lint) && !defined(SABER)
|
||||
static char RCS[] =
|
||||
"$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
|
||||
#endif /* !defined(lint) && !defined(SABER) */
|
||||
|
||||
|
||||
#define EPOCH 1970
|
||||
#define HOUR(x) ((time_t)(x) * 60)
|
||||
#define SECSPERDAY (24L * 60L * 60L)
|
||||
|
||||
|
||||
/*
|
||||
** An entry in the lexical lookup table.
|
||||
*/
|
||||
typedef struct _TABLE {
|
||||
char *name;
|
||||
int type;
|
||||
time_t value;
|
||||
} TABLE;
|
||||
|
||||
|
||||
/*
|
||||
** Daylight-savings mode: on, off, or not yet known.
|
||||
*/
|
||||
typedef enum _DSTMODE {
|
||||
DSTon, DSToff, DSTmaybe
|
||||
} DSTMODE;
|
||||
|
||||
/*
|
||||
** Meridian: am, pm, or 24-hour style.
|
||||
*/
|
||||
typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} MERIDIAN;
|
||||
|
||||
|
||||
/*
|
||||
** Global variables. We could get rid of most of these by using a good
|
||||
** union as the yacc stack. (This routine was originally written before
|
||||
** yacc had the %union construct.) Maybe someday; right now we only use
|
||||
** the %union very rarely.
|
||||
*/
|
||||
static char *yyInput;
|
||||
static DSTMODE yyDSTmode;
|
||||
static time_t yyDayOrdinal;
|
||||
static time_t yyDayNumber;
|
||||
static int yyHaveDate;
|
||||
static int yyHaveDay;
|
||||
static int yyHaveRel;
|
||||
static int yyHaveTime;
|
||||
static int yyHaveZone;
|
||||
static time_t yyTimezone;
|
||||
static time_t yyDay;
|
||||
static time_t yyHour;
|
||||
static time_t yyMinutes;
|
||||
static time_t yyMonth;
|
||||
static time_t yySeconds;
|
||||
static time_t yyYear;
|
||||
static MERIDIAN yyMeridian;
|
||||
static time_t yyRelMonth;
|
||||
static time_t yyRelSeconds;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
time_t Number;
|
||||
enum _MERIDIAN Meridian;
|
||||
}
|
||||
|
||||
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
|
||||
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
|
||||
|
||||
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
|
||||
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
|
||||
%type <Meridian> tMERIDIAN o_merid
|
||||
|
||||
%%
|
||||
|
||||
spec : /* NULL */
|
||||
| spec item
|
||||
;
|
||||
|
||||
item : time {
|
||||
yyHaveTime++;
|
||||
}
|
||||
| zone {
|
||||
yyHaveZone++;
|
||||
}
|
||||
| date {
|
||||
yyHaveDate++;
|
||||
}
|
||||
| day {
|
||||
yyHaveDay++;
|
||||
}
|
||||
| rel {
|
||||
yyHaveRel++;
|
||||
}
|
||||
| number
|
||||
;
|
||||
|
||||
time : tUNUMBER tMERIDIAN {
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $2;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $4;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yyMeridian = MER24;
|
||||
yyDSTmode = DSToff;
|
||||
yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = $6;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = MER24;
|
||||
yyDSTmode = DSToff;
|
||||
yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
|
||||
}
|
||||
;
|
||||
|
||||
zone : tZONE {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSToff;
|
||||
}
|
||||
| tDAYZONE {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSTon;
|
||||
}
|
||||
|
|
||||
tZONE tDST {
|
||||
yyTimezone = $1;
|
||||
yyDSTmode = DSTon;
|
||||
}
|
||||
;
|
||||
|
||||
day : tDAY {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
}
|
||||
| tDAY ',' {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
}
|
||||
| tUNUMBER tDAY {
|
||||
yyDayOrdinal = $1;
|
||||
yyDayNumber = $2;
|
||||
}
|
||||
;
|
||||
|
||||
date : tUNUMBER '/' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
}
|
||||
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
yyYear = $5;
|
||||
}
|
||||
| tUNUMBER tSNUMBER tSNUMBER {
|
||||
/* ISO 8601 format. yyyy-mm-dd. */
|
||||
yyYear = $1;
|
||||
yyMonth = -$2;
|
||||
yyDay = -$3;
|
||||
}
|
||||
| tMONTH tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
}
|
||||
| tMONTH tUNUMBER ',' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
yyYear = $4;
|
||||
}
|
||||
| tUNUMBER tMONTH {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
}
|
||||
| tUNUMBER tMONTH tUNUMBER {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
yyYear = $3;
|
||||
}
|
||||
;
|
||||
|
||||
rel : relunit tAGO {
|
||||
yyRelSeconds = -yyRelSeconds;
|
||||
yyRelMonth = -yyRelMonth;
|
||||
}
|
||||
| relunit
|
||||
;
|
||||
|
||||
relunit : tUNUMBER tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * $2 * 60L;
|
||||
}
|
||||
| tSNUMBER tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * $2 * 60L;
|
||||
}
|
||||
| tMINUTE_UNIT {
|
||||
yyRelSeconds += $1 * 60L;
|
||||
}
|
||||
| tSNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1;
|
||||
}
|
||||
| tUNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1;
|
||||
}
|
||||
| tSEC_UNIT {
|
||||
yyRelSeconds++;
|
||||
}
|
||||
| tSNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tUNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tMONTH_UNIT {
|
||||
yyRelMonth += $1;
|
||||
}
|
||||
;
|
||||
|
||||
number : tUNUMBER {
|
||||
if (yyHaveTime && yyHaveDate && !yyHaveRel)
|
||||
yyYear = $1;
|
||||
else {
|
||||
if($1>10000) {
|
||||
time_t date_part;
|
||||
|
||||
date_part= $1/10000;
|
||||
yyHaveDate++;
|
||||
yyDay= (date_part)%100;
|
||||
yyMonth= (date_part/100)%100;
|
||||
yyYear = date_part/10000;
|
||||
}
|
||||
yyHaveTime++;
|
||||
if ($1 < 100) {
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
}
|
||||
else {
|
||||
yyHour = $1 / 100;
|
||||
yyMinutes = $1 % 100;
|
||||
}
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
o_merid : /* NULL */ {
|
||||
$$ = MER24;
|
||||
}
|
||||
| tMERIDIAN {
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
/* Month and day table. */
|
||||
static TABLE MonthDayTable[] = {
|
||||
{ "january", tMONTH, 1 },
|
||||
{ "february", tMONTH, 2 },
|
||||
{ "march", tMONTH, 3 },
|
||||
{ "april", tMONTH, 4 },
|
||||
{ "may", tMONTH, 5 },
|
||||
{ "june", tMONTH, 6 },
|
||||
{ "july", tMONTH, 7 },
|
||||
{ "august", tMONTH, 8 },
|
||||
{ "september", tMONTH, 9 },
|
||||
{ "sept", tMONTH, 9 },
|
||||
{ "october", tMONTH, 10 },
|
||||
{ "november", tMONTH, 11 },
|
||||
{ "december", tMONTH, 12 },
|
||||
{ "sunday", tDAY, 0 },
|
||||
{ "monday", tDAY, 1 },
|
||||
{ "tuesday", tDAY, 2 },
|
||||
{ "tues", tDAY, 2 },
|
||||
{ "wednesday", tDAY, 3 },
|
||||
{ "wednes", tDAY, 3 },
|
||||
{ "thursday", tDAY, 4 },
|
||||
{ "thur", tDAY, 4 },
|
||||
{ "thurs", tDAY, 4 },
|
||||
{ "friday", tDAY, 5 },
|
||||
{ "saturday", tDAY, 6 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Time units table. */
|
||||
static TABLE UnitsTable[] = {
|
||||
{ "year", tMONTH_UNIT, 12 },
|
||||
{ "month", tMONTH_UNIT, 1 },
|
||||
{ "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
|
||||
{ "week", tMINUTE_UNIT, 7 * 24 * 60 },
|
||||
{ "day", tMINUTE_UNIT, 1 * 24 * 60 },
|
||||
{ "hour", tMINUTE_UNIT, 60 },
|
||||
{ "minute", tMINUTE_UNIT, 1 },
|
||||
{ "min", tMINUTE_UNIT, 1 },
|
||||
{ "second", tSEC_UNIT, 1 },
|
||||
{ "sec", tSEC_UNIT, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Assorted relative-time words. */
|
||||
static TABLE OtherTable[] = {
|
||||
{ "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
|
||||
{ "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
|
||||
{ "today", tMINUTE_UNIT, 0 },
|
||||
{ "now", tMINUTE_UNIT, 0 },
|
||||
{ "last", tUNUMBER, -1 },
|
||||
{ "this", tMINUTE_UNIT, 0 },
|
||||
{ "next", tUNUMBER, 2 },
|
||||
{ "first", tUNUMBER, 1 },
|
||||
/* { "second", tUNUMBER, 2 }, */
|
||||
{ "third", tUNUMBER, 3 },
|
||||
{ "fourth", tUNUMBER, 4 },
|
||||
{ "fifth", tUNUMBER, 5 },
|
||||
{ "sixth", tUNUMBER, 6 },
|
||||
{ "seventh", tUNUMBER, 7 },
|
||||
{ "eighth", tUNUMBER, 8 },
|
||||
{ "ninth", tUNUMBER, 9 },
|
||||
{ "tenth", tUNUMBER, 10 },
|
||||
{ "eleventh", tUNUMBER, 11 },
|
||||
{ "twelfth", tUNUMBER, 12 },
|
||||
{ "ago", tAGO, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* The timezone table. */
|
||||
/* Some of these are commented out because a time_t can't store a float. */
|
||||
static TABLE TimezoneTable[] = {
|
||||
{ "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
|
||||
{ "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
|
||||
{ "utc", tZONE, HOUR( 0) },
|
||||
{ "wet", tZONE, HOUR( 0) }, /* Western European */
|
||||
{ "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
|
||||
{ "wat", tZONE, HOUR( 1) }, /* West Africa */
|
||||
{ "at", tZONE, HOUR( 2) }, /* Azores */
|
||||
#if 0
|
||||
/* For completeness. BST is also British Summer, and GST is
|
||||
* also Guam Standard. */
|
||||
{ "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
|
||||
{ "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
|
||||
#endif
|
||||
#if 0
|
||||
{ "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
|
||||
{ "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
|
||||
{ "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
|
||||
#endif
|
||||
{ "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
|
||||
{ "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
|
||||
{ "est", tZONE, HOUR( 5) }, /* Eastern Standard */
|
||||
{ "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
|
||||
{ "cst", tZONE, HOUR( 6) }, /* Central Standard */
|
||||
{ "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
|
||||
{ "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
|
||||
{ "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
|
||||
{ "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
|
||||
{ "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
|
||||
{ "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
|
||||
{ "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
|
||||
{ "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
|
||||
{ "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
|
||||
{ "cat", tZONE, HOUR(10) }, /* Central Alaska */
|
||||
{ "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
|
||||
{ "nt", tZONE, HOUR(11) }, /* Nome */
|
||||
{ "idlw", tZONE, HOUR(12) }, /* International Date Line West */
|
||||
{ "cet", tZONE, -HOUR(1) }, /* Central European */
|
||||
{ "met", tZONE, -HOUR(1) }, /* Middle European */
|
||||
{ "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
|
||||
{ "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
|
||||
{ "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
|
||||
{ "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
|
||||
{ "fwt", tZONE, -HOUR(1) }, /* French Winter */
|
||||
{ "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
|
||||
{ "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
|
||||
{ "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
|
||||
#if 0
|
||||
{ "it", tZONE, -HOUR(3.5) },/* Iran */
|
||||
#endif
|
||||
{ "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
|
||||
{ "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
|
||||
#if 0
|
||||
{ "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
|
||||
#endif
|
||||
{ "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
|
||||
#if 0
|
||||
/* For completeness. NST is also Newfoundland Stanard, and SST is
|
||||
* also Swedish Summer. */
|
||||
{ "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
|
||||
{ "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
|
||||
#endif /* 0 */
|
||||
{ "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
|
||||
{ "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
|
||||
#if 0
|
||||
{ "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
|
||||
#endif
|
||||
{ "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
|
||||
{ "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
|
||||
#if 0
|
||||
{ "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
|
||||
{ "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
|
||||
#endif
|
||||
{ "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
|
||||
{ "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
|
||||
{ "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
|
||||
{ "nzt", tZONE, -HOUR(12) }, /* New Zealand */
|
||||
{ "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
|
||||
{ "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
|
||||
{ "idle", tZONE, -HOUR(12) }, /* International Date Line East */
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Military timezone table. */
|
||||
static TABLE MilitaryTable[] = {
|
||||
{ "a", tZONE, HOUR( 1) },
|
||||
{ "b", tZONE, HOUR( 2) },
|
||||
{ "c", tZONE, HOUR( 3) },
|
||||
{ "d", tZONE, HOUR( 4) },
|
||||
{ "e", tZONE, HOUR( 5) },
|
||||
{ "f", tZONE, HOUR( 6) },
|
||||
{ "g", tZONE, HOUR( 7) },
|
||||
{ "h", tZONE, HOUR( 8) },
|
||||
{ "i", tZONE, HOUR( 9) },
|
||||
{ "k", tZONE, HOUR( 10) },
|
||||
{ "l", tZONE, HOUR( 11) },
|
||||
{ "m", tZONE, HOUR( 12) },
|
||||
{ "n", tZONE, HOUR(- 1) },
|
||||
{ "o", tZONE, HOUR(- 2) },
|
||||
{ "p", tZONE, HOUR(- 3) },
|
||||
{ "q", tZONE, HOUR(- 4) },
|
||||
{ "r", tZONE, HOUR(- 5) },
|
||||
{ "s", tZONE, HOUR(- 6) },
|
||||
{ "t", tZONE, HOUR(- 7) },
|
||||
{ "u", tZONE, HOUR(- 8) },
|
||||
{ "v", tZONE, HOUR(- 9) },
|
||||
{ "w", tZONE, HOUR(-10) },
|
||||
{ "x", tZONE, HOUR(-11) },
|
||||
{ "y", tZONE, HOUR(-12) },
|
||||
{ "z", tZONE, HOUR( 0) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
yyerror(s)
|
||||
char *s;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
ToSeconds(Hours, Minutes, Seconds, Meridian)
|
||||
time_t Hours;
|
||||
time_t Minutes;
|
||||
time_t Seconds;
|
||||
MERIDIAN Meridian;
|
||||
{
|
||||
if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
|
||||
return -1;
|
||||
switch (Meridian) {
|
||||
case MER24:
|
||||
if (Hours < 0 || Hours > 23)
|
||||
return -1;
|
||||
return (Hours * 60L + Minutes) * 60L + Seconds;
|
||||
case MERam:
|
||||
if (Hours < 1 || Hours > 12)
|
||||
return -1;
|
||||
return (Hours * 60L + Minutes) * 60L + Seconds;
|
||||
case MERpm:
|
||||
if (Hours < 1 || Hours > 12)
|
||||
return -1;
|
||||
return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
|
||||
time_t Month;
|
||||
time_t Day;
|
||||
time_t Year;
|
||||
time_t Hours;
|
||||
time_t Minutes;
|
||||
time_t Seconds;
|
||||
MERIDIAN Meridian;
|
||||
DSTMODE DSTmode;
|
||||
{
|
||||
static int DaysInMonth[12] = {
|
||||
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||
};
|
||||
time_t tod;
|
||||
time_t Julian;
|
||||
int i;
|
||||
|
||||
if (Year < 0)
|
||||
Year = -Year;
|
||||
if (Year < 100)
|
||||
Year += 1900;
|
||||
DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
|
||||
? 29 : 28;
|
||||
if (Year < EPOCH || Year > 1999
|
||||
|| Month < 1 || Month > 12
|
||||
/* Lint fluff: "conversion from long may lose accuracy" */
|
||||
|| Day < 1 || Day > DaysInMonth[(int)--Month])
|
||||
return -1;
|
||||
|
||||
for (Julian = Day - 1, i = 0; i < Month; i++)
|
||||
Julian += DaysInMonth[i];
|
||||
for (i = EPOCH; i < Year; i++)
|
||||
Julian += 365 + (i % 4 == 0);
|
||||
Julian *= SECSPERDAY;
|
||||
Julian += yyTimezone * 60L;
|
||||
if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
|
||||
return -1;
|
||||
Julian += tod;
|
||||
if (DSTmode == DSTon
|
||||
|| (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
|
||||
Julian -= 60 * 60;
|
||||
return Julian;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
DSTcorrect(Start, Future)
|
||||
time_t Start;
|
||||
time_t Future;
|
||||
{
|
||||
time_t StartDay;
|
||||
time_t FutureDay;
|
||||
|
||||
StartDay = (localtime(&Start)->tm_hour + 1) % 24;
|
||||
FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
|
||||
return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
RelativeDate(Start, DayOrdinal, DayNumber)
|
||||
time_t Start;
|
||||
time_t DayOrdinal;
|
||||
time_t DayNumber;
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
|
||||
now = Start;
|
||||
tm = localtime(&now);
|
||||
now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
|
||||
now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
|
||||
return DSTcorrect(Start, now);
|
||||
}
|
||||
|
||||
|
||||
static time_t
|
||||
RelativeMonth(Start, RelMonth)
|
||||
time_t Start;
|
||||
time_t RelMonth;
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t Month;
|
||||
time_t Year;
|
||||
|
||||
if (RelMonth == 0)
|
||||
return 0;
|
||||
tm = localtime(&Start);
|
||||
Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
|
||||
Year = Month / 12;
|
||||
Month = Month % 12 + 1;
|
||||
return DSTcorrect(Start,
|
||||
Convert(Month, (time_t)tm->tm_mday, Year,
|
||||
(time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
|
||||
MER24, DSTmaybe));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
LookupWord(buff)
|
||||
char *buff;
|
||||
{
|
||||
register char *p;
|
||||
register char *q;
|
||||
register TABLE *tp;
|
||||
int i;
|
||||
int abbrev;
|
||||
|
||||
/* Make it lowercase. */
|
||||
for (p = buff; *p; p++)
|
||||
if (isupper(*p))
|
||||
*p = tolower(*p);
|
||||
|
||||
if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
|
||||
yylval.Meridian = MERam;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
|
||||
yylval.Meridian = MERpm;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
|
||||
/* See if we have an abbreviation for a month. */
|
||||
if (strlen(buff) == 3)
|
||||
abbrev = 1;
|
||||
else if (strlen(buff) == 4 && buff[3] == '.') {
|
||||
abbrev = 1;
|
||||
buff[3] = '\0';
|
||||
}
|
||||
else
|
||||
abbrev = 0;
|
||||
|
||||
for (tp = MonthDayTable; tp->name; tp++) {
|
||||
if (abbrev) {
|
||||
if (strncmp(buff, tp->name, 3) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
else if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
if (strcmp(buff, "dst") == 0)
|
||||
return tDST;
|
||||
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
/* Strip off any plural and try the units table again. */
|
||||
i = strlen(buff) - 1;
|
||||
if (buff[i] == 's') {
|
||||
buff[i] = '\0';
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
buff[i] = 's'; /* Put back for "this" in OtherTable. */
|
||||
}
|
||||
|
||||
for (tp = OtherTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
/* Military timezones. */
|
||||
if (buff[1] == '\0' && isalpha(*buff)) {
|
||||
for (tp = MilitaryTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop out any periods and try the timezone table again. */
|
||||
for (i = 0, p = q = buff; *q; q++)
|
||||
if (*q != '.')
|
||||
*p++ = *q;
|
||||
else
|
||||
i++;
|
||||
*p = '\0';
|
||||
if (i)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp(buff, tp->name) == 0) {
|
||||
yylval.Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
return tID;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
yylex()
|
||||
{
|
||||
register char c;
|
||||
register char *p;
|
||||
char buff[20];
|
||||
int Count;
|
||||
int sign;
|
||||
|
||||
for ( ; ; ) {
|
||||
while (isspace(*yyInput))
|
||||
yyInput++;
|
||||
|
||||
if (isdigit(c = *yyInput) || c == '-' || c == '+') {
|
||||
if (c == '-' || c == '+') {
|
||||
sign = c == '-' ? -1 : 1;
|
||||
if (!isdigit(*++yyInput))
|
||||
/* skip the '-' sign */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
for (yylval.Number = 0; isdigit(c = *yyInput++); )
|
||||
yylval.Number = 10 * yylval.Number + c - '0';
|
||||
yyInput--;
|
||||
if (sign < 0)
|
||||
yylval.Number = -yylval.Number;
|
||||
return sign ? tSNUMBER : tUNUMBER;
|
||||
}
|
||||
if (isalpha(c)) {
|
||||
for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
|
||||
if (p < &buff[sizeof buff - 1])
|
||||
*p++ = c;
|
||||
*p = '\0';
|
||||
yyInput--;
|
||||
return LookupWord(buff);
|
||||
}
|
||||
if (c != '(')
|
||||
return *yyInput++;
|
||||
Count = 0;
|
||||
do {
|
||||
c = *yyInput++;
|
||||
if (c == '\0')
|
||||
return c;
|
||||
if (c == '(')
|
||||
Count++;
|
||||
else if (c == ')')
|
||||
Count--;
|
||||
} while (Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
time_t
|
||||
get_date(p, now)
|
||||
char *p;
|
||||
struct timeb *now;
|
||||
{
|
||||
struct tm *tm;
|
||||
struct timeb ftz;
|
||||
time_t Start;
|
||||
time_t tod;
|
||||
|
||||
yyInput = p;
|
||||
if (now == NULL) {
|
||||
now = &ftz;
|
||||
#if !defined(HAVE_FTIME)
|
||||
(void)time(&ftz.time);
|
||||
/* Set the timezone global. */
|
||||
tzset();
|
||||
{
|
||||
#if sgi
|
||||
ftz.timezone = (int) _timezone / 60;
|
||||
#else /* not sgi */
|
||||
#ifdef __386BSD__
|
||||
ftz.timezone = 0;
|
||||
#else /* neither sgi nor 386BSD */
|
||||
#if defined (USG)
|
||||
extern time_t timezone;
|
||||
|
||||
ftz.timezone = (int) timezone / 60;
|
||||
#else /* neither sgi nor 386BSD nor USG */
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
gettimeofday (&tv, &tz);
|
||||
ftz.timezone = (int) tz.tz_minuteswest;
|
||||
#endif /* neither sgi nor 386BSD nor USG */
|
||||
#endif /* neither sgi nor 386BSD */
|
||||
#endif /* not sgi */
|
||||
}
|
||||
#else /* HAVE_FTIME */
|
||||
(void)ftime(&ftz);
|
||||
#endif /* HAVE_FTIME */
|
||||
}
|
||||
|
||||
tm = localtime(&now->time);
|
||||
yyYear = tm->tm_year;
|
||||
yyMonth = tm->tm_mon + 1;
|
||||
yyDay = tm->tm_mday;
|
||||
yyTimezone = now->timezone;
|
||||
yyDSTmode = DSTmaybe;
|
||||
yyHour = 0;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
yyRelMonth = 0;
|
||||
yyHaveDate = 0;
|
||||
yyHaveDay = 0;
|
||||
yyHaveRel = 0;
|
||||
yyHaveTime = 0;
|
||||
yyHaveZone = 0;
|
||||
|
||||
if (yyparse()
|
||||
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
|
||||
return -1;
|
||||
|
||||
if (yyHaveDate || yyHaveTime || yyHaveDay) {
|
||||
Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
|
||||
yyMeridian, yyDSTmode);
|
||||
if (Start < 0)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
Start = now->time;
|
||||
if (!yyHaveRel)
|
||||
Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
|
||||
}
|
||||
|
||||
Start += yyRelSeconds;
|
||||
Start += RelativeMonth(Start, yyRelMonth);
|
||||
|
||||
if (yyHaveDay && !yyHaveDate) {
|
||||
tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
|
||||
Start += tod;
|
||||
}
|
||||
|
||||
/* Have to do *something* with a legitimate -1 so it's distinguishable
|
||||
* from the error return value. (Alternately could set errno on error.) */
|
||||
return Start == -1 ? 0 : Start;
|
||||
}
|
||||
|
||||
|
||||
#if defined(TEST)
|
||||
|
||||
/* ARGSUSED */
|
||||
main(ac, av)
|
||||
int ac;
|
||||
char *av[];
|
||||
{
|
||||
char buff[128];
|
||||
time_t d;
|
||||
|
||||
(void)printf("Enter date, or blank line to exit.\n\t> ");
|
||||
(void)fflush(stdout);
|
||||
while (gets(buff) && buff[0]) {
|
||||
d = get_date(buff, (struct timeb *)NULL);
|
||||
if (d == -1)
|
||||
(void)printf("Bad format - couldn't convert.\n");
|
||||
else
|
||||
(void)printf("%s", ctime(&d));
|
||||
(void)printf("\t> ");
|
||||
(void)fflush(stdout);
|
||||
}
|
||||
exit(0);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif /* defined(TEST) */
|
49
lib/gethostname.c
Normal file
49
lib/gethostname.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* gethostname emulation for SysV and POSIX.1.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#ifdef HAVE_UNAME
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/* Put up to LEN chars of the host name into NAME.
|
||||
Null terminate it if the name is shorter than LEN.
|
||||
Return 0 if ok, -1 if error. */
|
||||
|
||||
int
|
||||
gethostname (name, len)
|
||||
char *name;
|
||||
int len;
|
||||
{
|
||||
#ifdef HAVE_UNAME
|
||||
struct utsname uts;
|
||||
|
||||
if (uname (&uts) == -1)
|
||||
return -1;
|
||||
if (len > sizeof (uts.nodename))
|
||||
{
|
||||
/* More space than we need is available. */
|
||||
name[sizeof (uts.nodename)] = '\0';
|
||||
len = sizeof (uts.nodename);
|
||||
}
|
||||
strncpy (name, uts.nodename, len);
|
||||
#else
|
||||
strcpy (name, ""); /* Hardcode your system name if you want. */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
679
lib/getopt.c
Normal file
679
lib/getopt.c
Normal file
@ -0,0 +1,679 @@
|
||||
/* Getopt for GNU.
|
||||
NOTE: getopt is now part of the C library, so if you don't know what
|
||||
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
|
||||
before changing it!
|
||||
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* AIX requires this to be the first thing in the file. */
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else /* not __GNUC__ */
|
||||
#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifdef _AIX
|
||||
#pragma alloca
|
||||
#else
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif /* alloca.h */
|
||||
#endif /* not __GNUC__ */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#undef alloca
|
||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
|
||||
contain conflicting prototypes for getopt. */
|
||||
#include <stdlib.h>
|
||||
#else /* Not GNU C library. */
|
||||
#define __alloca alloca
|
||||
#endif /* GNU C library. */
|
||||
|
||||
#if !__STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
|
||||
long-named option. Because this is not POSIX.2 compliant, it is
|
||||
being phased out. */
|
||||
#define GETOPT_COMPAT
|
||||
|
||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
|
||||
but it behaves differently for the user, since it allows the user
|
||||
to intersperse the options with the other arguments.
|
||||
|
||||
As `getopt' works, it permutes the elements of ARGV so that,
|
||||
when it is done, all the options precede everything else. Thus
|
||||
all application programs are extended to handle flexible argument order.
|
||||
|
||||
Setting the environment variable POSIXLY_CORRECT disables permutation.
|
||||
Then the behavior is completely standard.
|
||||
|
||||
GNU application programs can use a third alternative mode in which
|
||||
they can distinguish the relative order of options and other arguments. */
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
char *optarg = 0;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
int optind = 0;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
This allows us to pick up the scan where we left off.
|
||||
|
||||
If this is zero, or a null string, it means resume the scan
|
||||
by advancing to the next ARGV-element. */
|
||||
|
||||
static char *nextchar;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
int opterr = 1;
|
||||
|
||||
/* Describe how to deal with options that follow non-option ARGV-elements.
|
||||
|
||||
If the caller did not specify anything,
|
||||
the default is REQUIRE_ORDER if the environment variable
|
||||
POSIXLY_CORRECT is defined, PERMUTE otherwise.
|
||||
|
||||
REQUIRE_ORDER means don't recognize them as options;
|
||||
stop option processing when the first non-option is seen.
|
||||
This is what Unix does.
|
||||
This mode of operation is selected by either setting the environment
|
||||
variable POSIXLY_CORRECT, or using `+' as the first character
|
||||
of the list of option characters.
|
||||
|
||||
PERMUTE is the default. We permute the contents of ARGV as we scan,
|
||||
so that eventually all the non-options are at the end. This allows options
|
||||
to be given in any order, even with programs that were not written to
|
||||
expect this.
|
||||
|
||||
RETURN_IN_ORDER is an option available to programs that were written
|
||||
to expect options and other ARGV-elements in any order and that care about
|
||||
the ordering of the two. We describe each non-option ARGV-element
|
||||
as if it were the argument of an option with character code 1.
|
||||
Using `-' as the first character of the list of option characters
|
||||
selects this mode of operation.
|
||||
|
||||
The special argument `--' forces an end of option-scanning regardless
|
||||
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
|
||||
`--' can cause `getopt' to return EOF with `optind' != ARGC. */
|
||||
|
||||
static enum
|
||||
{
|
||||
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
|
||||
} ordering;
|
||||
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* We want to avoid inclusion of string.h with non-GNU libraries
|
||||
because there are many ways it can cause trouble.
|
||||
On some systems, it contains special magic macros that don't work
|
||||
in GCC. */
|
||||
#include <string.h>
|
||||
#define my_index strchr
|
||||
#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n))
|
||||
#else
|
||||
|
||||
/* Avoid depending on library functions or files
|
||||
whose names are inconsistent. */
|
||||
|
||||
char *getenv ();
|
||||
|
||||
static char *
|
||||
my_index (string, chr)
|
||||
char *string;
|
||||
int chr;
|
||||
{
|
||||
while (*string)
|
||||
{
|
||||
if (*string == chr)
|
||||
return string;
|
||||
string++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
my_bcopy (from, to, size)
|
||||
char *from, *to;
|
||||
int size;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
to[i] = from[i];
|
||||
}
|
||||
#endif /* GNU C library. */
|
||||
|
||||
/* Handle permutation of arguments. */
|
||||
|
||||
/* Describe the part of ARGV that contains non-options that have
|
||||
been skipped. `first_nonopt' is the index in ARGV of the first of them;
|
||||
`last_nonopt' is the index after the last of them. */
|
||||
|
||||
static int first_nonopt;
|
||||
static int last_nonopt;
|
||||
|
||||
/* Exchange two adjacent subsequences of ARGV.
|
||||
One subsequence is elements [first_nonopt,last_nonopt)
|
||||
which contains all the non-options that have been skipped so far.
|
||||
The other is elements [last_nonopt,optind), which contains all
|
||||
the options processed since those non-options were skipped.
|
||||
|
||||
`first_nonopt' and `last_nonopt' are relocated so that they describe
|
||||
the new indices of the non-options in ARGV after they are moved. */
|
||||
|
||||
static void
|
||||
exchange (argv)
|
||||
char **argv;
|
||||
{
|
||||
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
|
||||
char **temp = (char **) __alloca (nonopts_size);
|
||||
|
||||
/* Interchange the two blocks of data in ARGV. */
|
||||
|
||||
my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
|
||||
my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
|
||||
(optind - last_nonopt) * sizeof (char *));
|
||||
my_bcopy ((char *) temp,
|
||||
(char *) &argv[first_nonopt + optind - last_nonopt],
|
||||
nonopts_size);
|
||||
|
||||
/* Update records for the slots the non-options now occupy. */
|
||||
|
||||
first_nonopt += (optind - last_nonopt);
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `getopt'
|
||||
is called repeatedly, it returns successively each of the option characters
|
||||
from each of the option elements.
|
||||
|
||||
If `getopt' finds another option character, it returns that character,
|
||||
updating `optind' and `nextchar' so that the next call to `getopt' can
|
||||
resume the scan with the following option character or ARGV-element.
|
||||
|
||||
If there are no more option characters, `getopt' returns `EOF'.
|
||||
Then `optind' is the index in ARGV of the first ARGV-element
|
||||
that is not an option. (The ARGV-elements have been permuted
|
||||
so that those that are not options now come last.)
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen that is not listed in OPTSTRING,
|
||||
return '?' after printing an error message. If you set `opterr' to
|
||||
zero, the error message is suppressed but we still return '?'.
|
||||
|
||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
||||
so the following text in the same ARGV-element, or the text of the following
|
||||
ARGV-element, is returned in `optarg'. Two colons mean an option that
|
||||
wants an optional arg; if there is text in the current ARGV-element,
|
||||
it is returned in `optarg', otherwise `optarg' is set to zero.
|
||||
|
||||
If OPTSTRING starts with `-' or `+', it requests different methods of
|
||||
handling the non-option ARGV-elements.
|
||||
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
|
||||
|
||||
Long-named options begin with `--' instead of `-'.
|
||||
Their names may be abbreviated as long as the abbreviation is unique
|
||||
or is an exact match for some defined option. If they have an
|
||||
argument, it follows the option name in the same ARGV-element, separated
|
||||
from the option name by a `=', or else the in next ARGV-element.
|
||||
When `getopt' finds a long-named option, it returns 0 if that option's
|
||||
`flag' field is nonzero, the value of the option's `val' field
|
||||
if the `flag' field is zero.
|
||||
|
||||
The elements of ARGV aren't really const, because we permute them.
|
||||
But we pretend they're const in the prototype to be compatible
|
||||
with other systems.
|
||||
|
||||
LONGOPTS is a vector of `struct option' terminated by an
|
||||
element containing a name which is zero.
|
||||
|
||||
LONGIND returns the index in LONGOPT of the long-named option found.
|
||||
It is only valid when a long-named option has been found by the most
|
||||
recent call.
|
||||
|
||||
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
|
||||
long-named options. */
|
||||
|
||||
int
|
||||
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
const struct option *longopts;
|
||||
int *longind;
|
||||
int long_only;
|
||||
{
|
||||
int option_index;
|
||||
|
||||
optarg = 0;
|
||||
|
||||
/* Initialize the internal data when the first call is made.
|
||||
Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||
is the program name); the sequence of previously skipped
|
||||
non-option ARGV-elements is empty. */
|
||||
|
||||
if (optind == 0)
|
||||
{
|
||||
first_nonopt = last_nonopt = optind = 1;
|
||||
|
||||
nextchar = NULL;
|
||||
|
||||
/* Determine how to handle the ordering of options and nonoptions. */
|
||||
|
||||
if (optstring[0] == '-')
|
||||
{
|
||||
ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == '+')
|
||||
{
|
||||
ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (getenv ("POSIXLY_CORRECT") != NULL)
|
||||
ordering = REQUIRE_ORDER;
|
||||
else
|
||||
ordering = PERMUTE;
|
||||
}
|
||||
|
||||
if (nextchar == NULL || *nextchar == '\0')
|
||||
{
|
||||
if (ordering == PERMUTE)
|
||||
{
|
||||
/* If we have just processed some options following some non-options,
|
||||
exchange them so that the options come first. */
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (last_nonopt != optind)
|
||||
first_nonopt = optind;
|
||||
|
||||
/* Now skip any additional non-options
|
||||
and extend the range of non-options previously skipped. */
|
||||
|
||||
while (optind < argc
|
||||
&& (argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
optind++;
|
||||
last_nonopt = optind;
|
||||
}
|
||||
|
||||
/* Special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option,
|
||||
then exchange with previous non-options as if it were an option,
|
||||
then skip everything else like a non-option. */
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "--"))
|
||||
{
|
||||
optind++;
|
||||
|
||||
if (first_nonopt != last_nonopt && last_nonopt != optind)
|
||||
exchange ((char **) argv);
|
||||
else if (first_nonopt == last_nonopt)
|
||||
first_nonopt = optind;
|
||||
last_nonopt = argc;
|
||||
|
||||
optind = argc;
|
||||
}
|
||||
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
/* Set the next-arg-index to point at the non-options
|
||||
that we previously skipped, so the caller will digest them. */
|
||||
if (first_nonopt != last_nonopt)
|
||||
optind = first_nonopt;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option and did not permute it,
|
||||
either stop the scan or describe it to the caller and pass it by. */
|
||||
|
||||
if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#ifdef GETOPT_COMPAT
|
||||
&& (longopts == NULL
|
||||
|| argv[optind][0] != '+' || argv[optind][1] == '\0')
|
||||
#endif /* GETOPT_COMPAT */
|
||||
)
|
||||
{
|
||||
if (ordering == REQUIRE_ORDER)
|
||||
return EOF;
|
||||
optarg = argv[optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Start decoding its characters. */
|
||||
|
||||
nextchar = (argv[optind] + 1
|
||||
+ (longopts != NULL && argv[optind][1] == '-'));
|
||||
}
|
||||
|
||||
if (longopts != NULL
|
||||
&& ((argv[optind][0] == '-'
|
||||
&& (argv[optind][1] == '-' || long_only))
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
))
|
||||
{
|
||||
const struct option *p;
|
||||
char *s = nextchar;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
const struct option *pfound = NULL;
|
||||
int indfound;
|
||||
|
||||
while (*s && *s != '=')
|
||||
s++;
|
||||
|
||||
/* Test all options for either exact match or abbreviated matches. */
|
||||
for (p = longopts, option_index = 0; p->name;
|
||||
p++, option_index++)
|
||||
if (!strncmp (p->name, nextchar, s - nextchar))
|
||||
{
|
||||
if (s - nextchar == strlen (p->name))
|
||||
{
|
||||
/* Exact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
/* First nonexact match found. */
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else
|
||||
/* Second nonexact match found. */
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' is ambiguous\n",
|
||||
argv[0], argv[optind]);
|
||||
nextchar += strlen (nextchar);
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
optind++;
|
||||
if (*s)
|
||||
{
|
||||
/* Don't test has_arg with >, because some C compilers don't
|
||||
allow it to be used on enums. */
|
||||
if (pfound->has_arg)
|
||||
optarg = s + 1;
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind - 1][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr,
|
||||
"%s: option `--%s' doesn't allow an argument\n",
|
||||
argv[0], pfound->name);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr,
|
||||
"%s: option `%c%s' doesn't allow an argument\n",
|
||||
argv[0], argv[optind - 1][0], pfound->name);
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (optind < argc)
|
||||
optarg = argv[optind++];
|
||||
else
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `%s' requires an argument\n",
|
||||
argv[0], argv[optind - 1]);
|
||||
nextchar += strlen (nextchar);
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
nextchar += strlen (nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
/* Can't find it as a long option. If this is not getopt_long_only,
|
||||
or the option starts with '--' or is not a valid short
|
||||
option, then it's an error.
|
||||
Otherwise interpret it as a short option. */
|
||||
if (!long_only || argv[optind][1] == '-'
|
||||
#ifdef GETOPT_COMPAT
|
||||
|| argv[optind][0] == '+'
|
||||
#endif /* GETOPT_COMPAT */
|
||||
|| my_index (optstring, *nextchar) == NULL)
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (argv[optind][1] == '-')
|
||||
/* --option */
|
||||
fprintf (stderr, "%s: unrecognized option `--%s'\n",
|
||||
argv[0], nextchar);
|
||||
else
|
||||
/* +option or -option */
|
||||
fprintf (stderr, "%s: unrecognized option `%c%s'\n",
|
||||
argv[0], argv[optind][0], nextchar);
|
||||
}
|
||||
nextchar = (char *) "";
|
||||
optind++;
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
/* Look at and handle the next option-character. */
|
||||
|
||||
{
|
||||
char c = *nextchar++;
|
||||
char *temp = my_index (optstring, c);
|
||||
|
||||
/* Increment `optind' when we start to process its last character. */
|
||||
if (*nextchar == '\0')
|
||||
++optind;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (opterr)
|
||||
{
|
||||
if (c < 040 || c >= 0177)
|
||||
fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
|
||||
argv[0], c);
|
||||
else
|
||||
fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (temp[2] == ':')
|
||||
{
|
||||
/* This is an option that accepts an argument optionally. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
optarg = 0;
|
||||
nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
if (*nextchar != '\0')
|
||||
{
|
||||
optarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
optind++;
|
||||
}
|
||||
else if (optind == argc)
|
||||
{
|
||||
if (opterr)
|
||||
fprintf (stderr, "%s: option `-%c' requires an argument\n",
|
||||
argv[0], c);
|
||||
c = '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `optind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
optarg = argv[optind++];
|
||||
nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getopt (argc, argv, optstring)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
{
|
||||
return _getopt_internal (argc, argv, optstring,
|
||||
(const struct option *) 0,
|
||||
(int *) 0,
|
||||
0);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/* Compile with -DTEST to make an executable for use in testing
|
||||
the above definition of `getopt'. */
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
|
||||
c = getopt (argc, argv, "abc:d:0123456789");
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
125
lib/getopt.h
Normal file
125
lib/getopt.h
Normal file
@ -0,0 +1,125 @@
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
#if __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#if __STDC__
|
||||
#if defined(__GNU_LIBRARY__)
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
#endif /* not __GNU_LIBRARY__ */
|
||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
#endif /* not __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H */
|
153
lib/getopt1.c
Normal file
153
lib/getopt1.c
Normal file
@ -0,0 +1,153 @@
|
||||
/* Getopt for GNU.
|
||||
Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#ifndef __STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC)
|
||||
#include <stdlib.h>
|
||||
#else /* STDC_HEADERS or __GNU_LIBRARY__ */
|
||||
char *getenv ();
|
||||
#endif /* STDC_HEADERS or __GNU_LIBRARY__ */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only (argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
printf ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_optind != 0 && digit_optind != this_option_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_optind = this_option_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf ("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (optind < argc)
|
||||
printf ("%s ", argv[optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
86
lib/getugroups.c
Normal file
86
lib/getugroups.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* getugroups.c -- return a list of the groups a user is in
|
||||
Copyright (C) 1990, 1991 Free Software Foundation.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by David MacKenzie. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <grp.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Even though SunOS 4, Ultrix 4, and 386BSD are mostly POSIX.1 compliant,
|
||||
their getgroups system call (except in the `System V' environment, which
|
||||
is troublesome in other ways) fills in an array of int, not gid_t
|
||||
(which is `short' on those systems). We do the same, for consistency.
|
||||
Kludge, kludge. */
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#if !defined(sun) && !defined(ultrix) && !defined(__386BSD__)
|
||||
#define GETGROUPS_T gid_t
|
||||
#else /* sun or ultrix or 386BSD */
|
||||
#define GETGROUPS_T int
|
||||
#endif /* sun or ultrix or 386BSD */
|
||||
#else /* not _POSIX_VERSION */
|
||||
#define GETGROUPS_T int
|
||||
#endif /* not _POSIX_VERSION */
|
||||
|
||||
/* setgrent, getgrent, and endgrent are not specified by POSIX.1,
|
||||
so header files might not declare them.
|
||||
If you don't have them at all, we can't implement this function.
|
||||
You lose! */
|
||||
struct group *getgrent ();
|
||||
|
||||
#if defined(USG) || defined(STDC_HEADERS)
|
||||
#include <string.h>
|
||||
#else
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Like `getgroups', but for user USERNAME instead of for
|
||||
the current process. */
|
||||
|
||||
int
|
||||
getugroups (maxcount, grouplist, username)
|
||||
int maxcount;
|
||||
GETGROUPS_T *grouplist;
|
||||
char *username;
|
||||
{
|
||||
struct group *grp;
|
||||
register char **cp;
|
||||
register int count = 0;
|
||||
|
||||
setgrent ();
|
||||
while ((grp = getgrent ()) != 0)
|
||||
for (cp = grp->gr_mem; *cp; ++cp)
|
||||
if (!strcmp (username, *cp))
|
||||
{
|
||||
if (maxcount != 0)
|
||||
{
|
||||
if (count >= maxcount)
|
||||
{
|
||||
endgrent ();
|
||||
return count;
|
||||
}
|
||||
grouplist[count] = grp->gr_gid;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
endgrent ();
|
||||
return count;
|
||||
}
|
196
lib/getusershell.c
Normal file
196
lib/getusershell.c
Normal file
@ -0,0 +1,196 @@
|
||||
/* getusershell.c -- Return names of valid user shells.
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#ifndef SHELLS_FILE
|
||||
/* File containing a list of nonrestricted shells, one per line. */
|
||||
#define SHELLS_FILE "/etc/shells"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
#endif
|
||||
|
||||
static int readname ();
|
||||
|
||||
/* List of shells to use if the shells file is missing. */
|
||||
static char *default_shells[] =
|
||||
{
|
||||
"/bin/sh", "/bin/csh", "/usr/bin/sh", "/usr/bin/csh", NULL
|
||||
};
|
||||
|
||||
/* Index of the next shell in `default_shells' to return.
|
||||
0 means we are not using `default_shells'. */
|
||||
static int default_index = 0;
|
||||
|
||||
/* Input stream from the shells file. */
|
||||
static FILE *shellstream = NULL;
|
||||
|
||||
/* Line of input from the shells file. */
|
||||
static char *line = NULL;
|
||||
|
||||
/* Number of bytes allocated for `line'. */
|
||||
static int line_size = 0;
|
||||
|
||||
/* Return an entry from the shells file, ignoring comment lines.
|
||||
Return NULL if there are no more entries. */
|
||||
|
||||
char *
|
||||
getusershell ()
|
||||
{
|
||||
if (default_index > 0)
|
||||
{
|
||||
if (default_shells[default_index])
|
||||
/* Not at the end of the list yet. */
|
||||
return default_shells[default_index++];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (shellstream == NULL)
|
||||
{
|
||||
shellstream = fopen (SHELLS_FILE, "r");
|
||||
if (shellstream == NULL)
|
||||
{
|
||||
/* No shells file. Use the default list. */
|
||||
default_index = 1;
|
||||
return default_shells[0];
|
||||
}
|
||||
}
|
||||
|
||||
while (readname (&line, &line_size, shellstream))
|
||||
{
|
||||
if (*line != '#')
|
||||
return line;
|
||||
}
|
||||
return NULL; /* End of file. */
|
||||
}
|
||||
|
||||
/* Rewind the shells file. */
|
||||
|
||||
void
|
||||
setusershell ()
|
||||
{
|
||||
default_index = 0;
|
||||
if (shellstream == NULL)
|
||||
shellstream = fopen (SHELLS_FILE, "r");
|
||||
else
|
||||
fseek (shellstream, 0L, 0);
|
||||
}
|
||||
|
||||
/* Close the shells file. */
|
||||
|
||||
void
|
||||
endusershell ()
|
||||
{
|
||||
if (shellstream)
|
||||
{
|
||||
fclose (shellstream);
|
||||
shellstream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
static char *
|
||||
xmalloc (n)
|
||||
unsigned n;
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
{
|
||||
fprintf (stderr, "virtual memory exhausted\n");
|
||||
exit (1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Reallocate space P to size N, with error checking. */
|
||||
|
||||
static char *
|
||||
xrealloc (p, n)
|
||||
char *p;
|
||||
unsigned n;
|
||||
{
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
{
|
||||
fprintf (stderr, "virtual memory exhausted\n");
|
||||
exit (1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Read a line from STREAM, removing any newline at the end.
|
||||
Place the result in *NAME, which is malloc'd
|
||||
and/or realloc'd as necessary and can start out NULL,
|
||||
and whose size is passed and returned in *SIZE.
|
||||
|
||||
Return the number of characters placed in *NAME
|
||||
if some nonempty sequence was found, otherwise 0. */
|
||||
|
||||
static int
|
||||
readname (name, size, stream)
|
||||
char **name;
|
||||
int *size;
|
||||
FILE *stream;
|
||||
{
|
||||
int c;
|
||||
int name_index = 0;
|
||||
|
||||
if (*name == NULL)
|
||||
{
|
||||
*size = 10;
|
||||
*name = (char *) xmalloc (*size);
|
||||
}
|
||||
|
||||
/* Skip blank space. */
|
||||
while ((c = getc (stream)) != EOF && isspace (c))
|
||||
/* Do nothing. */ ;
|
||||
|
||||
while (c != EOF && !isspace (c))
|
||||
{
|
||||
(*name)[name_index++] = c;
|
||||
while (name_index >= *size)
|
||||
{
|
||||
*size *= 2;
|
||||
*name = (char *) xrealloc (*name, *size);
|
||||
}
|
||||
c = getc (stream);
|
||||
}
|
||||
(*name)[name_index] = '\0';
|
||||
return name_index;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
main ()
|
||||
{
|
||||
char *s;
|
||||
|
||||
while (s = getusershell ())
|
||||
puts (s);
|
||||
exit (0);
|
||||
}
|
||||
#endif
|
224
lib/mktime.c
Normal file
224
lib/mktime.c
Normal file
@ -0,0 +1,224 @@
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#ifndef STDC_HEADERS
|
||||
extern int errno;
|
||||
#endif
|
||||
#ifdef TM_IN_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#else
|
||||
#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
|
||||
#define LONG_MIN (-LONG_MAX - 1)
|
||||
#define INT_MAX (~(1 << (sizeof (int) * 8 - 1)))
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef __isleap
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 1000th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 1000 == 0))
|
||||
#endif
|
||||
|
||||
/* How many days are in each month. */
|
||||
static unsigned short int __mon_lengths[2][12] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
/* Leap years. */
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
#define invalid() return (time_t) -1
|
||||
|
||||
/* Return the `time_t' representation of TP and normalizes TP.
|
||||
Return (time_t) -1 if TP is not representable as a `time_t'.
|
||||
Note that 31 Dec 1969 23:59:59 is not representable
|
||||
because it is represented as (time_t) -1. */
|
||||
time_t
|
||||
mktime(tp)
|
||||
register struct tm *tp;
|
||||
{
|
||||
static struct tm min, max;
|
||||
static char init = 0;
|
||||
|
||||
register time_t result;
|
||||
register time_t t;
|
||||
register int i;
|
||||
register unsigned short *l;
|
||||
register struct tm *new;
|
||||
time_t end;
|
||||
|
||||
if (tp == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
invalid();
|
||||
}
|
||||
|
||||
if (!init)
|
||||
{
|
||||
init = 1;
|
||||
end = (time_t) LONG_MIN;
|
||||
new = gmtime(&end);
|
||||
if (new != NULL)
|
||||
min = *new;
|
||||
else
|
||||
min.tm_sec = min.tm_min = min.tm_hour =
|
||||
min.tm_mday = min.tm_mon = min.tm_year = INT_MIN;
|
||||
|
||||
end = (time_t) LONG_MAX;
|
||||
new = gmtime(&end);
|
||||
if (new != NULL)
|
||||
max = *new;
|
||||
else
|
||||
max.tm_sec = max.tm_min = max.tm_hour =
|
||||
max.tm_mday = max.tm_mon = max.tm_year = INT_MAX;
|
||||
}
|
||||
|
||||
/* Make all the elements of TP that we pay attention to
|
||||
be within the ranges of reasonable values for those things. */
|
||||
#define normalize(elt, min, max, nextelt) \
|
||||
while (tp->elt < min) \
|
||||
{ \
|
||||
--tp->nextelt; \
|
||||
tp->elt += max + 1; \
|
||||
} \
|
||||
while (tp->elt > max) \
|
||||
{ \
|
||||
++tp->nextelt; \
|
||||
tp->elt -= max + 1; \
|
||||
}
|
||||
|
||||
normalize (tm_sec, 0, 59, tm_min);
|
||||
normalize (tm_min, 0, 59, tm_hour);
|
||||
normalize (tm_hour, 0, 24, tm_mday);
|
||||
|
||||
/* Normalize the month first so we can use
|
||||
it to figure the range for the day. */
|
||||
normalize (tm_mon, 0, 11, tm_year);
|
||||
normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
|
||||
tm_mon);
|
||||
|
||||
/* Normalize the month again, since normalizing
|
||||
the day may have pushed it out of range. */
|
||||
normalize (tm_mon, 0, 11, tm_year);
|
||||
|
||||
/* Normalize the day again, because normalizing
|
||||
the month may have changed the range. */
|
||||
normalize (tm_mday, 1, __mon_lengths[__isleap (tp->tm_year)][tp->tm_mon],
|
||||
tm_mon);
|
||||
|
||||
/* Check for out-of-range values. */
|
||||
#define lowhigh(field, minmax, cmp) (tp->field cmp minmax.field)
|
||||
#define low(field) lowhigh(field, min, <)
|
||||
#define high(field) lowhigh(field, max, >)
|
||||
#define oor(field) (low(field) || high(field))
|
||||
#define lowbound(field) (tp->field == min.field)
|
||||
#define highbound(field) (tp->field == max.field)
|
||||
if (oor(tm_year))
|
||||
invalid();
|
||||
else if (lowbound(tm_year))
|
||||
{
|
||||
if (low(tm_mon))
|
||||
invalid();
|
||||
else if (lowbound(tm_mon))
|
||||
{
|
||||
if (low(tm_mday))
|
||||
invalid();
|
||||
else if (lowbound(tm_mday))
|
||||
{
|
||||
if (low(tm_hour))
|
||||
invalid();
|
||||
else if (lowbound(tm_hour))
|
||||
{
|
||||
if (low(tm_min))
|
||||
invalid();
|
||||
else if (lowbound(tm_min))
|
||||
{
|
||||
if (low(tm_sec))
|
||||
invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (highbound(tm_year))
|
||||
{
|
||||
if (high(tm_mon))
|
||||
invalid();
|
||||
else if (highbound(tm_mon))
|
||||
{
|
||||
if (high(tm_mday))
|
||||
invalid();
|
||||
else if (highbound(tm_mday))
|
||||
{
|
||||
if (high(tm_hour))
|
||||
invalid();
|
||||
else if (highbound(tm_hour))
|
||||
{
|
||||
if (high(tm_min))
|
||||
invalid();
|
||||
else if (highbound(tm_min))
|
||||
{
|
||||
if (high(tm_sec))
|
||||
invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = 0;
|
||||
for (i = 1970; i > 1900 + tp->tm_year; --i)
|
||||
t -= __isleap(i) ? 366 : 365;
|
||||
for (i = 1970; i < 1900 + tp->tm_year; ++i)
|
||||
t += __isleap(i) ? 366 : 365;
|
||||
l = __mon_lengths[__isleap(1900 + tp->tm_year)];
|
||||
for (i = 0; i < tp->tm_mon; ++i)
|
||||
t += l[i];
|
||||
t += tp->tm_mday - 1;
|
||||
result = ((t * 60 * 60 * 24) +
|
||||
(tp->tm_hour * 60 * 60) +
|
||||
(tp->tm_min * 60) +
|
||||
tp->tm_sec);
|
||||
|
||||
end = result;
|
||||
#if 0 /* This code breaks it, on SunOS anyway. */
|
||||
if (tp->tm_isdst < 0)
|
||||
new = localtime(&end);
|
||||
else
|
||||
#endif
|
||||
new = gmtime(&end);
|
||||
if (new == NULL)
|
||||
invalid();
|
||||
new->tm_isdst = tp->tm_isdst;
|
||||
*tp = *new;
|
||||
|
||||
return result;
|
||||
}
|
173
lib/posixtm.y
Normal file
173
lib/posixtm.y
Normal file
@ -0,0 +1,173 @@
|
||||
/* Parse dates for touch.
|
||||
Copyright (C) 1989, 1990, 1991 Free Software Foundation Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by Jim Kingdon and David MacKenzie. */
|
||||
%{
|
||||
#ifdef __GNUC__
|
||||
#define alloca __builtin_alloca
|
||||
#else
|
||||
#ifdef sparc
|
||||
#include <alloca.h>
|
||||
#else
|
||||
#ifdef _AIX
|
||||
#pragma alloca
|
||||
#else
|
||||
char *alloca ();
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#define YYDEBUG 1
|
||||
|
||||
/* Lexical analyzer's current scan position in the input string. */
|
||||
static char *curpos;
|
||||
|
||||
/* The return value. */
|
||||
static struct tm t;
|
||||
|
||||
time_t mktime ();
|
||||
|
||||
#define yyparse posixtime_yyparse
|
||||
static int yylex ();
|
||||
static int yyerror ();
|
||||
%}
|
||||
|
||||
%token DIGIT
|
||||
|
||||
%%
|
||||
date :
|
||||
digitpair /* month */
|
||||
digitpair /* day */
|
||||
digitpair /* hours */
|
||||
digitpair /* minutes */
|
||||
year
|
||||
seconds {
|
||||
if ($1 >= 1 && $1 <= 12)
|
||||
t.tm_mon = $1 - 1;
|
||||
else {
|
||||
YYABORT;
|
||||
}
|
||||
if ($2 >= 1 && $2 <= 31)
|
||||
t.tm_mday = $2;
|
||||
else {
|
||||
YYABORT;
|
||||
}
|
||||
if ($3 >= 0 && $3 <= 23)
|
||||
t.tm_hour = $3;
|
||||
else {
|
||||
YYABORT;
|
||||
}
|
||||
if ($4 >= 0 && $4 <= 59)
|
||||
t.tm_min = $4;
|
||||
else {
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
|
||||
year : digitpair {
|
||||
t.tm_year = $1;
|
||||
/* Deduce the century based on the year.
|
||||
See POSIX.2 section 4.63.3. */
|
||||
if ($1 <= 68)
|
||||
t.tm_year += 100;
|
||||
}
|
||||
| digitpair digitpair {
|
||||
t.tm_year = $1 * 100 + $2;
|
||||
if (t.tm_year < 1900) {
|
||||
YYABORT;
|
||||
} else
|
||||
t.tm_year -= 1900;
|
||||
}
|
||||
| /* empty */ {
|
||||
time_t now;
|
||||
struct tm *tmp;
|
||||
|
||||
/* Use current year. */
|
||||
time (&now);
|
||||
tmp = localtime (&now);
|
||||
t.tm_year = tmp->tm_year;
|
||||
}
|
||||
;
|
||||
|
||||
seconds : /* empty */ {
|
||||
t.tm_sec = 0;
|
||||
}
|
||||
| '.' digitpair {
|
||||
if ($2 >= 0 && $2 <= 61)
|
||||
t.tm_sec = $2;
|
||||
else {
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
digitpair : DIGIT DIGIT {
|
||||
$$ = $1 * 10 + $2;
|
||||
}
|
||||
;
|
||||
%%
|
||||
static int
|
||||
yylex ()
|
||||
{
|
||||
char ch = *curpos++;
|
||||
|
||||
if (ch >= '0' && ch <= '9')
|
||||
{
|
||||
yylval = ch - '0';
|
||||
return DIGIT;
|
||||
}
|
||||
else if (ch == '.' || ch == 0)
|
||||
return ch;
|
||||
else
|
||||
return '?'; /* Cause an error. */
|
||||
}
|
||||
|
||||
static int
|
||||
yyerror ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse a POSIX-style date and return it, or (time_t)-1 for an error. */
|
||||
|
||||
time_t
|
||||
posixtime (s)
|
||||
char *s;
|
||||
{
|
||||
curpos = s;
|
||||
/* Let mktime decide whether it is daylight savings time. */
|
||||
t.tm_isdst = -1;
|
||||
if (yyparse ())
|
||||
return (time_t)-1;
|
||||
else
|
||||
return mktime (&t);
|
||||
}
|
||||
|
||||
/* Parse a POSIX-style date and return it, or NULL for an error. */
|
||||
|
||||
struct tm *
|
||||
posixtm (s)
|
||||
char *s;
|
||||
{
|
||||
if (posixtime (s) == -1)
|
||||
return NULL;
|
||||
return &t;
|
||||
}
|
101
lib/putenv.c
Normal file
101
lib/putenv.c
Normal file
@ -0,0 +1,101 @@
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(USG)
|
||||
#include <string.h>
|
||||
#define index strchr
|
||||
#define bcopy(s, d, n) memcpy((d), (s), (n))
|
||||
#else /* not (STDC_HEADERS or USG) */
|
||||
#include <strings.h>
|
||||
#endif /* STDC_HEADERS or USG */
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#if !__STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* Put STRING, which is of the form "NAME=VALUE", in the environment. */
|
||||
int
|
||||
putenv (string)
|
||||
const char *string;
|
||||
{
|
||||
char *name_end = index (string, '=');
|
||||
register size_t size;
|
||||
register char **ep;
|
||||
|
||||
if (name_end == NULL)
|
||||
{
|
||||
/* Remove the variable from the environment. */
|
||||
size = strlen (string);
|
||||
for (ep = environ; *ep != NULL; ++ep)
|
||||
if (!strncmp (*ep, string, size) && (*ep)[size] == '=')
|
||||
{
|
||||
while (ep[1] != NULL)
|
||||
{
|
||||
ep[0] = ep[1];
|
||||
++ep;
|
||||
}
|
||||
*ep = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size = 0;
|
||||
for (ep = environ; *ep != NULL; ++ep)
|
||||
if (!strncmp (*ep, string, name_end - string) &&
|
||||
(*ep)[name_end - string] == '=')
|
||||
break;
|
||||
else
|
||||
++size;
|
||||
|
||||
if (*ep == NULL)
|
||||
{
|
||||
static char **last_environ = NULL;
|
||||
char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
|
||||
if (new_environ == NULL)
|
||||
return -1;
|
||||
(void) bcopy ((char *) environ, (char *) new_environ, size * sizeof (char *));
|
||||
new_environ[size] = (char *) string;
|
||||
new_environ[size + 1] = NULL;
|
||||
if (last_environ != NULL)
|
||||
free ((char *) last_environ);
|
||||
last_environ = new_environ;
|
||||
environ = new_environ;
|
||||
}
|
||||
else
|
||||
*ep = (char *) string;
|
||||
|
||||
return 0;
|
||||
}
|
34
lib/stime.c
Normal file
34
lib/stime.c
Normal file
@ -0,0 +1,34 @@
|
||||
/* stime -- set the system clock
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* David MacKenzie <djm@ai.mit.edu> */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Set the system time to *WHEN seconds past the start of 1970 GMT. */
|
||||
|
||||
int
|
||||
stime (when)
|
||||
time_t *when;
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = *when;
|
||||
tv.tv_usec = 0;
|
||||
return settimeofday (&tv, (struct timezone *) 0);
|
||||
}
|
37
lib/strcspn.c
Normal file
37
lib/strcspn.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
char *index ();
|
||||
|
||||
/* Return the length of the maximum inital segment of S
|
||||
which contains no characters from REJECT. */
|
||||
int
|
||||
strcspn (s, reject)
|
||||
register char *s;
|
||||
register char *reject;
|
||||
{
|
||||
register int count = 0;
|
||||
|
||||
while (*s != '\0')
|
||||
if (index (reject, *s++) == 0)
|
||||
++count;
|
||||
else
|
||||
return count;
|
||||
|
||||
return count;
|
||||
}
|
428
lib/strftime.c
Normal file
428
lib/strftime.c
Normal file
@ -0,0 +1,428 @@
|
||||
/* strftime - custom formatting of date and/or time
|
||||
Copyright (C) 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Note: this version of strftime lacks locale support,
|
||||
but it is standalone.
|
||||
|
||||
Performs `%' substitutions similar to those in printf. Except
|
||||
where noted, substituted fields have a fixed size; numeric fields are
|
||||
padded if necessary. Padding is with zeros by default; for fields
|
||||
that display a single number, padding can be changed or inhibited by
|
||||
following the `%' with one of the modifiers described below. Unknown
|
||||
field specifiers are copied as normal characters. All other
|
||||
characters are copied to the output without change.
|
||||
|
||||
Supports a superset of the ANSI C field specifiers.
|
||||
|
||||
Literal character fields:
|
||||
% %
|
||||
n newline
|
||||
t tab
|
||||
|
||||
Numeric modifiers (a nonstandard extension):
|
||||
- do not pad the field
|
||||
_ pad the field with spaces
|
||||
|
||||
Time fields:
|
||||
%H hour (00..23)
|
||||
%I hour (01..12)
|
||||
%k hour ( 0..23)
|
||||
%l hour ( 1..12)
|
||||
%M minute (00..59)
|
||||
%p locale's AM or PM
|
||||
%r time, 12-hour (hh:mm:ss [AP]M)
|
||||
%R time, 24-hour (hh:mm)
|
||||
%S second (00..61)
|
||||
%T time, 24-hour (hh:mm:ss)
|
||||
%X locale's time representation (%H:%M:%S)
|
||||
%Z time zone (EDT), or nothing if no time zone is determinable
|
||||
|
||||
Date fields:
|
||||
%a locale's abbreviated weekday name (Sun..Sat)
|
||||
%A locale's full weekday name, variable length (Sunday..Saturday)
|
||||
%b locale's abbreviated month name (Jan..Dec)
|
||||
%B locale's full month name, variable length (January..December)
|
||||
%c locale's date and time (Sat Nov 04 12:02:33 EST 1989)
|
||||
%C century (00..99)
|
||||
%d day of month (01..31)
|
||||
%e day of month ( 1..31)
|
||||
%D date (mm/dd/yy)
|
||||
%h same as %b
|
||||
%j day of year (001..366)
|
||||
%m month (01..12)
|
||||
%U week number of year with Sunday as first day of week (00..53)
|
||||
%w day of week (0..6)
|
||||
%W week number of year with Monday as first day of week (00..53)
|
||||
%x locale's date representation (mm/dd/yy)
|
||||
%y last two digits of year (00..99)
|
||||
%Y year (1970...)
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TZNAME)
|
||||
extern char *tzname[2];
|
||||
#endif
|
||||
|
||||
#if !__STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* Types of padding for numbers in date and time. */
|
||||
enum padding
|
||||
{
|
||||
none, blank, zero
|
||||
};
|
||||
|
||||
static char *days[] =
|
||||
{
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||
};
|
||||
|
||||
static char *months[] =
|
||||
{
|
||||
"January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"
|
||||
};
|
||||
|
||||
/* Add character C to STRING and increment LENGTH,
|
||||
unless LENGTH would exceed MAX. */
|
||||
|
||||
#define add_char(c) (length + 1 <= max) && (string[length++] = (c))
|
||||
|
||||
/* Add a 2 digit number to STRING, padding if specified.
|
||||
Return the number of characters added, up to MAX. */
|
||||
|
||||
static int
|
||||
add_num2 (string, num, max, pad)
|
||||
char *string;
|
||||
int num;
|
||||
int max;
|
||||
enum padding pad;
|
||||
{
|
||||
int top = num / 10;
|
||||
int length = 0;
|
||||
|
||||
if (top == 0 && pad == blank)
|
||||
add_char (' ');
|
||||
else if (top != 0 || pad == zero)
|
||||
add_char (top + '0');
|
||||
add_char (num % 10 + '0');
|
||||
return length;
|
||||
}
|
||||
|
||||
/* Add a 3 digit number to STRING, padding if specified.
|
||||
Return the number of characters added, up to MAX. */
|
||||
|
||||
static int
|
||||
add_num3 (string, num, max, pad)
|
||||
char *string;
|
||||
int num;
|
||||
int max;
|
||||
enum padding pad;
|
||||
{
|
||||
int top = num / 100;
|
||||
int mid = (num - top * 100) / 10;
|
||||
int length = 0;
|
||||
|
||||
if (top == 0 && pad == blank)
|
||||
add_char (' ');
|
||||
else if (top != 0 || pad == zero)
|
||||
add_char (top + '0');
|
||||
if (mid == 0 && top == 0 && pad == blank)
|
||||
add_char (' ');
|
||||
else if (mid != 0 || top != 0 || pad == zero)
|
||||
add_char (mid + '0');
|
||||
add_char (num % 10 + '0');
|
||||
return length;
|
||||
}
|
||||
|
||||
/* Like strncpy except return the number of characters copied. */
|
||||
|
||||
static int
|
||||
add_str (to, from, max)
|
||||
char *to;
|
||||
char *from;
|
||||
int max;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; from[i] && i <= max; ++i)
|
||||
to[i] = from[i];
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Return the week in the year of the time in TM, with the weeks
|
||||
starting on Sundays. */
|
||||
|
||||
static int
|
||||
sun_week (tm)
|
||||
struct tm *tm;
|
||||
{
|
||||
int dl;
|
||||
|
||||
/* Set `dl' to the day in the year of the last day of the week previous
|
||||
to the one containing the day specified in TM. If the day specified
|
||||
in TM is in the first week of the year, `dl' will be negative or 0.
|
||||
Otherwise, calculate the number of complete weeks before our week
|
||||
(dl / 7) and add any partial week at the start of the year (dl % 7). */
|
||||
dl = tm->tm_yday - tm->tm_wday;
|
||||
return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
|
||||
}
|
||||
|
||||
/* Return the week in the year of the time in TM, with the weeks
|
||||
starting on Mondays. */
|
||||
|
||||
static int
|
||||
mon_week (tm)
|
||||
struct tm *tm;
|
||||
{
|
||||
int dl, wday;
|
||||
|
||||
if (tm->tm_wday == 0)
|
||||
wday = 6;
|
||||
else
|
||||
wday = tm->tm_wday - 1;
|
||||
dl = tm->tm_yday - wday;
|
||||
return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
|
||||
}
|
||||
|
||||
#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
|
||||
char *
|
||||
zone_name (tp)
|
||||
struct tm *tp;
|
||||
{
|
||||
char *timezone ();
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
|
||||
gettimeofday (&tv, &tz);
|
||||
return timezone (tz.tz_minuteswest, tp->tm_isdst);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Format the time given in TM according to FORMAT, and put the
|
||||
results in STRING.
|
||||
Return the number of characters (not including terminating null)
|
||||
that were put into STRING, or 0 if the length would have
|
||||
exceeded MAX. */
|
||||
|
||||
size_t
|
||||
strftime (string, max, format, tm)
|
||||
char *string;
|
||||
size_t max;
|
||||
const char *format;
|
||||
const struct tm *tm;
|
||||
{
|
||||
enum padding pad; /* Type of padding to apply. */
|
||||
size_t length = 0; /* Characters put in STRING so far. */
|
||||
|
||||
for (; *format && length < max; ++format)
|
||||
{
|
||||
if (*format != '%')
|
||||
add_char (*format);
|
||||
else
|
||||
{
|
||||
++format;
|
||||
/* Modifiers: */
|
||||
if (*format == '-')
|
||||
{
|
||||
pad = none;
|
||||
++format;
|
||||
}
|
||||
else if (*format == '_')
|
||||
{
|
||||
pad = blank;
|
||||
++format;
|
||||
}
|
||||
else
|
||||
pad = zero;
|
||||
|
||||
switch (*format)
|
||||
{
|
||||
/* Literal character fields: */
|
||||
case 0:
|
||||
case '%':
|
||||
add_char ('%');
|
||||
break;
|
||||
case 'n':
|
||||
add_char ('\n');
|
||||
break;
|
||||
case 't':
|
||||
add_char ('\t');
|
||||
break;
|
||||
default:
|
||||
add_char (*format);
|
||||
break;
|
||||
|
||||
/* Time fields: */
|
||||
case 'H':
|
||||
case 'k':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_hour, max - length,
|
||||
*format == 'H' ? pad : blank);
|
||||
break;
|
||||
case 'I':
|
||||
case 'l':
|
||||
{
|
||||
int hour12;
|
||||
|
||||
if (tm->tm_hour == 0)
|
||||
hour12 = 12;
|
||||
else if (tm->tm_hour > 12)
|
||||
hour12 = tm->tm_hour - 12;
|
||||
else
|
||||
hour12 = tm->tm_hour;
|
||||
length +=
|
||||
add_num2 (&string[length], hour12, max - length,
|
||||
*format == 'I' ? pad : blank);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_min, max - length, pad);
|
||||
break;
|
||||
case 'p':
|
||||
if (tm->tm_hour < 12)
|
||||
add_char ('A');
|
||||
else
|
||||
add_char ('P');
|
||||
add_char ('M');
|
||||
break;
|
||||
case 'r':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%I:%M:%S %p", tm);
|
||||
break;
|
||||
case 'R':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%H:%M", tm);
|
||||
break;
|
||||
case 'S':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_sec, max - length, pad);
|
||||
break;
|
||||
case 'T':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%H:%M:%S", tm);
|
||||
break;
|
||||
case 'X':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%H:%M:%S", tm);
|
||||
break;
|
||||
case 'Z':
|
||||
#ifdef HAVE_TM_ZONE
|
||||
length += add_str (&string[length], tm->tm_zone, max - length);
|
||||
#else
|
||||
#ifdef HAVE_TZNAME
|
||||
if (tm->tm_isdst && tzname[1] && *tzname[1])
|
||||
length += add_str (&string[length], tzname[1], max - length);
|
||||
else
|
||||
length += add_str (&string[length], tzname[0], max - length);
|
||||
#else
|
||||
length += add_str (&string[length], zone_name (tm), max - length);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* Date fields: */
|
||||
case 'a':
|
||||
add_char (days[tm->tm_wday][0]);
|
||||
add_char (days[tm->tm_wday][1]);
|
||||
add_char (days[tm->tm_wday][2]);
|
||||
break;
|
||||
case 'A':
|
||||
length +=
|
||||
add_str (&string[length], days[tm->tm_wday], max - length);
|
||||
break;
|
||||
case 'b':
|
||||
case 'h':
|
||||
add_char (months[tm->tm_mon][0]);
|
||||
add_char (months[tm->tm_mon][1]);
|
||||
add_char (months[tm->tm_mon][2]);
|
||||
break;
|
||||
case 'B':
|
||||
length +=
|
||||
add_str (&string[length], months[tm->tm_mon], max - length);
|
||||
break;
|
||||
case 'c':
|
||||
length +=
|
||||
strftime (&string[length], max - length,
|
||||
"%a %b %d %H:%M:%S %Z %Y", tm);
|
||||
break;
|
||||
case 'C':
|
||||
length +=
|
||||
add_num2 (&string[length], (tm->tm_year + 1900) / 100,
|
||||
max - length, pad);
|
||||
break;
|
||||
case 'd':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_mday, max - length, pad);
|
||||
break;
|
||||
case 'e':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_mday, max - length, blank);
|
||||
break;
|
||||
case 'D':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%m/%d/%y", tm);
|
||||
break;
|
||||
case 'j':
|
||||
length +=
|
||||
add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
|
||||
break;
|
||||
case 'm':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
|
||||
break;
|
||||
case 'U':
|
||||
length +=
|
||||
add_num2 (&string[length], sun_week (tm), max - length, pad);
|
||||
break;
|
||||
case 'w':
|
||||
add_char (tm->tm_wday + '0');
|
||||
break;
|
||||
case 'W':
|
||||
length +=
|
||||
add_num2 (&string[length], mon_week (tm), max - length, pad);
|
||||
break;
|
||||
case 'x':
|
||||
length +=
|
||||
strftime (&string[length], max - length, "%m/%d/%y", tm);
|
||||
break;
|
||||
case 'y':
|
||||
length +=
|
||||
add_num2 (&string[length], tm->tm_year % 100,
|
||||
max - length, pad);
|
||||
break;
|
||||
case 'Y':
|
||||
add_char ((tm->tm_year + 1900) / 1000 + '0');
|
||||
length +=
|
||||
add_num3 (&string[length],
|
||||
(1900 + tm->tm_year) % 1000, max - length, zero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
add_char (0);
|
||||
return length - 1;
|
||||
}
|
188
lib/strtod.c
Normal file
188
lib/strtod.c
Normal file
@ -0,0 +1,188 @@
|
||||
/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <float.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
#define NULL 0
|
||||
#define DBL_MAX 1.7976931348623159e+308
|
||||
#define DBL_MIN 2.2250738585072010e-308
|
||||
extern int errno;
|
||||
#endif
|
||||
#ifndef HUGE_VAL
|
||||
#define HUGE_VAL HUGE
|
||||
#endif
|
||||
|
||||
#if !__STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
/* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the
|
||||
character after the last one used in the number is put in *ENDPTR. */
|
||||
double
|
||||
strtod (nptr, endptr)
|
||||
const char *nptr;
|
||||
char **endptr;
|
||||
{
|
||||
register const char *s;
|
||||
short int sign;
|
||||
|
||||
/* The number so far. */
|
||||
double num;
|
||||
|
||||
int got_dot; /* Found a decimal point. */
|
||||
int got_digit; /* Seen any digits. */
|
||||
|
||||
/* The exponent of the number. */
|
||||
long int exponent;
|
||||
|
||||
if (nptr == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto noconv;
|
||||
}
|
||||
|
||||
s = nptr;
|
||||
|
||||
/* Eat whitespace. */
|
||||
while (isspace (*s))
|
||||
++s;
|
||||
|
||||
/* Get the sign. */
|
||||
sign = *s == '-' ? -1 : 1;
|
||||
if (*s == '-' || *s == '+')
|
||||
++s;
|
||||
|
||||
num = 0.0;
|
||||
got_dot = 0;
|
||||
got_digit = 0;
|
||||
exponent = 0;
|
||||
for (;; ++s)
|
||||
{
|
||||
if (isdigit (*s))
|
||||
{
|
||||
got_digit = 1;
|
||||
|
||||
/* Make sure that multiplication by 10 will not overflow. */
|
||||
if (num > DBL_MAX * 0.1)
|
||||
/* The value of the digit doesn't matter, since we have already
|
||||
gotten as many digits as can be represented in a `double'.
|
||||
This doesn't necessarily mean the result will overflow.
|
||||
The exponent may reduce it to within range.
|
||||
|
||||
We just need to record that there was another
|
||||
digit so that we can multiply by 10 later. */
|
||||
++exponent;
|
||||
else
|
||||
num = (num * 10.0) + (*s - '0');
|
||||
|
||||
/* Keep track of the number of digits after the decimal point.
|
||||
If we just divided by 10 here, we would lose precision. */
|
||||
if (got_dot)
|
||||
--exponent;
|
||||
}
|
||||
else if (!got_dot && *s == '.')
|
||||
/* Record that we have found the decimal point. */
|
||||
got_dot = 1;
|
||||
else
|
||||
/* Any other character terminates the number. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!got_digit)
|
||||
goto noconv;
|
||||
|
||||
if (tolower (*s) == 'e')
|
||||
{
|
||||
/* Get the exponent specified after the `e' or `E'. */
|
||||
int save = errno;
|
||||
char *end;
|
||||
long int exp;
|
||||
|
||||
errno = 0;
|
||||
++s;
|
||||
exp = strtol (s, &end, 10);
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
/* The exponent overflowed a `long int'. It is probably a safe
|
||||
assumption that an exponent that cannot be represented by
|
||||
a `long int' exceeds the limits of a `double'. */
|
||||
if (endptr != NULL)
|
||||
*endptr = end;
|
||||
if (exp < 0)
|
||||
goto underflow;
|
||||
else
|
||||
goto overflow;
|
||||
}
|
||||
else if (end == s)
|
||||
/* There was no exponent. Reset END to point to
|
||||
the 'e' or 'E', so *ENDPTR will be set there. */
|
||||
end = (char *) s - 1;
|
||||
errno = save;
|
||||
s = end;
|
||||
exponent += exp;
|
||||
}
|
||||
|
||||
if (endptr != NULL)
|
||||
*endptr = (char *) s;
|
||||
|
||||
if (num == 0.0)
|
||||
return 0.0;
|
||||
|
||||
/* Multiply NUM by 10 to the EXPONENT power,
|
||||
checking for overflow and underflow. */
|
||||
|
||||
if (exponent < 0)
|
||||
{
|
||||
if (num < DBL_MIN * pow (10.0, (double) -exponent))
|
||||
goto underflow;
|
||||
}
|
||||
else if (exponent > 0)
|
||||
{
|
||||
if (num > DBL_MAX * pow (10.0, (double) -exponent))
|
||||
goto overflow;
|
||||
}
|
||||
|
||||
num *= pow (10.0, (double) exponent);
|
||||
|
||||
return num * sign;
|
||||
|
||||
overflow:
|
||||
/* Return an overflow error. */
|
||||
errno = ERANGE;
|
||||
return HUGE_VAL * sign;
|
||||
|
||||
underflow:
|
||||
/* Return an underflow error. */
|
||||
if (endptr != NULL)
|
||||
*endptr = (char *) nptr;
|
||||
errno = ERANGE;
|
||||
return 0.0;
|
||||
|
||||
noconv:
|
||||
/* There was no number. */
|
||||
if (endptr != NULL)
|
||||
*endptr = (char *) nptr;
|
||||
return 0.0;
|
||||
}
|
65
lib/xmalloc.c
Normal file
65
lib/xmalloc.c
Normal file
@ -0,0 +1,65 @@
|
||||
/* xmalloc.c -- malloc with out of memory checking
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
char *realloc ();
|
||||
void free ();
|
||||
#endif
|
||||
|
||||
void error ();
|
||||
|
||||
/* Allocate N bytes of memory dynamically, with error checking. */
|
||||
|
||||
char *
|
||||
xmalloc (n)
|
||||
unsigned n;
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = malloc (n);
|
||||
if (p == 0)
|
||||
/* Must exit with 2 for `cmp'. */
|
||||
error (2, 0, "virtual memory exhausted");
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Change the size of an allocated block of memory P to N bytes,
|
||||
with error checking.
|
||||
If P is NULL, run xmalloc.
|
||||
If N is 0, run free and return NULL. */
|
||||
|
||||
char *
|
||||
xrealloc (p, n)
|
||||
char *p;
|
||||
unsigned n;
|
||||
{
|
||||
if (p == 0)
|
||||
return xmalloc (n);
|
||||
if (n == 0)
|
||||
{
|
||||
free (p);
|
||||
return 0;
|
||||
}
|
||||
p = realloc (p, n);
|
||||
if (p == 0)
|
||||
/* Must exit with 2 for `cmp'. */
|
||||
error (2, 0, "virtual memory exhausted");
|
||||
return p;
|
||||
}
|
696
old/sh-utils/ChangeLog
Normal file
696
old/sh-utils/ChangeLog
Normal file
@ -0,0 +1,696 @@
|
||||
Wed Oct 28 14:16:48 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.8.
|
||||
|
||||
* stty.c: Accept Irix VRPRNT for VREPRINT.
|
||||
From Jim Meyering.
|
||||
|
||||
* stty.c: Fix some type mismatches. From Bruce Evans, bde@runx.oz.au.
|
||||
|
||||
* who.c (read_utmp): Close file on error.
|
||||
From Bruce Evans.
|
||||
|
||||
* su.c, test.c: Add some decls. From Bruce Evans.
|
||||
|
||||
* sleep.c (main): Arg to sleep is unsigned, not long.
|
||||
From Bruce Evans.
|
||||
|
||||
Fri Sep 11 00:25:52 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* echo.c, echo.1: New files.
|
||||
|
||||
Thu Sep 10 18:42:44 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* pathchk.c (main): Don't strip trailing slashes from args;
|
||||
they might make a path invalid.
|
||||
(portable_chars_only, dir_ok): New functions.
|
||||
(validate_path): Renamed from validate_new_path.
|
||||
Call them. Don't complain if a leading
|
||||
dir doesn't exist. Don't replace `parent' with a dir that
|
||||
doesn't exist. Don't print a message when falling back
|
||||
from pathconf to constant values.
|
||||
|
||||
* who.c [!UTMP_FILE]: If _PATH_UTMP is defined, use it instead
|
||||
of /etc/utmp. From Marc Boucher <marc@cam.org>.
|
||||
|
||||
Tue Aug 25 17:02:25 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.7.
|
||||
|
||||
* groups.sh, nohup.sh: Add $(bindir) to front of path.
|
||||
|
||||
Mon Aug 24 16:39:39 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c: make sane value for "min" 1, not 0.
|
||||
From haible@ma2s2.mathematik.uni-karlsruhe.de (Bruno Haible).
|
||||
|
||||
Sun Aug 23 03:02:07 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* id.c, test.c: Use NGROUPS_MAX if it's defined. 386BSD is like sun.
|
||||
|
||||
Sat Aug 22 03:16:41 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* test.c: Rename STANDALONE to TEST_STANDALONE to avoid IBM RT
|
||||
ACIS sys/param.h conflict.
|
||||
|
||||
* su.c (correct_password) [HAVE_SHADOW_H]: Try to get the
|
||||
encrypted correct password from the shadow password file.
|
||||
|
||||
Fri Jul 17 15:25:01 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* su.c, getusershell.c: New files.
|
||||
|
||||
Fri Jul 3 15:08:43 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c, who.c: Change FOO_MISSING to HAVE_FOO.
|
||||
|
||||
Fri Jun 5 01:49:29 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* strcspn.c: New file.
|
||||
|
||||
* expr.c: Misc. cleanups.
|
||||
|
||||
* expr.c (eval7): Renamed from eval6.
|
||||
Give syntax error if no more args. Don't coerce all values to numbers.
|
||||
(eval6): New function.
|
||||
(eval5): Accept == as a synonym for =.
|
||||
(eval2): Coerce values to numbers for comparisons.
|
||||
Above all from Dana Jacobsen (jacobsd@prism.cs.orst.edu).
|
||||
|
||||
Thu Jun 4 19:32:09 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* printf.c (print_formatted): Move main loop into new function.
|
||||
(main): Add an outer loop to use the format multiple times.
|
||||
(verify): Don't reject a completely empty string.
|
||||
Check errno (for overflow).
|
||||
|
||||
* false.sh, true.sh: New programs. Oh, boy.
|
||||
|
||||
Thu May 14 01:17:22 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c (set_mode): Support crt and dec modes partially if
|
||||
necessary, so they work on, for example, Ultrix . . . .
|
||||
|
||||
Wed May 13 14:47:45 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c (set_mode): Swap nl and -nl. Have them also affect
|
||||
output as well as input.
|
||||
|
||||
Tue May 12 00:07:28 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* date.c (show_date): Use strftime for the whole conversion.
|
||||
|
||||
Tue May 5 15:20:24 1992 David J. MacKenzie (djm@hal)
|
||||
|
||||
* stty.c (wrapf): Print the formatted buffer; don't redo the
|
||||
formatting using vprintf.
|
||||
|
||||
Thu Apr 30 01:17:08 1992 David J. MacKenzie (djm@churchy.gnu.ai.mit.edu)
|
||||
|
||||
* printf.c (xstrtol, xstrtoul, xstrtod, verify): New functions.
|
||||
(main, print_direc): Use them. Make error messages more specific.
|
||||
|
||||
* tee.c (tee): Only malloc and free the table of file descriptors
|
||||
if >0 files are given.
|
||||
|
||||
Fri Apr 17 11:56:48 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* pathchk.c (validate_new_path): Print the name of the component that
|
||||
failed the length test, not the whole path.
|
||||
From Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de).
|
||||
|
||||
Mon Apr 6 15:11:36 1992 David J. MacKenzie (djm@wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* who.c (read_utmp): Check close return for error.
|
||||
(print_heading): Align columns based on sizes of utmp members.
|
||||
(who_am_i): Skip past /dev/ instead of skipping leading path.
|
||||
|
||||
Mon Mar 16 23:47:03 1992 David J. MacKenzie (djm@apple-gunkies.gnu.ai.mit.edu)
|
||||
|
||||
* date.c (show_date): Don't call strftime if FORMAT is the
|
||||
empty string.
|
||||
|
||||
* date.c (main): Reorganize to reduce duplicated code.
|
||||
Add -d option.
|
||||
(usage): Document -d.
|
||||
(set_date): Function removed.
|
||||
|
||||
Tue Feb 11 16:12:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* printf.c (print_esc): When a numeric escape is given,
|
||||
don't call print_esc_char, and return 1 less.
|
||||
From Thorston Ohl.
|
||||
|
||||
Mon Jan 20 02:17:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.6.
|
||||
|
||||
* test.c: HAVE_MULTIPLE_GROUPS -> HAVE_GETGROUPS, for bash 1.11.
|
||||
|
||||
Fri Jan 17 15:46:18 1992 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* expr.c (docolon): Use re_nsub to find the number of
|
||||
subexpressions . . . From Karl Berry, who knows.
|
||||
|
||||
Wed Dec 25 23:27:53 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* expr.c (docolon): Use the new way (re_regs.num_regs > 0) to find
|
||||
out if there were any subexpressions, instead of the old way
|
||||
(re_regs.start[1] >= 0), which can cause random memory
|
||||
accesses with regex 0.1. From Brian Matthews.
|
||||
|
||||
Tue Dec 24 02:12:15 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* system.h, id.c, pathchk.c, tee.c: Change POSIX ifdefs to
|
||||
HAVE_UNISTD_H and _POSIX_VERSION.
|
||||
|
||||
Wed Dec 11 13:15:09 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.5.
|
||||
|
||||
* expr.c (main): Set obscure_syntax to tell re_match to
|
||||
allocate memory for the group registers.
|
||||
|
||||
Mon Dec 9 16:03:14 1991 Charles Hannum (mycroft at hal.gnu.ai.mit.edu)
|
||||
|
||||
* who.c (list_entries): Check type == USER_PROCESS if defined, for SysV.
|
||||
|
||||
Sat Dec 7 00:32:02 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.4.
|
||||
|
||||
* env, id, nice, pathchk, stty, tee, tty, uname: Change usage
|
||||
messages and documentation to list long-named options starting
|
||||
with `--' rather than `+'.
|
||||
|
||||
* env.c (main), nice.c (main): Simplify test for which exit
|
||||
status to use if exec fails.
|
||||
|
||||
Fri Dec 6 23:49:42 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* tee.c (main) [POSIX]: Use sigaction instead of signal, which
|
||||
POSIX doesn't have.
|
||||
|
||||
Fri Oct 18 00:31:35 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* test.c (two_arguments): Fix from Chet.
|
||||
|
||||
* expr.c: Include regex.h after sys/types.h, not before, so
|
||||
size_t gets defined.
|
||||
|
||||
* test.c: New version, adapted from bash 1.10.
|
||||
|
||||
* id.c: GID_T -> GETGROUPS_T, for clarity.
|
||||
|
||||
Sat Oct 12 14:38:34 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
|
||||
|
||||
* configure: Define uid_t and gid_t as int if they're not
|
||||
defined in sys/types.h. That's probably right for old Unixes
|
||||
and avoids trying to find the C preprocessor.
|
||||
|
||||
Sat Sep 28 13:01:23 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c (set_mode): Make `raw' and `cooked' not change parity
|
||||
and character size, which would probably make them useless on
|
||||
7-bit lines.
|
||||
Make `raw' set the `time' character to 0, not 1.
|
||||
From Bruce Evans.
|
||||
|
||||
* nohup.sh: If creating nohup.out, give it mode 0600, for POSIX.
|
||||
|
||||
Fri Sep 13 14:59:51 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
|
||||
|
||||
* id.c [POSIX]: Always use sysconf to get NGROUPS_MAX.
|
||||
|
||||
Thu Aug 29 14:43:07 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* test.c: Don't include sys/file.h if POSIX.
|
||||
Use gid_t for getgroups.
|
||||
|
||||
* stty.c (set_mode): Use CEOF and CEOL instead of hardcoding them.
|
||||
(display_speed): Fix a printf string type mismatch.
|
||||
From Bruce Evans.
|
||||
|
||||
Mon Aug 26 16:52:51 1991 David J. MacKenzie (djm at pogo.gnu.ai.mit.edu)
|
||||
|
||||
* configure, src/Makefile.in, lib/Makefile.in: Only put $< in
|
||||
Makefiles if VPATH is being used, because older makes don't
|
||||
understand it.
|
||||
|
||||
Mon Aug 19 01:57:46 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.3.
|
||||
|
||||
Sat Aug 17 22:48:15 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* src/Makefile.in (install): Install a link to test called '['.
|
||||
|
||||
Wed Aug 14 12:22:57 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* test.c (unary_operator): Check first char of string, not its address.
|
||||
|
||||
Sun Aug 11 18:10:30 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.2.
|
||||
|
||||
* system.h: Define S_IFMT if needed, for test.c.
|
||||
|
||||
* test.c: New file, from bash.
|
||||
|
||||
* nice.c: Change +priority to +adjustment (more accurate).
|
||||
|
||||
Sat Aug 10 13:09:51 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c [WINSIZE_IN_PTEM]: sys/ptem.h requires sys/stream.h.
|
||||
|
||||
* nice.c, configure: Use nice if available and setpriority is missing.
|
||||
|
||||
Thu Aug 8 01:34:05 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* date.c: USG needs TZ=GMT0 for UCT timezone, also.
|
||||
|
||||
* stty.c: Add pass8 and litout modes.
|
||||
|
||||
Sun Aug 4 22:45:51 1991 David J. MacKenzie (djm at wheat-chex)
|
||||
|
||||
* Version 1.1.
|
||||
|
||||
Fri Aug 2 13:22:31 1991 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* configure: Implement +srcdir. Don't check for bison.
|
||||
|
||||
* stty.c: Don't change ixon in "sane" mode.
|
||||
|
||||
* configure: Use 1 instead of 255 for checking tzname,
|
||||
because of signedness.
|
||||
|
||||
Thu Aug 1 13:40:58 1991 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* printenv.c (main): Don't print the variable names when given
|
||||
args, as people seem to use printenv in scripts after all . . . .
|
||||
|
||||
* stty.c: Don't change parity or character size settings in
|
||||
"sane" mode. The right values for those depend on the hardware.
|
||||
|
||||
Wed Jul 31 01:19:01 1991 David J. MacKenzie (djm at hal)
|
||||
|
||||
* stty.c [_AIX]: Include sys/ioctl.h -- needed on
|
||||
AIX to get window size.
|
||||
|
||||
Tue Jul 30 00:06:54 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* getdate.y: New file.
|
||||
* date.c: Add -s option to set date in English.
|
||||
* configure: Check for ftime.
|
||||
|
||||
* date.c: Remove COMPUTE_TM_ZONE code, which didn't work.
|
||||
* configure: Instead of checking whether tzname is declared,
|
||||
check whether it exists.
|
||||
|
||||
* logname.c (main): Go back to just printing an error message
|
||||
if getlogin fails, as required by POSIX.
|
||||
|
||||
* stty.c (screen_columns, wrapf): New functions to implement
|
||||
output wrapping.
|
||||
Globally: use them.
|
||||
|
||||
* configure: Define uid_t and gid_t if sys/types.h doesn't.
|
||||
* system.h: Define F_OK et al. if nothing else does.
|
||||
|
||||
Mon Jul 29 21:11:16 1991 David J. MacKenzie (djm at wombat.gnu.ai.mit.edu)
|
||||
|
||||
* pathchk.c (validate_new_path): Rearrange tests so that
|
||||
pathconf is only called on existing directories. Use access
|
||||
instead of stat to determine directory searchability.
|
||||
From Jim Meyering.
|
||||
|
||||
* stty.c, configure: Add WINSIZE_IN_PTEM and GWINSZ_BROKEN for SCO.
|
||||
|
||||
Wed Jul 24 02:13:31 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c (sane_mode): Always set control chars to sane values.
|
||||
Set min and time if they're different from eof and eol.
|
||||
|
||||
* whoami.c: Print UID as unsigned.
|
||||
* logname.c: Do "whoami" if getlogin fails.
|
||||
|
||||
* logname.c (main): fprintf was missing an arg.
|
||||
|
||||
Tue Jul 23 02:20:15 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* id.c: GID_T is int if ultrix as well as if sun.
|
||||
|
||||
* stty.c: Implement raw and cooked modes.
|
||||
|
||||
Mon Jul 22 15:21:21 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* tee.c (main): close stdin and stdout to check for errors.
|
||||
|
||||
* stty.c: Use tcflag_t for termios bitmasks.
|
||||
Use speed_t for speeds. Use unsigned long for baud rates to
|
||||
accomodate large values, and support 57600 and 115200 if available.
|
||||
|
||||
* date.c, configure: Instead of SIZE_T_MISSING,
|
||||
define size_t if it's missing.
|
||||
|
||||
* id.c, whoami.c: Use uid_t and gid_t.
|
||||
|
||||
* id.c: If POSIX and not sun (bogus!), pass getgroups and
|
||||
getugroups an array of gid_t instead of int.
|
||||
|
||||
* system.h: New file.
|
||||
* Most programs: include it.
|
||||
|
||||
Fri Jul 19 12:04:58 1991 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* env.c [!STDC_HEADERS]: Declare errno.
|
||||
* printf.c, pathchk.c: Don't include errno.h; not needed.
|
||||
|
||||
* version.c: New file.
|
||||
* All C programs: Link with it, to get version number in the
|
||||
binary where at least `strings -' and grep can find it.
|
||||
|
||||
* pathchk.c (strip_trailing_slashes): Function removed; use
|
||||
version in lib.
|
||||
|
||||
Mon Jul 15 11:34:22 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* Version 1.0.
|
||||
|
||||
* pathchk.c: Always check whether _POSIX_PATH_MAX and
|
||||
_POSIX_NAME_MAX need to be defined.
|
||||
[POSIX]: If no PATH_MAX or NAME_MAX and pathconf for the path
|
||||
returns -1 (some systems do this if the path does not exist),
|
||||
use pathconf for "/".
|
||||
|
||||
Sun Jul 14 21:17:22 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* date.c (date_seconds): Function removed, replaced with
|
||||
posixtm.y in lib.
|
||||
(set_date): Change caller.
|
||||
* configure: Check for bison.
|
||||
|
||||
* stty.c [!C_LINE_MISSING]: Add support for setting and
|
||||
printing the line discipline.
|
||||
* configure: Check for C_LINE_MISSING.
|
||||
|
||||
* configure: Check for Minix.
|
||||
|
||||
Sat Jul 13 01:33:59 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* Add `man' directory and manual pages.
|
||||
* configure: Set INSTALLDATA and MAN.
|
||||
|
||||
* id.c: Add #ifdefs for POSIX ways of getting max groups list size.
|
||||
(print_group_list, print_full_info): Allocate list of groups
|
||||
with malloc since its size might not be constant.
|
||||
|
||||
* nice.c (main): Don't adjust priority if printing it.
|
||||
Default adjustment of 10, not 0.
|
||||
|
||||
* printf.c: Add \c escape and %b conversion.
|
||||
Implement '*' for field width and precision.
|
||||
Make all errors fatal.
|
||||
(print_esc_string, print_esc): New functions.
|
||||
|
||||
* configure, date.c: Change SYS_TIME_H to TM_IN_SYS_TIME.
|
||||
* configure: Always check where to find struct tm.
|
||||
|
||||
* yes.c: Rewrite to accept multiple arguments.
|
||||
|
||||
* Add groups.sh.
|
||||
|
||||
Fri Jul 12 10:57:00 1991 David J. MacKenzie (djm at wookumz.gnu.ai.mit.edu)
|
||||
|
||||
* dirname.c: Move code from dirname function into main,
|
||||
simplifying things quite a bit. From Jim Meyering.
|
||||
* Omit strdup from lib; no longer used.
|
||||
* configure: Don't check for strdup.
|
||||
|
||||
* printenv.c (main): If args given, print the values in the order
|
||||
given on the command line rather than the order given in the
|
||||
environment.
|
||||
|
||||
* tee.c, tty.c (struct longopts): Revise to make short-option
|
||||
equivalents clear.
|
||||
|
||||
Thu Jul 11 12:46:11 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* nice.c: Add long options.
|
||||
|
||||
* Add date command and libraries it needs.
|
||||
* configure: Updated.
|
||||
|
||||
* env.c: Add long options. Use GNU putenv instead of custom
|
||||
setenv function.
|
||||
|
||||
* id.c: Add long options.
|
||||
|
||||
* pathchk.c [POSIX]: Use pathconf if necessary to get NAME_MAX
|
||||
and PATH_MAX.
|
||||
|
||||
* nice.c: Use exit status required for nohup by POSIX.2
|
||||
(nohup execs nice).
|
||||
|
||||
* sleep.c: Don't bother with hex and octal.
|
||||
|
||||
* env.c: Fix exit status for POSIX.2 draft 11.1.
|
||||
|
||||
* Many files: Remove private copies of xmalloc, error, xstrdup,
|
||||
etc. to use shared versions.
|
||||
Fix #includes for USG, STDC_HEADERS, POSIX.
|
||||
|
||||
Mon Jul 8 18:56:24 1991 David J. MacKenzie (djm at churchy.gnu.ai.mit.edu)
|
||||
|
||||
* date.c (main): For -u, set TZ to "" instead of "GMT0",
|
||||
unless on HP-UX or Ultrix.
|
||||
|
||||
* Rename some feature-test macros.
|
||||
* stime.c: Created from code in date.c.
|
||||
* date.c (compute_tm_zone): New function.
|
||||
(date_seconds, show_date): Use it.
|
||||
(xmalloc, xrealloc): Functions removed; use xmalloc.c instead.
|
||||
|
||||
Tue Jul 2 02:28:11 1991 David J. MacKenzie (djm at geech.gnu.ai.mit.edu)
|
||||
|
||||
* tee.c (tee): Report errors in closing files.
|
||||
|
||||
Mon Mar 18 10:13:59 1991 Jeffrey A. Law (law at geech.ai.mit.edu)
|
||||
|
||||
* date.c (date_seconds, show_date): #if COMPUTE_TMZONE then
|
||||
compute the proper value to place in tm->tm_zone from
|
||||
information returned by localtime and gettimeofday.
|
||||
|
||||
Fri Apr 26 11:38:09 1991 David J. MacKenzie (djm at mole.gnu.ai.mit.edu)
|
||||
|
||||
* stty.c: Define default values for control chars if necessary.
|
||||
Complain about invalid options if no other options follow.
|
||||
Use POSIX functions instead of ioctl, for manipulating termios.
|
||||
|
||||
* expr.c (main): Exit status was backwards.
|
||||
|
||||
Thu Dec 20 00:36:01 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* id.c: Reorganization and many changes to fix bugs and POSIX
|
||||
compliance problems.
|
||||
|
||||
Mon Dec 10 03:09:13 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* stty.c: Don't declare printf and some other functions that
|
||||
might have variable numbers of args in system header file decls.
|
||||
|
||||
Tue Nov 14 23:37:22 1990 Roland McGrath (roland at geech.ai.mit.edu)
|
||||
|
||||
* id.c (print_groups): Put spaces after commas.
|
||||
(print_group): New fn, to print a group id. Uses numeric fmt
|
||||
unless -n, in which case it uses group names.
|
||||
(print_groups): Call it. Find the rgid and egid, and print them as
|
||||
well as the supplementary groups. Make sure we print each group only
|
||||
once.
|
||||
|
||||
Sun Sep 16 01:49:14 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* id.c (main): Add -G option for POSIX.2 draft 10.
|
||||
Allow a username to be given.
|
||||
(print_groups): New function from code in main.
|
||||
(getugroups): New function.
|
||||
|
||||
Sun Aug 12 00:32:01 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* env.c (main): Instead of setting _POSIX_OPTION_ORDER,
|
||||
tell getopt to not permute, with `+'.
|
||||
|
||||
Sat Aug 11 01:32:53 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* expr.c: Use regex.c library instead of private regex routines.
|
||||
|
||||
* nice.c (main): Add -n option for POSIX.2a.
|
||||
(usage): New function.
|
||||
|
||||
Fri Aug 10 23:58:11 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* who.c: Add -m, -i, -w options for POSIX.2a.
|
||||
|
||||
Tue Aug 7 00:01:02 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* expr.c: Use exit directly instead of longjmp on error.
|
||||
Use argv[0] instead of hardcoded "expr" in messages.
|
||||
Make some functions void.
|
||||
|
||||
Sat Aug 4 21:19:25 1990 David J. MacKenzie (djm at pogo.ai.mit.edu)
|
||||
|
||||
* env.c: Change exit statuses for POSIX draft 10.
|
||||
|
||||
Wed Jul 4 04:32:51 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* tee.c: Use error instead of perror_with_name and
|
||||
out_of_memory.
|
||||
|
||||
Wed Jun 20 02:39:49 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* date.c: Change -DSETTOD to -DSTIME_MISSING, -DSIZE_T to
|
||||
-DSIZE_T_IN_TYPES, and -DSTDC_HDRS to -DSTDC_HEADERS.
|
||||
Declare some more functions. Replace fatal, memory_out, and
|
||||
nonfatal_perror with error.
|
||||
|
||||
Mon Jun 18 00:16:52 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* stty.c: Add some Unix compatibility modes.
|
||||
|
||||
Sat Jun 16 21:05:59 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* stty.c (display_changed, display_all): Print values of min
|
||||
and time.
|
||||
|
||||
Thu Jun 14 17:49:31 1990 David J. MacKenzie (djm at apple-gunkies)
|
||||
|
||||
* stty.c: Implement tab, backspace, etc. delay args.
|
||||
|
||||
Thu May 31 12:25:40 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* nohup.sh: Don't ignore SIGTERM.
|
||||
If ./nohup.out is unwritable, try $HOME/nohup.out.
|
||||
|
||||
Thu May 3 22:33:32 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* who.c: Use error instead of fatal and fatal_perror.
|
||||
(print_headings): Print headings in all caps, like SYSV does.
|
||||
(list_entries): New function for -q to make it like SYSV -q.
|
||||
(valid_entries): Function removed.
|
||||
|
||||
Mon Apr 2 01:27:23 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* id.c (main): Don't strip off leading path from program name.
|
||||
Revise a couple of error messages.
|
||||
|
||||
* whoami.c (main): Use geteuid, not getuid, for Unix compatibility.
|
||||
|
||||
Tue Mar 20 14:28:25 1990 David J. MacKenzie (djm at pogo.ai.mit.edu)
|
||||
|
||||
* tee.c (main): Pass list of files and its size as args to tee
|
||||
rather than as global vars. Exit with return value of tee
|
||||
instead of always 0.
|
||||
(tee): Use unbuffered I/O instead of stdio, for POSIX.
|
||||
Return an error status.
|
||||
(xwrite): New function.
|
||||
|
||||
Tue Mar 13 00:38:13 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* who.c (who_am_i): Print heading before checking to see
|
||||
whether there is an entry for the tty on stdin, for
|
||||
consistency with the who function.
|
||||
(main): Use argv[optind], not argv[1], as alternate file.
|
||||
|
||||
Fri Mar 9 15:49:04 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* who.c: Rename UTMP to UTMP_FILE for compatibility with SysV
|
||||
utmp.h. Include some additional header files.
|
||||
(main): Recognize some options from SysVr3 who. Call usage.
|
||||
Set new global var `program_name' from argv[0].
|
||||
(usage): New function.
|
||||
(who): If -q given, only print count of users logged on.
|
||||
(print_entry): New function to format an entry on the output;
|
||||
make format more like that of the Unix who programs.
|
||||
(print_heading): New function to print a line describing each
|
||||
output field.
|
||||
(who, who_am_i): Call print_entry and print_heading.
|
||||
(valid_entries): New function to return count of nonempty
|
||||
entries in utmp.
|
||||
(search_entries): Compare with utmp tty field instead of
|
||||
username field. Don't assume null termination in utmp field.
|
||||
(who_am_i): Print the entry for the tty on stdin rather than
|
||||
the first entry found for the uid. If hostname is not
|
||||
available, use a null one instead of "<unknown>".
|
||||
Don't hardcode max hostname length.
|
||||
(idle_string): New function to format idle time field.
|
||||
(fatal, fatal_perror): Use program_name instead of hardcoded "who"
|
||||
in error messages.
|
||||
|
||||
Tue Mar 6 00:59:03 1990 David J. MacKenzie (djm at albert.ai.mit.edu)
|
||||
|
||||
* printenv.c (main): Allow multiple variables to be specified.
|
||||
(barf): Function removed.
|
||||
|
||||
Sat Jan 20 18:41:48 1990 Jim Kingdon (kingdon at geech)
|
||||
|
||||
* expr.c (nextarg): Do not pass *args to strcmp if NULL.
|
||||
|
||||
Mon Dec 18 09:57:20 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
|
||||
|
||||
* printenv.c (main): Simplify error messages.
|
||||
|
||||
Sat Dec 16 15:15:50 1989 David J. MacKenzie (djm at hobbes.ai.mit.edu)
|
||||
|
||||
* expr.c: Indent to regularize spacing.
|
||||
(cmpv, arithf): Change '#define foo (args)' to '#define foo(args)'
|
||||
so they compile.
|
||||
(docolon): Remove unused vars.
|
||||
(multiply): Rename from times to avoid libc conflict.
|
||||
(error): Include program name in message.
|
||||
(xmalloc): Rename from Malloc.
|
||||
(re_compiled): Rename from re_comp to avoid libc conflict.
|
||||
|
||||
* basename.c: Fix some weird indentation.
|
||||
(main): Print a clearer usage message.
|
||||
Use a simpler method for removing suffix, if given.
|
||||
(fatal): Function no longer used; removed.
|
||||
|
||||
* sleep.c: (main): Rename `time' to `seconds'. Print usage
|
||||
message if given no args.
|
||||
Exit with status 0 instead of falling off end.
|
||||
(error): Print to stderr, not stdout.
|
||||
|
||||
* tee.c: (main): Use getopt_long instead of custom parser,
|
||||
and adjust usage message.
|
||||
Use list of filenames in argv rather than making a copy.
|
||||
(tee): New function created from the second half of main.
|
||||
Fix bug where it tried to fclose a loop index instead of a stream.
|
||||
(xmalloc): Ok to return 0 if 0 bytes requested.
|
||||
(xrealloc): Unused function removed.
|
||||
|
||||
* whoami.c: Canonicalize usage message and fix error message.
|
||||
|
||||
* who.c: Declare some functions.
|
||||
(fatal_perror): New function for printing errors after system
|
||||
calls.
|
||||
Global: Use it when appropriate.
|
||||
(xmalloc): Return char *, not int.
|
||||
(read_utmp): Ok if utmp file is empty.
|
||||
Include filename in error messages.
|
||||
(scan_entries): Adjust columns to line up better, particularly
|
||||
when there are users with 8 character long usernames logged in.
|
||||
|
||||
Sat Oct 28 13:20:43 1989 David J. MacKenzie (djm at spiff)
|
||||
|
||||
* uname.c: Added long options.
|
||||
global: changed the word `part' to the word `element'
|
||||
(more precise).
|
||||
(program_name, long_options): New variables.
|
||||
(main): Support long options.
|
||||
(usage): Add long options summary to message.
|
||||
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
left-margin: 8
|
||||
version-control: never
|
||||
End:
|
14
old/sh-utils/NEWS
Normal file
14
old/sh-utils/NEWS
Normal file
@ -0,0 +1,14 @@
|
||||
Major changes in release 1.8:
|
||||
* add echo command
|
||||
* fix some incorrect warnings in pathchk
|
||||
* look at the right utmp file on 386BSD
|
||||
* date doesn't dump core on some systems now
|
||||
|
||||
Major changes in release 1.7:
|
||||
* add su, who, true, false commands
|
||||
* add more tests to expr
|
||||
* fix printf program handling of \ escapes
|
||||
* printf can re-use format string for multiple groups of arguments
|
||||
* printf catches numeric conversion errors with an ANSI C library
|
||||
* stty nl and -nl were backwards
|
||||
* date can format an arbitrary date without setting it
|
78
src/basename.c
Normal file
78
src/basename.c
Normal file
@ -0,0 +1,78 @@
|
||||
/* basename -- strip directory and suffix from filenames
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Usage: basename name [suffix]
|
||||
NAME is a pathname; SUFFIX is a suffix to strip from it.
|
||||
|
||||
basename /usr/foo/lossage/functions.l
|
||||
=> functions.l
|
||||
basename /usr/foo/lossage/functions.l .l
|
||||
=> functions
|
||||
basename functions.lisp p
|
||||
=> functions.lis */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
char *basename ();
|
||||
void remove_suffix ();
|
||||
void strip_trailing_slashes ();
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s name [suffix]\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
strip_trailing_slashes (argv[1]);
|
||||
|
||||
name = basename (argv[1]);
|
||||
|
||||
if (argc == 3)
|
||||
remove_suffix (name, argv[2]);
|
||||
|
||||
puts (name);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* Remove SUFFIX from the end of NAME if it is there, unless NAME
|
||||
consists entirely of SUFFIX. */
|
||||
|
||||
void
|
||||
remove_suffix (name, suffix)
|
||||
register char *name, *suffix;
|
||||
{
|
||||
register char *np, *sp;
|
||||
|
||||
np = name + strlen (name);
|
||||
sp = suffix + strlen (suffix);
|
||||
|
||||
while (np > name && sp > suffix)
|
||||
if (*--np != *--sp)
|
||||
return;
|
||||
if (np > name)
|
||||
*np = '\0';
|
||||
}
|
190
src/date.c
Normal file
190
src/date.c
Normal file
@ -0,0 +1,190 @@
|
||||
/* date - print or set the system date and time
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Options:
|
||||
-d DATESTR Display the date DATESTR.
|
||||
-s DATESTR Set the date to DATESTR.
|
||||
-u Display or set the date in universal instead of local time.
|
||||
+FORMAT Specify custom date output format, described below.
|
||||
MMDDhhmm[[CC]YY][.ss] Set the date in the format described below.
|
||||
|
||||
If one non-option argument is given, it is used as the date to which
|
||||
to set the system clock, and must have the format:
|
||||
MM month (01..12)
|
||||
DD day in month (01..31)
|
||||
hh hour (00..23)
|
||||
mm minute (00..59)
|
||||
CC first 2 digits of year (optional, defaults to current) (00..99)
|
||||
YY last 2 digits of year (optional, defaults to current) (00..99)
|
||||
ss second (00..61)
|
||||
|
||||
If a non-option argument that starts with a `+' is specified, it
|
||||
is used to control the format in which the date is printed; it
|
||||
can contain any of the `%' substitutions allowed by the strftime
|
||||
function. A newline is always added at the end of the output.
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
/* This is portable and avoids bringing in all of the ctype stuff. */
|
||||
#define isdigit(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
#ifdef TM_IN_SYS_TIME
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifndef STDC_HEADERS
|
||||
time_t mktime ();
|
||||
size_t strftime ();
|
||||
time_t time ();
|
||||
#endif
|
||||
|
||||
int putenv ();
|
||||
int stime ();
|
||||
|
||||
char *xrealloc ();
|
||||
time_t get_date ();
|
||||
time_t posixtime ();
|
||||
void error ();
|
||||
void show_date ();
|
||||
void usage ();
|
||||
|
||||
/* putenv string to use Universal Coordinated Time.
|
||||
POSIX.2 says it should be "TZ=UCT0" or "TZ=GMT0". */
|
||||
#ifndef TZ_UCT
|
||||
#if defined(hpux) || defined(__hpux__) || defined(ultrix) || defined(__ultrix__) || defined(USG)
|
||||
#define TZ_UCT "TZ=GMT0"
|
||||
#else
|
||||
#define TZ_UCT "TZ="
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The name this program was run with, for error messages. */
|
||||
char *program_name;
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int optc;
|
||||
char *datestr = NULL;
|
||||
time_t when;
|
||||
int set_date = 0;
|
||||
int universal_time = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt (argc, argv, "d:s:u")) != EOF)
|
||||
switch (optc)
|
||||
{
|
||||
case 'd':
|
||||
datestr = optarg;
|
||||
break;
|
||||
case 's':
|
||||
datestr = optarg;
|
||||
set_date = 1;
|
||||
break;
|
||||
case 'u':
|
||||
universal_time = 1;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
|
||||
if (argc - optind > 1)
|
||||
usage ();
|
||||
|
||||
if (universal_time && putenv (TZ_UCT) != 0)
|
||||
error (1, 0, "virtual memory exhausted");
|
||||
|
||||
time (&when);
|
||||
|
||||
if (datestr)
|
||||
when = get_date (datestr, NULL);
|
||||
|
||||
if (argc - optind == 1 && argv[optind][0] != '+')
|
||||
{
|
||||
when = posixtime (argv[optind]);
|
||||
set_date = 1;
|
||||
}
|
||||
|
||||
if (when == -1)
|
||||
error (1, 0, "invalid date");
|
||||
|
||||
if (set_date && stime (&when) == -1)
|
||||
error (0, errno, "cannot set date");
|
||||
|
||||
if (argc - optind == 1 && argv[optind][0] == '+')
|
||||
show_date (argv[optind] + 1, when);
|
||||
else
|
||||
show_date ((char *) NULL, when);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* Display the date and/or time in WHEN according to the format specified
|
||||
in FORMAT, followed by a newline. If FORMAT is NULL, use the
|
||||
standard output format (ctime style but with a timezone inserted). */
|
||||
|
||||
void
|
||||
show_date (format, when)
|
||||
char *format;
|
||||
time_t when;
|
||||
{
|
||||
struct tm *tm;
|
||||
char *out = NULL;
|
||||
size_t out_length = 0;
|
||||
|
||||
tm = localtime (&when);
|
||||
|
||||
if (format == NULL)
|
||||
/* Print the date in the default format. Vanilla ANSI C strftime
|
||||
doesn't support %e, but POSIX requires it. If you don't use
|
||||
a GNU strftime, make sure yours supports %e. */
|
||||
format = "%a %b %e %H:%M:%S %Z %Y";
|
||||
else if (*format == '\0')
|
||||
{
|
||||
printf ("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
out_length += 200;
|
||||
out = (char *) xrealloc (out, out_length);
|
||||
}
|
||||
while (strftime (out, out_length, format, tm) == 0);
|
||||
|
||||
printf ("%s\n", out);
|
||||
free (out);
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-u] [-d datestr] [-s datestr] [+FORMAT] [MMDDhhmm[[CC]YY][.ss]]\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
57
src/dirname.c
Normal file
57
src/dirname.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* dirname -- strip filename suffix from pathname
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by David MacKenzie and Jim Meyering. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
void strip_trailing_slashes ();
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register char *path;
|
||||
register char *slash;
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s path\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
path = argv[1];
|
||||
strip_trailing_slashes (path);
|
||||
|
||||
slash = rindex (path, '/');
|
||||
if (slash == NULL)
|
||||
path = ".";
|
||||
else
|
||||
{
|
||||
/* Remove any trailing slashes and final element. */
|
||||
while (slash > path && *slash == '/')
|
||||
--slash;
|
||||
slash[1] = 0;
|
||||
}
|
||||
puts (path);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
179
src/echo.c
Normal file
179
src/echo.c
Normal file
@ -0,0 +1,179 @@
|
||||
/* echo.c, taken from Bash.
|
||||
Copyright (C) 1987, 1989, 1991, 1992 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 2, 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. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
/* echo [-neE] [arg ...]
|
||||
Output the ARGs. If -n is specified, the trailing newline is
|
||||
suppressed. If the -e option is given, interpretation of the
|
||||
following backslash-escaped characters is turned on:
|
||||
\a alert (bell)
|
||||
\b backspace
|
||||
\c suppress trailing newline
|
||||
\f form feed
|
||||
\n new line
|
||||
\r carriage return
|
||||
\t horizontal tab
|
||||
\v vertical tab
|
||||
\\ backslash
|
||||
\num the character whose ASCII code is NUM (octal).
|
||||
|
||||
You can explicitly turn off the interpretation of the above characters
|
||||
on System V systems with the -E option.
|
||||
*/
|
||||
|
||||
#define V9_ECHO
|
||||
|
||||
#if defined (V9_ECHO)
|
||||
# if defined (USG)
|
||||
# define VALID_ECHO_OPTIONS "neE"
|
||||
# else
|
||||
# define VALID_ECHO_OPTIONS "ne"
|
||||
# endif /* !USG */
|
||||
#else /* !V9_ECHO */
|
||||
# define VALID_ECHO_OPTIONS "n"
|
||||
#endif /* !V9_ECHO */
|
||||
|
||||
/* Print the words in LIST to standard output. If the first word is
|
||||
`-n', then don't print a trailing newline. We also support the
|
||||
echo syntax from Version 9 unix systems. */
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int display_return = 1, do_v9 = 0;
|
||||
|
||||
/* System V machines already have a /bin/sh with a v9 behaviour. We
|
||||
use the identical behaviour for these machines so that the
|
||||
existing system shell scripts won't barf. */
|
||||
#if defined (V9_ECHO) && defined (USG)
|
||||
do_v9 = 1;
|
||||
#endif
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
while (argc > 0 && *argv[0] == '-')
|
||||
{
|
||||
register char *temp;
|
||||
register int i;
|
||||
|
||||
/* If it appears that we are handling options, then make sure that
|
||||
all of the options specified are actually valid. Otherwise, the
|
||||
string should just be echoed. */
|
||||
temp = argv[0] + 1;
|
||||
|
||||
for (i = 0; temp[i]; i++)
|
||||
{
|
||||
if (rindex (VALID_ECHO_OPTIONS, temp[i]) == 0)
|
||||
goto just_echo;
|
||||
}
|
||||
|
||||
if (!*temp)
|
||||
goto just_echo;
|
||||
|
||||
/* All of the options in TEMP are valid options to ECHO.
|
||||
Handle them. */
|
||||
while (*temp)
|
||||
{
|
||||
if (*temp == 'n')
|
||||
display_return = 0;
|
||||
#if defined (V9_ECHO)
|
||||
else if (*temp == 'e')
|
||||
do_v9 = 1;
|
||||
#if defined (USG)
|
||||
else if (*temp == 'E')
|
||||
do_v9 = 0;
|
||||
#endif /* USG */
|
||||
#endif /* V9_ECHO */
|
||||
else
|
||||
goto just_echo;
|
||||
|
||||
temp++;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
just_echo:
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
#if defined (V9_ECHO)
|
||||
if (do_v9)
|
||||
{
|
||||
while (argc > 0)
|
||||
{
|
||||
register char *s = argv[0];
|
||||
register int c;
|
||||
|
||||
while (c = *s++)
|
||||
{
|
||||
if (c == '\\' && *s)
|
||||
{
|
||||
switch (c = *s++)
|
||||
{
|
||||
case 'a': c = '\007'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 'c': display_return = 0; continue;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'v': c = (int) 0x0B; break;
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
c -= '0';
|
||||
if (*s >= '0' && *s <= '7')
|
||||
c = c * 8 + (*s++ - '0');
|
||||
if (*s >= '0' && *s <= '7')
|
||||
c = c * 8 + (*s++ - '0');
|
||||
break;
|
||||
case '\\': break;
|
||||
default: putchar ('\\'); break;
|
||||
}
|
||||
}
|
||||
putchar(c);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
if (argc > 0)
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* V9_ECHO */
|
||||
{
|
||||
while (argc > 0)
|
||||
{
|
||||
fputs (argv[0], stdout);
|
||||
argc--;
|
||||
argv++;
|
||||
if (argc > 0)
|
||||
putchar (' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (display_return)
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
168
src/env.c
Normal file
168
src/env.c
Normal file
@ -0,0 +1,168 @@
|
||||
/* env - run a program in a modified environment
|
||||
Copyright (C) 1986, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Richard Mlynarik and David MacKenzie */
|
||||
|
||||
/* Options:
|
||||
-
|
||||
-i
|
||||
--ignore-environment
|
||||
Construct a new environment from scratch; normally the
|
||||
environment is inherited from the parent process, except as
|
||||
modified by other options.
|
||||
|
||||
-u variable
|
||||
--unset=variable
|
||||
Unset variable VARIABLE (remove it from the environment).
|
||||
If VARIABLE was not set, does nothing.
|
||||
|
||||
variable=value (an arg containing a "=" character)
|
||||
Set the environment variable VARIABLE to value VALUE. VALUE
|
||||
may be of zero length ("variable="). Setting a variable to a
|
||||
zero-length value is different from unsetting it.
|
||||
|
||||
--
|
||||
Indicate that the following argument is the program
|
||||
to invoke. This is necessary when the program's name
|
||||
begins with "-" or contains a "=".
|
||||
|
||||
The first remaining argument specifies a program to invoke;
|
||||
it is searched for according to the specification of the PATH
|
||||
environment variable. Any arguments following that are
|
||||
passed as arguments to that program.
|
||||
|
||||
If no command name is specified following the environment
|
||||
specifications, the resulting environment is printed.
|
||||
This is like specifying a command name of "printenv".
|
||||
|
||||
Examples:
|
||||
|
||||
If the environment passed to "env" is
|
||||
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
|
||||
|
||||
env - foo
|
||||
runs "foo" in a null environment.
|
||||
|
||||
env foo
|
||||
runs "foo" in the environment
|
||||
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
|
||||
|
||||
env DISPLAY=gnu:0 nemacs
|
||||
runs "nemacs" in the envionment
|
||||
{ LOGNAME=rms EDITOR=emacs PATH=.:/gnubin:/hacks DISPLAY=gnu:0 }
|
||||
|
||||
env - LOGNAME=foo /hacks/hack bar baz
|
||||
runs the "hack" program on arguments "bar" and "baz" in an
|
||||
environment in which the only variable is "LOGNAME". Note that
|
||||
the "-" option clears out the PATH variable, so one should be
|
||||
careful to specify in which directory to find the program to
|
||||
call.
|
||||
|
||||
env -u EDITOR LOGNAME=foo PATH=/energy -- e=mc2 bar baz
|
||||
runs the program "/energy/e=mc2" with environment
|
||||
{ LOGNAME=foo PATH=/energy }
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
int putenv ();
|
||||
void error ();
|
||||
void usage ();
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* The name by which this program was run. */
|
||||
char *program_name;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"ignore-environment", 0, NULL, 'i'},
|
||||
{"unset", 1, NULL, 'u'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv, envp)
|
||||
register int argc;
|
||||
register char **argv;
|
||||
char **envp;
|
||||
{
|
||||
char *dummy_environ[1];
|
||||
int optc;
|
||||
int ignore_environment = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "+iu:", longopts, (int *) 0)) != EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'i':
|
||||
ignore_environment = 1;
|
||||
break;
|
||||
case 'u':
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "-"))
|
||||
ignore_environment = 1;
|
||||
|
||||
environ = dummy_environ;
|
||||
environ[0] = NULL;
|
||||
|
||||
if (!ignore_environment)
|
||||
for (; *envp; envp++)
|
||||
putenv (*envp);
|
||||
|
||||
optind = 0; /* Force GNU getopt to re-initialize. */
|
||||
while ((optc = getopt_long (argc, argv, "+iu:", longopts, (int *) 0)) != EOF)
|
||||
if (optc == 'u')
|
||||
putenv (optarg); /* Requires GNU putenv. */
|
||||
|
||||
if (optind != argc && !strcmp (argv[optind], "-"))
|
||||
++optind;
|
||||
|
||||
while (optind < argc && index (argv[optind], '='))
|
||||
putenv (argv[optind++]);
|
||||
|
||||
/* If no program is specified, print the environment and exit. */
|
||||
if (optind == argc)
|
||||
{
|
||||
while (*environ)
|
||||
puts (*environ++);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
execvp (argv[optind], &argv[optind]);
|
||||
error (errno == ENOENT ? 127 : 126, errno, "%s", argv[optind]);
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-] [-i] [-u name] [--ignore-environment] [--unset=name]\n\
|
||||
[name=value]... [command [args...]]\n",
|
||||
program_name);
|
||||
exit (2);
|
||||
}
|
672
src/expr.c
Normal file
672
src/expr.c
Normal file
@ -0,0 +1,672 @@
|
||||
/* expr -- evaluate expressions.
|
||||
Copyright (C) 1986, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Author: Mike Parker.
|
||||
|
||||
This program evaluates expressions. Each token (operator, operand,
|
||||
parenthesis) of the expression must be a seperate argument. The
|
||||
parser used is a reasonably general one, though any incarnation of
|
||||
it is language-specific. It is especially nice for expressions.
|
||||
|
||||
No parse tree is needed; a new node is evaluated immediately.
|
||||
One function can handle multiple operators all of equal precedence,
|
||||
provided they all associate ((x op x) op x).
|
||||
|
||||
Define EVAL_TRACE to print an evaluation trace. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
#include "system.h"
|
||||
|
||||
#if !__STDC__
|
||||
#define const
|
||||
#endif
|
||||
|
||||
#define NEW(type) ((type *) xmalloc (sizeof (type)))
|
||||
#define OLD(x) free ((char *) x)
|
||||
|
||||
/* The kinds of value we can have. */
|
||||
enum valtype
|
||||
{
|
||||
integer,
|
||||
string
|
||||
};
|
||||
typedef enum valtype TYPE;
|
||||
|
||||
/* A value is.... */
|
||||
struct valinfo
|
||||
{
|
||||
TYPE type; /* Which kind. */
|
||||
union
|
||||
{ /* The value itself. */
|
||||
int i;
|
||||
char *s;
|
||||
} u;
|
||||
};
|
||||
typedef struct valinfo VALUE;
|
||||
|
||||
/* The arguments given to the program, minus the program name. */
|
||||
char **args;
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
VALUE *docolon ();
|
||||
VALUE *eval ();
|
||||
VALUE *int_value ();
|
||||
VALUE *str_value ();
|
||||
char *xstrdup ();
|
||||
char *strstr ();
|
||||
char *xmalloc ();
|
||||
int isstring ();
|
||||
int nextarg ();
|
||||
int nomoreargs ();
|
||||
int null ();
|
||||
int toarith ();
|
||||
void error ();
|
||||
void freev ();
|
||||
void printv ();
|
||||
void tostring ();
|
||||
void trace ();
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
VALUE *v;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s expression...\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
args = argv + 1;
|
||||
|
||||
v = eval ();
|
||||
if (!nomoreargs ())
|
||||
error (2, 0, "syntax error");
|
||||
printv (v);
|
||||
|
||||
exit (null (v));
|
||||
}
|
||||
|
||||
/* Return a VALUE for I. */
|
||||
|
||||
VALUE *
|
||||
int_value (i)
|
||||
int i;
|
||||
{
|
||||
VALUE *v;
|
||||
|
||||
v = NEW (VALUE);
|
||||
v->type = integer;
|
||||
v->u.i = i;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Return a VALUE for S. */
|
||||
|
||||
VALUE *
|
||||
str_value (s)
|
||||
char *s;
|
||||
{
|
||||
VALUE *v;
|
||||
|
||||
v = NEW (VALUE);
|
||||
v->type = string;
|
||||
v->u.s = xstrdup (s);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Free VALUE V, including structure components. */
|
||||
|
||||
void
|
||||
freev (v)
|
||||
VALUE *v;
|
||||
{
|
||||
if (v->type == string)
|
||||
free (v->u.s);
|
||||
OLD (v);
|
||||
}
|
||||
|
||||
/* Print VALUE V. */
|
||||
|
||||
void
|
||||
printv (v)
|
||||
VALUE *v;
|
||||
{
|
||||
switch (v->type)
|
||||
{
|
||||
case integer:
|
||||
printf ("%d\n", v->u.i);
|
||||
break;
|
||||
case string:
|
||||
printf ("%s\n", v->u.s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if V is a null-string or zero-number. */
|
||||
|
||||
int
|
||||
null (v)
|
||||
VALUE *v;
|
||||
{
|
||||
switch (v->type)
|
||||
{
|
||||
case integer:
|
||||
return v->u.i == 0;
|
||||
case string:
|
||||
return v->u.s[0] == '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if V is a string value. */
|
||||
|
||||
int
|
||||
isstring (v)
|
||||
VALUE *v;
|
||||
{
|
||||
return v->type == string;
|
||||
}
|
||||
|
||||
/* Coerce V to a string value (can't fail). */
|
||||
|
||||
void
|
||||
tostring (v)
|
||||
VALUE *v;
|
||||
{
|
||||
char *temp;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case integer:
|
||||
temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
|
||||
sprintf (temp, "%d", v->u.i);
|
||||
v->u.s = temp;
|
||||
v->type = string;
|
||||
break;
|
||||
case string:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
|
||||
|
||||
int
|
||||
toarith (v)
|
||||
VALUE *v;
|
||||
{
|
||||
int i;
|
||||
int neg;
|
||||
char *cp;
|
||||
|
||||
switch (v->type)
|
||||
{
|
||||
case integer:
|
||||
return 1;
|
||||
case string:
|
||||
i = 0;
|
||||
cp = v->u.s;
|
||||
neg = (*cp == '-');
|
||||
if (neg)
|
||||
cp++;
|
||||
for (; *cp; cp++)
|
||||
{
|
||||
if (isdigit (*cp))
|
||||
i = i * 10 + *cp - '0';
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
free (v->u.s);
|
||||
v->u.i = i * (neg ? -1 : 1);
|
||||
v->type = integer;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if the next token matches STR exactly.
|
||||
STR must not be NULL. */
|
||||
|
||||
int
|
||||
nextarg (str)
|
||||
char *str;
|
||||
{
|
||||
if (*args == NULL)
|
||||
return 0;
|
||||
return strcmp (*args, str) == 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if there no more tokens. */
|
||||
|
||||
int
|
||||
nomoreargs ()
|
||||
{
|
||||
return *args == 0;
|
||||
}
|
||||
|
||||
/* The comparison operator handling functions. */
|
||||
|
||||
#define cmpf(name, rel) \
|
||||
int name (l, r) VALUE *l; VALUE *r; \
|
||||
{ \
|
||||
if (isstring (l) || isstring (r)) \
|
||||
{ \
|
||||
tostring (l); \
|
||||
tostring (r); \
|
||||
return strcmp (l->u.s, r->u.s) rel 0; \
|
||||
} \
|
||||
else \
|
||||
return l->u.i rel r->u.i; \
|
||||
}
|
||||
|
||||
cmpf (less_than, <)
|
||||
cmpf (less_equal, <=)
|
||||
cmpf (equal, ==)
|
||||
cmpf (not_equal, !=)
|
||||
cmpf (greater_equal, >=)
|
||||
cmpf (greater_than, >)
|
||||
|
||||
#undef cmpf
|
||||
|
||||
/* The arithmetic operator handling functions. */
|
||||
|
||||
#define arithf(name, op) \
|
||||
int name (l, r) VALUE *l; VALUE *r; \
|
||||
{ \
|
||||
if (!toarith (l) || !toarith (r)) \
|
||||
error (2, 0, "non-numeric argument"); \
|
||||
return l->u.i op r->u.i; \
|
||||
}
|
||||
|
||||
arithf (plus, +)
|
||||
arithf (minus, -)
|
||||
arithf (multiply, *)
|
||||
arithf (divide, /)
|
||||
arithf (mod, %)
|
||||
|
||||
#undef arithf
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
/* Print evaluation trace and args remaining. */
|
||||
|
||||
void
|
||||
trace (fxn)
|
||||
char *fxn;
|
||||
{
|
||||
char **a;
|
||||
|
||||
printf ("%s:", fxn);
|
||||
for (a = args; *a; a++)
|
||||
printf (" %s", *a);
|
||||
putchar ('\n');
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do the : operator.
|
||||
SV is the VALUE for the lhs (the string),
|
||||
PV is the VALUE for the rhs (the pattern). */
|
||||
|
||||
VALUE *
|
||||
docolon (sv, pv)
|
||||
VALUE *sv;
|
||||
VALUE *pv;
|
||||
{
|
||||
VALUE *v;
|
||||
const char *errmsg;
|
||||
struct re_pattern_buffer re_buffer;
|
||||
struct re_registers re_regs;
|
||||
int len;
|
||||
|
||||
tostring (sv);
|
||||
tostring (pv);
|
||||
|
||||
len = strlen (pv->u.s);
|
||||
re_buffer.allocated = 2 * len;
|
||||
re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
|
||||
re_buffer.translate = 0;
|
||||
errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
|
||||
if (errmsg)
|
||||
error (2, 0, "%s", errmsg);
|
||||
|
||||
len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
|
||||
if (len >= 0)
|
||||
{
|
||||
/* Were \(...\) used? */
|
||||
if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
|
||||
{
|
||||
sv->u.s[re_regs.end[1]] = '\0';
|
||||
v = str_value (sv->u.s + re_regs.start[1]);
|
||||
}
|
||||
else
|
||||
v = int_value (len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Match failed -- return the right kind of null. */
|
||||
if (strstr (pv->u.s, "\\("))
|
||||
v = str_value ("");
|
||||
else
|
||||
v = int_value (0);
|
||||
}
|
||||
free (re_buffer.buffer);
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Handle bare operands and ( expr ) syntax. */
|
||||
|
||||
VALUE *
|
||||
eval7 ()
|
||||
{
|
||||
VALUE *v;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval7");
|
||||
#endif
|
||||
if (nomoreargs ())
|
||||
error (2, 0, "syntax error");
|
||||
else if (nextarg ("("))
|
||||
{
|
||||
args++;
|
||||
v = eval ();
|
||||
if (!nextarg (")"))
|
||||
error (2, 0, "syntax error");
|
||||
args++;
|
||||
return v;
|
||||
}
|
||||
else if (nextarg (")"))
|
||||
error (2, 0, "syntax error");
|
||||
else
|
||||
return str_value (*args++);
|
||||
}
|
||||
|
||||
/* Handle match, substr, index, and length keywords. */
|
||||
|
||||
VALUE *
|
||||
eval6 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
VALUE *v;
|
||||
VALUE *i1;
|
||||
VALUE *i2;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval6");
|
||||
#endif
|
||||
if (nextarg ("length"))
|
||||
{
|
||||
args++;
|
||||
r = eval6 ();
|
||||
tostring (r);
|
||||
v = int_value (strlen (r->u.s));
|
||||
freev (r);
|
||||
return v;
|
||||
}
|
||||
else if (nextarg ("match"))
|
||||
{
|
||||
args++;
|
||||
l = eval6 ();
|
||||
r = eval6 ();
|
||||
v = docolon (l, r);
|
||||
freev (l);
|
||||
freev (r);
|
||||
return v;
|
||||
}
|
||||
else if (nextarg ("index"))
|
||||
{
|
||||
args++;
|
||||
l = eval6 ();
|
||||
r = eval6 ();
|
||||
tostring (l);
|
||||
tostring (r);
|
||||
v = int_value (strcspn (l->u.s, r->u.s) + 1);
|
||||
if (v->u.i == strlen (l->u.s) + 1)
|
||||
v->u.i = 0;
|
||||
freev (l);
|
||||
freev (r);
|
||||
return v;
|
||||
}
|
||||
else if (nextarg ("substr"))
|
||||
{
|
||||
args++;
|
||||
l = eval6 ();
|
||||
i1 = eval6 ();
|
||||
i2 = eval6 ();
|
||||
tostring (l);
|
||||
if (!toarith (i1) || !toarith (i2)
|
||||
|| i1->u.i > strlen (l->u.s)
|
||||
|| i1->u.i <= 0 || i2->u.i <= 0)
|
||||
v = str_value ("");
|
||||
else
|
||||
{
|
||||
v = NEW (VALUE);
|
||||
v->type = string;
|
||||
v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
|
||||
l->u.s + i1->u.i - 1, i2->u.i);
|
||||
}
|
||||
freev (l);
|
||||
freev (i1);
|
||||
freev (i2);
|
||||
return v;
|
||||
}
|
||||
else
|
||||
return eval7 ();
|
||||
}
|
||||
|
||||
/* Handle : operator (pattern matching).
|
||||
Calls docolon to do the real work. */
|
||||
|
||||
VALUE *
|
||||
eval5 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
VALUE *v;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval5");
|
||||
#endif
|
||||
l = eval6 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg (":"))
|
||||
{
|
||||
args++;
|
||||
r = eval6 ();
|
||||
v = docolon (l, r);
|
||||
freev (l);
|
||||
freev (r);
|
||||
l = v;
|
||||
}
|
||||
else
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle *, /, % operators. */
|
||||
|
||||
VALUE *
|
||||
eval4 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
int (*fxn) ();
|
||||
int val;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval4");
|
||||
#endif
|
||||
l = eval5 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg ("*"))
|
||||
fxn = multiply;
|
||||
else if (nextarg ("/"))
|
||||
fxn = divide;
|
||||
else if (nextarg ("%"))
|
||||
fxn = mod;
|
||||
else
|
||||
return l;
|
||||
args++;
|
||||
r = eval5 ();
|
||||
val = (*fxn) (l, r);
|
||||
freev (l);
|
||||
freev (r);
|
||||
l = int_value (val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle +, - operators. */
|
||||
|
||||
VALUE *
|
||||
eval3 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
int (*fxn) ();
|
||||
int val;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval3");
|
||||
#endif
|
||||
l = eval4 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg ("+"))
|
||||
fxn = plus;
|
||||
else if (nextarg ("-"))
|
||||
fxn = minus;
|
||||
else
|
||||
return l;
|
||||
args++;
|
||||
r = eval4 ();
|
||||
val = (*fxn) (l, r);
|
||||
freev (l);
|
||||
freev (r);
|
||||
l = int_value (val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle comparisons. */
|
||||
|
||||
VALUE *
|
||||
eval2 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
int (*fxn) ();
|
||||
int val;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval2");
|
||||
#endif
|
||||
l = eval3 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg ("<"))
|
||||
fxn = less_than;
|
||||
else if (nextarg ("<="))
|
||||
fxn = less_equal;
|
||||
else if (nextarg ("=") || nextarg ("=="))
|
||||
fxn = equal;
|
||||
else if (nextarg ("!="))
|
||||
fxn = not_equal;
|
||||
else if (nextarg (">="))
|
||||
fxn = greater_equal;
|
||||
else if (nextarg (">"))
|
||||
fxn = greater_than;
|
||||
else
|
||||
return l;
|
||||
args++;
|
||||
r = eval3 ();
|
||||
toarith (l);
|
||||
toarith (r);
|
||||
val = (*fxn) (l, r);
|
||||
freev (l);
|
||||
freev (r);
|
||||
l = int_value (val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle &. */
|
||||
|
||||
VALUE *
|
||||
eval1 ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval1");
|
||||
#endif
|
||||
l = eval2 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg ("&"))
|
||||
{
|
||||
args++;
|
||||
r = eval2 ();
|
||||
if (null (l) || null (r))
|
||||
{
|
||||
freev (l);
|
||||
freev (r);
|
||||
l = int_value (0);
|
||||
}
|
||||
else
|
||||
freev (r);
|
||||
}
|
||||
else
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle |. */
|
||||
|
||||
VALUE *
|
||||
eval ()
|
||||
{
|
||||
VALUE *l;
|
||||
VALUE *r;
|
||||
|
||||
#ifdef EVAL_TRACE
|
||||
trace ("eval");
|
||||
#endif
|
||||
l = eval1 ();
|
||||
while (1)
|
||||
{
|
||||
if (nextarg ("|"))
|
||||
{
|
||||
args++;
|
||||
r = eval1 ();
|
||||
if (null (l))
|
||||
{
|
||||
freev (l);
|
||||
l = r;
|
||||
}
|
||||
else
|
||||
freev (r);
|
||||
}
|
||||
else
|
||||
return l;
|
||||
}
|
||||
}
|
31
src/groups.sh
Executable file
31
src/groups.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
# groups -- print the groups a user is in
|
||||
# Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
|
||||
|
||||
# Make sure we get GNU id, if possible; also allow
|
||||
# it to be somewhere else in PATH if not installed yet.
|
||||
PATH=@bindir@:$PATH
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
id -Gn
|
||||
else
|
||||
for name in "$@"; do
|
||||
echo $name : `id -Gn $name`
|
||||
done
|
||||
fi
|
346
src/id.c
Normal file
346
src/id.c
Normal file
@ -0,0 +1,346 @@
|
||||
/* id -- print real and effective UIDs and GIDs
|
||||
Copyright (C) 1989, 1991 Free Software Foundation.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by Arnold Robbins, arnold@audiofax.com.
|
||||
Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include "system.h"
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#include <limits.h>
|
||||
#if !defined(NGROUPS_MAX) || NGROUPS_MAX < 1
|
||||
#define NGROUPS_MAX sysconf (_SC_NGROUPS_MAX)
|
||||
#endif /* !NGROUPS_MAX */
|
||||
|
||||
/* Even though SunOS 4, Ultrix 4, and 386BSD are mostly POSIX.1 compliant,
|
||||
their getgroups system call (except in the `System V' environment, which
|
||||
is troublesome in other ways) fills in an array of int, not gid_t
|
||||
(which is `short' on those systems). Kludge, kludge. */
|
||||
|
||||
#if !defined(sun) && !defined(ultrix) && !defined(__386BSD__)
|
||||
#define GETGROUPS_T gid_t
|
||||
#else /* sun or ultrix or 386BSD */
|
||||
#define GETGROUPS_T int
|
||||
#endif /* sun or ultrix or 386BSD */
|
||||
#else /* not _POSIX_VERSION */
|
||||
struct passwd *getpwuid ();
|
||||
struct group *getgrgid ();
|
||||
uid_t getuid ();
|
||||
gid_t getgid ();
|
||||
uid_t geteuid ();
|
||||
gid_t getegid ();
|
||||
#include <sys/param.h>
|
||||
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
|
||||
#define NGROUPS_MAX NGROUPS
|
||||
#endif /* not NGROUPS_MAX and NGROUPS */
|
||||
#define GETGROUPS_T int
|
||||
#endif /* not _POSIX_VERSION */
|
||||
|
||||
char *xmalloc ();
|
||||
int getugroups ();
|
||||
void error ();
|
||||
void print_user ();
|
||||
void print_group ();
|
||||
void print_group_list ();
|
||||
void print_full_info ();
|
||||
void usage ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, output only the group ID(s). -g */
|
||||
int just_group = 0;
|
||||
|
||||
/* If nonzero, output user/group name instead of ID number. -n */
|
||||
int use_name = 0;
|
||||
|
||||
/* If nonzero, output real UID/GID instead of default effective UID/GID. -r */
|
||||
int use_real = 0;
|
||||
|
||||
/* If nonzero, output only the user ID(s). -u */
|
||||
int just_user = 0;
|
||||
|
||||
/* If nonzero, output only the supplementary groups. -G */
|
||||
int just_group_list = 0;
|
||||
|
||||
/* The real and effective IDs of the user to print. */
|
||||
uid_t ruid, euid;
|
||||
gid_t rgid, egid;
|
||||
|
||||
/* The number of errors encountered so far. */
|
||||
int problems = 0;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"group", 0, NULL, 'g'},
|
||||
{"name", 0, NULL, 'n'},
|
||||
{"real", 0, NULL, 'r'},
|
||||
{"user", 0, NULL, 'u'},
|
||||
{"groups", 0, NULL, 'G'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int optc;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "gnruG", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'g':
|
||||
just_group = 1;
|
||||
break;
|
||||
case 'n':
|
||||
use_name = 1;
|
||||
break;
|
||||
case 'r':
|
||||
use_real = 1;
|
||||
break;
|
||||
case 'u':
|
||||
just_user = 1;
|
||||
break;
|
||||
case 'G':
|
||||
just_group_list = 1;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (just_user + just_group + just_group_list > 1)
|
||||
error (1, 0, "cannot print only user and only group");
|
||||
|
||||
if (just_user + just_group + just_group_list == 0 && (use_real || use_name))
|
||||
error (1, 0, "cannot print only names or real IDs in default format");
|
||||
|
||||
if (argc - optind > 1)
|
||||
usage ();
|
||||
|
||||
if (argc - optind == 1)
|
||||
{
|
||||
struct passwd *pwd = getpwnam (argv[optind]);
|
||||
if (pwd == NULL)
|
||||
error (1, 0, "%s: No such user", argv[optind]);
|
||||
ruid = euid = pwd->pw_uid;
|
||||
rgid = egid = pwd->pw_gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
euid = geteuid ();
|
||||
ruid = getuid ();
|
||||
egid = getegid ();
|
||||
rgid = getgid ();
|
||||
}
|
||||
|
||||
if (just_user)
|
||||
print_user (use_real ? ruid : euid);
|
||||
else if (just_group)
|
||||
print_group (use_real ? rgid : egid);
|
||||
else if (just_group_list)
|
||||
print_group_list (argv[optind]);
|
||||
else
|
||||
print_full_info (argv[optind]);
|
||||
putchar ('\n');
|
||||
|
||||
exit (problems != 0);
|
||||
}
|
||||
|
||||
/* Print the name or value of user ID UID. */
|
||||
|
||||
void
|
||||
print_user (uid)
|
||||
int uid;
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
|
||||
if (use_name)
|
||||
{
|
||||
pwd = getpwuid (uid);
|
||||
if (pwd == NULL)
|
||||
problems++;
|
||||
}
|
||||
|
||||
if (pwd == NULL)
|
||||
printf ("%u", (unsigned) uid);
|
||||
else
|
||||
printf ("%s", pwd->pw_name);
|
||||
}
|
||||
|
||||
/* Print the name or value of group ID GID. */
|
||||
|
||||
void
|
||||
print_group (gid)
|
||||
int gid;
|
||||
{
|
||||
struct group *grp = NULL;
|
||||
|
||||
if (use_name)
|
||||
{
|
||||
grp = getgrgid (gid);
|
||||
if (grp == NULL)
|
||||
problems++;
|
||||
}
|
||||
|
||||
if (grp == NULL)
|
||||
printf ("%u", (unsigned) gid);
|
||||
else
|
||||
printf ("%s", grp->gr_name);
|
||||
}
|
||||
|
||||
/* Print all of the distinct groups the user is in . */
|
||||
|
||||
void
|
||||
print_group_list (username)
|
||||
char *username;
|
||||
{
|
||||
print_group (rgid);
|
||||
if (egid != rgid)
|
||||
{
|
||||
putchar (' ');
|
||||
print_group (egid);
|
||||
}
|
||||
|
||||
#ifdef NGROUPS_MAX
|
||||
{
|
||||
int ngroups;
|
||||
GETGROUPS_T *groups;
|
||||
register int i;
|
||||
|
||||
groups = (GETGROUPS_T *) xmalloc (NGROUPS_MAX * sizeof (GETGROUPS_T));
|
||||
if (username == 0)
|
||||
ngroups = getgroups (NGROUPS_MAX, groups);
|
||||
else
|
||||
ngroups = getugroups (NGROUPS_MAX, groups, username);
|
||||
if (ngroups < 0)
|
||||
{
|
||||
error (0, errno, "cannot get supplemental group list");
|
||||
problems++;
|
||||
free (groups);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ngroups; i++)
|
||||
if (groups[i] != rgid && groups[i] != egid)
|
||||
{
|
||||
putchar (' ');
|
||||
print_group (groups[i]);
|
||||
}
|
||||
free (groups);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Print all of the info about the user's user and group IDs. */
|
||||
|
||||
void
|
||||
print_full_info (username)
|
||||
char *username;
|
||||
{
|
||||
struct passwd *pwd;
|
||||
struct group *grp;
|
||||
|
||||
printf ("uid=%u", (unsigned) ruid);
|
||||
pwd = getpwuid (ruid);
|
||||
if (pwd == NULL)
|
||||
problems++;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
|
||||
printf (" gid=%u", (unsigned) rgid);
|
||||
grp = getgrgid (rgid);
|
||||
if (grp == NULL)
|
||||
problems++;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
|
||||
if (euid != ruid)
|
||||
{
|
||||
printf (" euid=%u", (unsigned) euid);
|
||||
pwd = getpwuid (euid);
|
||||
if (pwd == NULL)
|
||||
problems++;
|
||||
else
|
||||
printf ("(%s)", pwd->pw_name);
|
||||
}
|
||||
|
||||
if (egid != rgid)
|
||||
{
|
||||
printf (" egid=%u", (unsigned) egid);
|
||||
grp = getgrgid (egid);
|
||||
if (grp == NULL)
|
||||
problems++;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
|
||||
#ifdef NGROUPS_MAX
|
||||
{
|
||||
int ngroups;
|
||||
GETGROUPS_T *groups;
|
||||
register int i;
|
||||
|
||||
groups = (GETGROUPS_T *) xmalloc (NGROUPS_MAX * sizeof (GETGROUPS_T));
|
||||
if (username == 0)
|
||||
ngroups = getgroups (NGROUPS_MAX, groups);
|
||||
else
|
||||
ngroups = getugroups (NGROUPS_MAX, groups, username);
|
||||
if (ngroups < 0)
|
||||
{
|
||||
error (0, errno, "cannot get supplemental group list");
|
||||
problems++;
|
||||
free (groups);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngroups > 0)
|
||||
fputs (" groups=", stdout);
|
||||
for (i = 0; i < ngroups; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
putchar (',');
|
||||
printf ("%u", (unsigned) groups[i]);
|
||||
grp = getgrgid (groups[i]);
|
||||
if (grp == NULL)
|
||||
problems++;
|
||||
else
|
||||
printf ("(%s)", grp->gr_name);
|
||||
}
|
||||
free (groups);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-gnruG] [--group] [--name] [--real] [--user] [--groups] [username]\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
43
src/logname.c
Normal file
43
src/logname.c
Normal file
@ -0,0 +1,43 @@
|
||||
/* logname -- print user's login name
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register char *cp;
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
cp = getlogin ();
|
||||
if (cp)
|
||||
{
|
||||
puts (cp);
|
||||
exit (0);
|
||||
}
|
||||
fprintf (stderr,"%s: no login name\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
150
src/nice.c
Normal file
150
src/nice.c
Normal file
@ -0,0 +1,150 @@
|
||||
/* nice -- run a program with modified scheduling priority
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* David MacKenzie <djm@ai.mit.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef NICE_PRIORITY
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include "system.h"
|
||||
|
||||
int isinteger ();
|
||||
void error ();
|
||||
void usage ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"adjustment", 1, NULL, 'n'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int current_priority;
|
||||
int adjustment = 0;
|
||||
int minusflag = 0;
|
||||
int adjustment_given = 0;
|
||||
int optc;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "+0123456789-n:", longopts,
|
||||
(int *) 0)) != EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case '?':
|
||||
usage ();
|
||||
|
||||
case 'n':
|
||||
if (!isinteger (optarg))
|
||||
error (1, 0, "invalid priority `%s'", optarg);
|
||||
adjustment = atoi (optarg);
|
||||
adjustment_given = 1;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
minusflag = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
adjustment = adjustment * 10 + optc - '0';
|
||||
adjustment_given = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (minusflag)
|
||||
adjustment = -adjustment;
|
||||
if (!adjustment_given)
|
||||
adjustment = 10;
|
||||
|
||||
if (optind == argc)
|
||||
{
|
||||
if (adjustment_given)
|
||||
usage ();
|
||||
/* No command given; print the priority. */
|
||||
errno = 0;
|
||||
#ifndef NICE_PRIORITY
|
||||
current_priority = getpriority (PRIO_PROCESS, 0);
|
||||
#else
|
||||
current_priority = nice (0);
|
||||
#endif
|
||||
if (current_priority == -1 && errno != 0)
|
||||
error (1, errno, "cannot get priority");
|
||||
printf ("%d\n", current_priority);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#ifndef NICE_PRIORITY
|
||||
current_priority = getpriority (PRIO_PROCESS, 0);
|
||||
#else
|
||||
current_priority = nice (0);
|
||||
#endif
|
||||
if (current_priority == -1 && errno != 0)
|
||||
error (1, errno, "cannot get priority");
|
||||
|
||||
#ifndef NICE_PRIORITY
|
||||
if (setpriority (PRIO_PROCESS, 0, current_priority + adjustment))
|
||||
#else
|
||||
if (nice (adjustment) == -1)
|
||||
#endif
|
||||
error (1, errno, "cannot set priority");
|
||||
|
||||
execvp (argv[optind], &argv[optind]);
|
||||
error (errno == ENOENT ? 127 : 126, errno, "%s", argv[optind]);
|
||||
}
|
||||
|
||||
/* Return nonzero if S represents a (possibly signed) decimal integer,
|
||||
zero if not. */
|
||||
|
||||
int
|
||||
isinteger (s)
|
||||
char *s;
|
||||
{
|
||||
if (*s == '-')
|
||||
++s;
|
||||
if (*s == 0)
|
||||
return 0;
|
||||
while (*s)
|
||||
{
|
||||
if (*s < '0' || *s > '9')
|
||||
return 0;
|
||||
++s;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-n adjustment] [-adjustment] [--adjustment=adjustment]\n\
|
||||
[command [arg...]]\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
48
src/nohup.sh
Executable file
48
src/nohup.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# nohup -- run a command immume to hangups, with output to a non-tty
|
||||
# Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Written by David MacKenzie <djm@gnu.ai.mit.edu>.
|
||||
|
||||
# Make sure we get GNU nice, if possible; also allow
|
||||
# it to be somewhere else in PATH if not installed yet.
|
||||
PATH=@bindir@:$PATH
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: nohup command [arg...]" 2>&1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
trap "" 1
|
||||
oldmask=`umask`; umask 077
|
||||
# Only redirect the output if the user didn't already do it.
|
||||
if [ -t 1 ]; then
|
||||
# If we cannot write to the current directory, use the home directory.
|
||||
if cat /dev/null >> nohup.out; then
|
||||
echo "nohup: appending output to \`nohup.out'" 2>&1
|
||||
umask $oldmask
|
||||
exec nice -5 "$@" >> nohup.out 2>&1
|
||||
else
|
||||
cat /dev/null >> $HOME/nohup.out
|
||||
echo "nohup: appending output to \`$HOME/nohup.out'" 2>&1
|
||||
umask $oldmask
|
||||
exec nice -5 "$@" >> $HOME/nohup.out 2>&1
|
||||
fi
|
||||
else
|
||||
umask $oldmask
|
||||
exec nice -5 "$@"
|
||||
fi
|
332
src/pathchk.c
Normal file
332
src/pathchk.c
Normal file
@ -0,0 +1,332 @@
|
||||
/* pathchk -- check whether pathnames are valid or portable
|
||||
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Usage: pathchk [-p] [--portability] path...
|
||||
|
||||
For each PATH, print a message if any of these conditions are false:
|
||||
* all existing leading directories in PATH have search (execute) permission
|
||||
* strlen (PATH) <= PATH_MAX
|
||||
* strlen (each_directory_in_PATH) <= NAME_MAX
|
||||
|
||||
Exit status:
|
||||
0 All PATH names passed all of the tests.
|
||||
1 An error occurred.
|
||||
|
||||
Options:
|
||||
-p, --portability Instead of performing length checks on the
|
||||
underlying filesystem, test the length of the
|
||||
pathname and its components against the POSIX.1
|
||||
minimum limits for portability, _POSIX_NAME_MAX
|
||||
and _POSIX_PATH_MAX in 2.9.2. Also check that
|
||||
the pathname contains no characters not in the
|
||||
portable filename character set.
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu>
|
||||
and Jim Meyering <meyering@cs.utexas.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#include <limits.h>
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
|
||||
#endif /* not PATH_MAX */
|
||||
#ifndef NAME_MAX
|
||||
#define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX);
|
||||
#endif /* not NAME_MAX */
|
||||
|
||||
#else /* not _POSIX_VERSION */
|
||||
|
||||
#include <sys/param.h>
|
||||
#ifndef PATH_MAX
|
||||
#ifdef MAXPATHLEN
|
||||
#define PATH_MAX MAXPATHLEN
|
||||
#else /* not MAXPATHLEN */
|
||||
#define PATH_MAX _POSIX_PATH_MAX
|
||||
#endif /* not MAXPATHLEN */
|
||||
#endif /* not PATH_MAX */
|
||||
|
||||
#ifndef NAME_MAX
|
||||
#ifdef MAXNAMLEN
|
||||
#define NAME_MAX MAXNAMLEN
|
||||
#else /* not MAXNAMLEN */
|
||||
#define NAME_MAX _POSIX_NAME_MAX
|
||||
#endif /* not MAXNAMLEN */
|
||||
#endif /* not NAME_MAX */
|
||||
|
||||
#endif /* not _POSIX_VERSION */
|
||||
|
||||
#ifndef _POSIX_PATH_MAX
|
||||
#define _POSIX_PATH_MAX 255
|
||||
#endif
|
||||
#ifndef _POSIX_NAME_MAX
|
||||
#define _POSIX_NAME_MAX 14
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX_FOR
|
||||
#define PATH_MAX_FOR(p) PATH_MAX
|
||||
#endif
|
||||
#ifndef NAME_MAX_FOR
|
||||
#define NAME_MAX_FOR(p) NAME_MAX
|
||||
#endif
|
||||
|
||||
char *xstrdup();
|
||||
int validate_path ();
|
||||
void error ();
|
||||
void usage ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"portability", 0, NULL, 'p'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int exit_status = 0;
|
||||
int check_portability = 0;
|
||||
int optc;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "p", longopts, (int *) 0)) != EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'p':
|
||||
check_portability = 1;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
usage ();
|
||||
|
||||
for (; optind < argc; ++optind)
|
||||
exit_status |= validate_path (argv[optind], check_portability);
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Each element is nonzero if the corresponding ASCII character is
|
||||
in the POSIX portable character set, and zero if it is not.
|
||||
In addition, the entry for `/' is nonzero to simplify checking. */
|
||||
char portable_chars[] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* If PATH contains only portable characters, return 1, else 0. */
|
||||
|
||||
int
|
||||
portable_chars_only (path)
|
||||
char *path;
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = path; *p; ++p)
|
||||
if (portable_chars[*p] == 0)
|
||||
{
|
||||
error (0, 0, "path `%s' contains nonportable character `%c'",
|
||||
path, *p);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return 1 if PATH is a usable leading directory, 0 if not,
|
||||
2 if it doesn't exist. */
|
||||
|
||||
int
|
||||
dir_ok (path)
|
||||
char *path;
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
if (stat (path, &stats))
|
||||
return 2;
|
||||
|
||||
if (!S_ISDIR (stats.st_mode))
|
||||
{
|
||||
error (0, 0, "`%s' is not a directory", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use access to test for search permission because
|
||||
testing permission bits of st_mode can lose with new
|
||||
access control mechanisms. Of course, access loses if you're
|
||||
running setuid. */
|
||||
if (access (path, X_OK) != 0)
|
||||
{
|
||||
if (errno == EACCES)
|
||||
error (0, 0, "directory `%s' is not searchable", path);
|
||||
else
|
||||
error (0, errno, "%s", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make sure that
|
||||
strlen (PATH) <= PATH_MAX
|
||||
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
|
||||
|
||||
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
|
||||
_POSIX_NAME_MAX instead, and make sure that PATH contains no
|
||||
characters not in the POSIX portable filename character set, which
|
||||
consists of A-Z, a-z, 0-9, ., _, -.
|
||||
|
||||
Make sure that all leading directories along PATH that exist have
|
||||
`x' permission.
|
||||
|
||||
Return 0 if all of these tests are successful, 1 if any fail. */
|
||||
|
||||
int
|
||||
validate_path (path, portability)
|
||||
char *path;
|
||||
int portability;
|
||||
{
|
||||
int path_max;
|
||||
int last_elem; /* Nonzero if checking last element of path. */
|
||||
int exists; /* 2 if the path element exists. */
|
||||
char *slash;
|
||||
char *parent; /* Last existing leading directory so far. */
|
||||
|
||||
if (portability && !portable_chars_only (path))
|
||||
return 1;
|
||||
|
||||
if (*path == '\0')
|
||||
return 0;
|
||||
|
||||
/* Figure out the parent of the first element in PATH. */
|
||||
parent = xstrdup (*path == '/' ? "/" : ".");
|
||||
|
||||
slash = path;
|
||||
last_elem = 0;
|
||||
while (1)
|
||||
{
|
||||
int name_max;
|
||||
int length; /* Length of partial path being checked. */
|
||||
char *start; /* Start of path element being checked. */
|
||||
|
||||
/* Find the end of this element of the path.
|
||||
Then chop off the rest of the path after this element. */
|
||||
while (*slash == '/')
|
||||
slash++;
|
||||
start = slash;
|
||||
slash = index (slash, '/');
|
||||
if (slash != NULL)
|
||||
*slash = '\0';
|
||||
else
|
||||
{
|
||||
last_elem = 1;
|
||||
slash = index (start, '\0');
|
||||
}
|
||||
|
||||
if (!last_elem)
|
||||
{
|
||||
exists = dir_ok (path);
|
||||
if (dir_ok == 0)
|
||||
{
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
length = slash - start;
|
||||
/* Since we know that `parent' is a directory, it's ok to call
|
||||
pathconf with it as the argument. (If `parent' isn't a directory
|
||||
or doesn't exist, the behavior of pathconf is undefined.)
|
||||
But if `parent' is a directory and is on a remote file system,
|
||||
it's likely that pathconf can't give us a reasonable value
|
||||
and will return -1. (NFS and tempfs are not POSIX . . .)
|
||||
In that case, we have no choice but to assume the pessimal
|
||||
POSIX minimums. */
|
||||
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
|
||||
if (name_max < 0)
|
||||
name_max = _POSIX_NAME_MAX;
|
||||
if (length > name_max)
|
||||
{
|
||||
error (0, 0, "name `%s' has length %d; exceeds limit of %d",
|
||||
start, length, name_max);
|
||||
free (parent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (last_elem)
|
||||
break;
|
||||
|
||||
if (exists == 1)
|
||||
{
|
||||
free (parent);
|
||||
parent = xstrdup (path);
|
||||
}
|
||||
|
||||
*slash++ = '/';
|
||||
}
|
||||
|
||||
/* `parent' is now the last existing leading directory in the whole path,
|
||||
so it's ok to call pathconf with it as the argument. */
|
||||
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
|
||||
if (path_max < 0)
|
||||
path_max = _POSIX_PATH_MAX;
|
||||
free (parent);
|
||||
if (strlen (path) > path_max)
|
||||
{
|
||||
error (0, 0, "path `%s' has length %d; exceeds limit of %d",
|
||||
path, strlen (path), path_max);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-p] [--portability] path...\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
69
src/printenv.c
Normal file
69
src/printenv.c
Normal file
@ -0,0 +1,69 @@
|
||||
/* printenv -- print all or part of environment
|
||||
Copyright (C) 1989, 1991 Free Software Foundation.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Usage: printenv [variable...]
|
||||
|
||||
If no arguments are given, print the entire environment.
|
||||
If one or more variable names are given, print the value of
|
||||
each one that is set, and nothing for ones that are not set.
|
||||
|
||||
Exit status:
|
||||
0 if all variables specified were found
|
||||
1 if not
|
||||
|
||||
David MacKenzie and Richard Mlynarik */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
extern char **environ;
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char **env;
|
||||
char *ep, *ap;
|
||||
int i;
|
||||
int matches = 0;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
for (env = environ; *env; ++env)
|
||||
puts (*env);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; ++i)
|
||||
{
|
||||
for (env = environ; *env; ++env)
|
||||
{
|
||||
ep = *env;
|
||||
ap = argv[i];
|
||||
while (*ep != '\0' && *ap != '\0' && *ep++ == *ap++)
|
||||
if (*ep == '=' && *ap == '\0')
|
||||
{
|
||||
puts (ep + 1);
|
||||
++matches;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
exit (matches != argc - 1);
|
||||
}
|
481
src/printf.c
Normal file
481
src/printf.c
Normal file
@ -0,0 +1,481 @@
|
||||
/* printf - format and print data
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Usage: printf format [argument...]
|
||||
|
||||
A front end to the printf function that lets it be used from the shell.
|
||||
|
||||
Backslash escapes:
|
||||
|
||||
\" = double quote
|
||||
\\ = backslash
|
||||
\a = alert (bell)
|
||||
\b = backspace
|
||||
\c = produce no further output
|
||||
\f = form feed
|
||||
\n = new line
|
||||
\r = carriage return
|
||||
\t = horizontal tab
|
||||
\v = vertical tab
|
||||
\0ooo = octal number (ooo is 0 to 3 digits)
|
||||
\xhhh = hexadecimal number (hhh is 1 to 3 digits)
|
||||
|
||||
Additional directive:
|
||||
|
||||
%b = print an argument string, interpreting backslash escapes
|
||||
|
||||
The `format' argument is re-used as many times as necessary
|
||||
to convert all of the given arguments.
|
||||
|
||||
David MacKenzie <djm@gnu.ai.mit.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
#ifndef STDC_HEADERS
|
||||
double strtod ();
|
||||
long strtol ();
|
||||
unsigned long strtoul ();
|
||||
#endif
|
||||
|
||||
#define isodigit(c) ((c) >= '0' && (c) <= '7')
|
||||
#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
|
||||
#define octtobin(c) ((c) - '0')
|
||||
|
||||
char *xmalloc ();
|
||||
double xstrtod ();
|
||||
int print_esc ();
|
||||
int print_formatted ();
|
||||
long xstrtol ();
|
||||
unsigned long xstrtoul ();
|
||||
void error ();
|
||||
void print_direc ();
|
||||
void print_esc_char ();
|
||||
void print_esc_string ();
|
||||
void verify ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* The value to return to the calling program. */
|
||||
int exit_status;
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *format;
|
||||
int args_used;
|
||||
|
||||
program_name = argv[0];
|
||||
exit_status = 0;
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s format [argument...]\n", program_name);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
format = argv[1];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
do
|
||||
{
|
||||
args_used = print_formatted (format, argc, argv);
|
||||
argc -= args_used;
|
||||
argv += args_used;
|
||||
}
|
||||
while (args_used > 0 && argc > 0);
|
||||
|
||||
exit (exit_status);
|
||||
}
|
||||
|
||||
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
|
||||
arguments to any `%' directives.
|
||||
Return the number of elements of ARGV used. */
|
||||
|
||||
int
|
||||
print_formatted (format, argc, argv)
|
||||
char *format;
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int save_argc = argc; /* Preserve original value. */
|
||||
char *f; /* Pointer into `format'. */
|
||||
char *direc_start; /* Start of % directive. */
|
||||
int direc_length; /* Length of % directive. */
|
||||
int field_width; /* Arg to first '*', or -1 if none. */
|
||||
int precision; /* Arg to second '*', or -1 if none. */
|
||||
|
||||
for (f = format; *f; ++f)
|
||||
{
|
||||
switch (*f)
|
||||
{
|
||||
case '%':
|
||||
direc_start = f++;
|
||||
direc_length = 1;
|
||||
field_width = precision = -1;
|
||||
if (*f == '%')
|
||||
{
|
||||
putchar ('%');
|
||||
break;
|
||||
}
|
||||
if (*f == 'b')
|
||||
{
|
||||
if (argc > 0)
|
||||
{
|
||||
print_esc_string (*argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (index ("-+ #", *f))
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
if (*f == '*')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
if (argc > 0)
|
||||
{
|
||||
field_width = xstrtoul (*argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
else
|
||||
field_width = 0;
|
||||
}
|
||||
else
|
||||
while (isdigit (*f))
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
if (*f == '.')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
if (*f == '*')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
if (argc > 0)
|
||||
{
|
||||
precision = xstrtoul (*argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
else
|
||||
precision = 0;
|
||||
}
|
||||
else
|
||||
while (isdigit (*f))
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
}
|
||||
if (*f == 'l' || *f == 'L' || *f == 'h')
|
||||
{
|
||||
++f;
|
||||
++direc_length;
|
||||
}
|
||||
if (!index ("diouxXfeEgGcs", *f))
|
||||
error (1, 0, "%%%c: invalid directive", *f);
|
||||
++direc_length;
|
||||
if (argc > 0)
|
||||
{
|
||||
print_direc (direc_start, direc_length, field_width,
|
||||
precision, *argv);
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
else
|
||||
print_direc (direc_start, direc_length, field_width,
|
||||
precision, "");
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
f += print_esc (f);
|
||||
break;
|
||||
|
||||
default:
|
||||
putchar (*f);
|
||||
}
|
||||
}
|
||||
|
||||
return save_argc - argc;
|
||||
}
|
||||
|
||||
/* Print a \ escape sequence starting at ESCSTART.
|
||||
Return the number of characters in the escape sequence
|
||||
besides the backslash. */
|
||||
|
||||
int
|
||||
print_esc (escstart)
|
||||
char *escstart;
|
||||
{
|
||||
register char *p = escstart + 1;
|
||||
int esc_value = 0; /* Value of \nnn escape. */
|
||||
int esc_length; /* Length of \nnn escape. */
|
||||
|
||||
/* \0ooo and \xhhh escapes have maximum length of 3 chars. */
|
||||
if (*p == 'x')
|
||||
{
|
||||
for (esc_length = 0, ++p;
|
||||
esc_length < 3 && isxdigit (*p);
|
||||
++esc_length, ++p)
|
||||
esc_value = esc_value * 16 + hextobin (*p);
|
||||
if (esc_length == 0)
|
||||
error (1, 0, "missing hexadecimal number in escape");
|
||||
putchar (esc_value);
|
||||
}
|
||||
else if (*p == '0')
|
||||
{
|
||||
for (esc_length = 0, ++p;
|
||||
esc_length < 3 && isodigit (*p);
|
||||
++esc_length, ++p)
|
||||
esc_value = esc_value * 8 + octtobin (*p);
|
||||
putchar (esc_value);
|
||||
}
|
||||
else if (index ("\"\\abcfnrtv", *p))
|
||||
print_esc_char (*p++);
|
||||
else
|
||||
error (1, 0, "\\%c: invalid escape", *p);
|
||||
return p - escstart - 1;
|
||||
}
|
||||
|
||||
/* Output a single-character \ escape. */
|
||||
|
||||
void
|
||||
print_esc_char (c)
|
||||
char c;
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'a': /* Alert. */
|
||||
putchar (7);
|
||||
break;
|
||||
case 'b': /* Backspace. */
|
||||
putchar (8);
|
||||
break;
|
||||
case 'c': /* Cancel the rest of the output. */
|
||||
exit (0);
|
||||
break;
|
||||
case 'f': /* Form feed. */
|
||||
putchar (12);
|
||||
break;
|
||||
case 'n': /* New line. */
|
||||
putchar (10);
|
||||
break;
|
||||
case 'r': /* Carriage return. */
|
||||
putchar (13);
|
||||
break;
|
||||
case 't': /* Horizontal tab. */
|
||||
putchar (9);
|
||||
break;
|
||||
case 'v': /* Vertical tab. */
|
||||
putchar (11);
|
||||
break;
|
||||
default:
|
||||
putchar (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print string STR, evaluating \ escapes. */
|
||||
|
||||
void
|
||||
print_esc_string (str)
|
||||
char *str;
|
||||
{
|
||||
for (; *str; str++)
|
||||
if (*str == '\\')
|
||||
str += print_esc (str);
|
||||
else
|
||||
putchar (*str);
|
||||
}
|
||||
|
||||
/* Output a % directive. START is the start of the directive,
|
||||
LENGTH is its length, and ARGUMENT is its argument.
|
||||
If FIELD_WIDTH or PRECISION is non-negative, they are args for
|
||||
'*' values in those fields. */
|
||||
|
||||
void
|
||||
print_direc (start, length, field_width, precision, argument)
|
||||
char *start;
|
||||
int length;
|
||||
int field_width;
|
||||
int precision;
|
||||
char *argument;
|
||||
{
|
||||
char *p; /* Null-terminated copy of % directive. */
|
||||
|
||||
p = xmalloc ((unsigned) (length + 1));
|
||||
strncpy (p, start, length);
|
||||
p[length] = 0;
|
||||
|
||||
switch (p[length - 1])
|
||||
{
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (field_width < 0)
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, xstrtol (argument));
|
||||
else
|
||||
printf (p, precision, xstrtol (argument));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, field_width, xstrtol (argument));
|
||||
else
|
||||
printf (p, field_width, precision, xstrtol (argument));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (field_width < 0)
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, xstrtoul (argument));
|
||||
else
|
||||
printf (p, precision, xstrtoul (argument));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, field_width, xstrtoul (argument));
|
||||
else
|
||||
printf (p, field_width, precision, xstrtoul (argument));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
if (field_width < 0)
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, xstrtod (argument));
|
||||
else
|
||||
printf (p, precision, xstrtod (argument));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, field_width, xstrtod (argument));
|
||||
else
|
||||
printf (p, field_width, precision, xstrtod (argument));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf (p, *argument);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (field_width < 0)
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, argument);
|
||||
else
|
||||
printf (p, precision, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (precision < 0)
|
||||
printf (p, field_width, argument);
|
||||
else
|
||||
printf (p, field_width, precision, argument);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
free (p);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
xstrtoul (s)
|
||||
char *s;
|
||||
{
|
||||
char *end;
|
||||
unsigned long val;
|
||||
|
||||
errno = 0;
|
||||
val = strtoul (s, &end, 0);
|
||||
verify (s, end);
|
||||
return val;
|
||||
}
|
||||
|
||||
long
|
||||
xstrtol (s)
|
||||
char *s;
|
||||
{
|
||||
char *end;
|
||||
long val;
|
||||
|
||||
errno = 0;
|
||||
val = strtol (s, &end, 0);
|
||||
verify (s, end);
|
||||
return val;
|
||||
}
|
||||
|
||||
double
|
||||
xstrtod (s)
|
||||
char *s;
|
||||
{
|
||||
char *end;
|
||||
double val;
|
||||
|
||||
errno = 0;
|
||||
val = strtod (s, &end);
|
||||
verify (s, end);
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
verify (s, end)
|
||||
char *s, *end;
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
error (0, errno, "%s", s);
|
||||
exit_status = 1;
|
||||
}
|
||||
else if (*end)
|
||||
{
|
||||
if (s == end)
|
||||
error (0, 0, "%s: expected a numeric value", s);
|
||||
else
|
||||
error (0, 0, "%s: value not completely converted", s);
|
||||
exit_status = 1;
|
||||
}
|
||||
}
|
84
src/sleep.c
Normal file
84
src/sleep.c
Normal file
@ -0,0 +1,84 @@
|
||||
/* sleep - delay for a specified amount of time.
|
||||
Copyright (C) 1984, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
long argdecode ();
|
||||
void error ();
|
||||
|
||||
/* The name by which this program was run. */
|
||||
char *program_name;
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i;
|
||||
unsigned seconds = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s number[smhd]...\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
seconds += argdecode (argv[i]);
|
||||
|
||||
sleep (seconds);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
long
|
||||
argdecode (s)
|
||||
char *s;
|
||||
{
|
||||
long value;
|
||||
register char *p = s;
|
||||
register char c;
|
||||
|
||||
value = 0;
|
||||
while ((c = *p++) >= '0' && c <= '9')
|
||||
value = value * 10 + c - '0';
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 's':
|
||||
break;
|
||||
case 'm':
|
||||
value *= 60;
|
||||
break;
|
||||
case 'h':
|
||||
value *= 60 * 60;
|
||||
break;
|
||||
case 'd':
|
||||
value *= 60 * 60 * 24;
|
||||
break;
|
||||
default:
|
||||
p--;
|
||||
}
|
||||
|
||||
if (*p)
|
||||
error (1, 0, "invalid time interval `%s'", s);
|
||||
return value;
|
||||
}
|
1241
src/stty.c
Normal file
1241
src/stty.c
Normal file
File diff suppressed because it is too large
Load Diff
519
src/su.c
Normal file
519
src/su.c
Normal file
@ -0,0 +1,519 @@
|
||||
/* su for GNU. Run a shell with substitute user and group IDs.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Run a shell with the real and effective UID and GID and groups
|
||||
of USER, default `root'.
|
||||
|
||||
The shell run is taken from USER's password entry, /bin/sh if
|
||||
none is specified there. If the account has a password, su
|
||||
prompts for a password unless run by a user with real UID 0.
|
||||
|
||||
Does not change the current directory.
|
||||
Sets `HOME' and `SHELL' from the password entry for USER, and if
|
||||
USER is not root, sets `USER' and `LOGNAME' to USER.
|
||||
The subshell is not a login shell.
|
||||
|
||||
If one or more ARGs are given, they are passed as additional
|
||||
arguments to the subshell.
|
||||
|
||||
Does not handle /bin/sh or other shells specially
|
||||
(setting argv[0] to "-su", passing -c only to certain shells, etc.).
|
||||
I don't see the point in doing that, and it's ugly.
|
||||
|
||||
This program intentionally does not support a "wheel group" that
|
||||
restricts who can su to UID 0 accounts. RMS considers that to
|
||||
be fascist.
|
||||
|
||||
Options:
|
||||
-, -l, --login Make the subshell a login shell.
|
||||
Unset all environment variables except
|
||||
TERM, HOME and SHELL (set as above), and USER
|
||||
and LOGNAME (set unconditionally as above), and
|
||||
set PATH to a default value.
|
||||
Change to USER's home directory.
|
||||
Prepend "-" to the shell's name.
|
||||
-c, --commmand=COMMAND
|
||||
Pass COMMAND to the subshell with a -c option
|
||||
instead of starting an interactive shell.
|
||||
-f, --fast Pass the -f option to the subshell.
|
||||
-m, -p, --preserve-environment
|
||||
Do not change HOME, USER, LOGNAME, SHELL.
|
||||
Run $SHELL instead of USER's shell from /etc/passwd
|
||||
unless not the superuser and USER's shell is
|
||||
restricted.
|
||||
Overridden by --login and --shell.
|
||||
-s, --shell=shell Run SHELL instead of USER's shell from /etc/passwd
|
||||
unless not the superuser and USER's shell is
|
||||
restricted.
|
||||
|
||||
Compile-time options:
|
||||
-DSYSLOG_SUCCESS Log successful su's (by default, to root) with syslog.
|
||||
-DSYSLOG_FAILURE Log failed su's (by default, to root) with syslog.
|
||||
|
||||
-DSYSLOG_NON_ROOT Log all su's, not just those to root (UID 0).
|
||||
Never logs attempted su's to nonexistent accounts.
|
||||
|
||||
Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include "system.h"
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
void log_su ();
|
||||
#else
|
||||
#ifdef SYSLOG_SUCCESS
|
||||
#undef SYSLOG_SUCCESS
|
||||
#endif
|
||||
#ifdef SYSLOG_FAILURE
|
||||
#undef SYSLOG_FAILURE
|
||||
#endif
|
||||
#ifdef SYSLOG_NON_ROOT
|
||||
#undef SYSLOG_NON_ROOT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#include <limits.h>
|
||||
#ifdef NGROUPS_MAX
|
||||
#undef NGROUPS_MAX
|
||||
#endif
|
||||
#define NGROUPS_MAX sysconf (_SC_NGROUPS_MAX)
|
||||
#else /* not _POSIX_VERSION */
|
||||
struct passwd *getpwuid ();
|
||||
struct group *getgrgid ();
|
||||
uid_t getuid ();
|
||||
#include <sys/param.h>
|
||||
#if !defined(NGROUPS_MAX) && defined(NGROUPS)
|
||||
#define NGROUPS_MAX NGROUPS
|
||||
#endif
|
||||
#endif /* not _POSIX_VERSION */
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
#define endgrent()
|
||||
#define endpwent()
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SHADOW_H
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
|
||||
/* The default PATH for simulated logins to non-superuser accounts. */
|
||||
#define DEFAULT_LOGIN_PATH ":/usr/ucb:/bin:/usr/bin"
|
||||
|
||||
/* The default PATH for simulated logins to superuser accounts. */
|
||||
#define DEFAULT_ROOT_LOGIN_PATH "/usr/ucb:/bin:/usr/bin:/etc"
|
||||
|
||||
/* The shell to run if none is given in the user's passwd entry. */
|
||||
#define DEFAULT_SHELL "/bin/sh"
|
||||
|
||||
/* The user to become if none is specified. */
|
||||
#define DEFAULT_USER "root"
|
||||
|
||||
char *crypt ();
|
||||
char *getpass ();
|
||||
char *getusershell ();
|
||||
void endusershell ();
|
||||
void setusershell ();
|
||||
|
||||
char *basename ();
|
||||
char *concat ();
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
int correct_password ();
|
||||
int elements ();
|
||||
int restricted_shell ();
|
||||
void change_identity ();
|
||||
void error ();
|
||||
void modify_environment ();
|
||||
void run_shell ();
|
||||
void usage ();
|
||||
void xputenv ();
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, pass the `-f' option to the subshell. */
|
||||
int fast_startup;
|
||||
|
||||
/* If nonzero, simulate a login instead of just starting a shell. */
|
||||
int simulate_login;
|
||||
|
||||
/* If nonzero, change some environment vars to indicate the user su'd to. */
|
||||
int change_environment;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"command", 1, 0, 'c'},
|
||||
{"fast", 0, &fast_startup, 1},
|
||||
{"login", 0, &simulate_login, 1},
|
||||
{"preserve-environment", 0, &change_environment, 0},
|
||||
{"shell", 1, 0, 's'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int optc;
|
||||
char *new_user = DEFAULT_USER;
|
||||
char *command = 0;
|
||||
char **additional_args = 0;
|
||||
char *shell = 0;
|
||||
struct passwd *pw;
|
||||
|
||||
program_name = argv[0];
|
||||
fast_startup = 0;
|
||||
simulate_login = 0;
|
||||
change_environment = 1;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "c:flmps:", longopts, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 'c':
|
||||
command = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
fast_startup = 1;
|
||||
break;
|
||||
case 'l':
|
||||
simulate_login = 1;
|
||||
break;
|
||||
case 'm':
|
||||
case 'p':
|
||||
change_environment = 0;
|
||||
break;
|
||||
case 's':
|
||||
shell = optarg;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
if (optind < argc && !strcmp (argv[optind], "-"))
|
||||
{
|
||||
simulate_login = 1;
|
||||
++optind;
|
||||
}
|
||||
if (optind < argc)
|
||||
new_user = argv[optind++];
|
||||
if (optind < argc)
|
||||
additional_args = argv + optind;
|
||||
|
||||
pw = getpwnam (new_user);
|
||||
if (pw == 0)
|
||||
error (1, 0, "user %s does not exist", new_user);
|
||||
endpwent ();
|
||||
if (!correct_password (pw))
|
||||
{
|
||||
#ifdef SYSLOG_FAILURE
|
||||
log_su (pw, 0);
|
||||
#endif
|
||||
error (1, 0, "incorrect password");
|
||||
}
|
||||
#ifdef SYSLOG_SUCCESS
|
||||
else
|
||||
{
|
||||
log_su (pw, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pw->pw_shell == 0 || pw->pw_shell[0] == 0)
|
||||
pw->pw_shell = DEFAULT_SHELL;
|
||||
if (shell == 0 && change_environment == 0)
|
||||
shell = getenv ("SHELL");
|
||||
if (shell != 0 && getuid () && restricted_shell (pw->pw_shell))
|
||||
{
|
||||
/* The user being su'd to has a nonstandard shell, and so is
|
||||
probably a uucp account or has restricted access. Don't
|
||||
compromise the account by allowing access with a standard
|
||||
shell. */
|
||||
error (0, 0, "using restricted shell %s", pw->pw_shell);
|
||||
shell = 0;
|
||||
}
|
||||
if (shell == 0)
|
||||
shell = pw->pw_shell;
|
||||
shell = strcpy (xmalloc (strlen (shell) + 1), shell);
|
||||
modify_environment (pw, shell);
|
||||
|
||||
change_identity (pw);
|
||||
if (simulate_login && chdir (pw->pw_dir))
|
||||
error (0, errno, "warning: cannot change directory to %s", pw->pw_dir);
|
||||
run_shell (shell, command, additional_args);
|
||||
}
|
||||
|
||||
/* Ask the user for a password.
|
||||
Return 1 if the user gives the correct password for entry PW,
|
||||
0 if not. Return 1 without asking for a password if run by UID 0
|
||||
or if PW has an empty password. */
|
||||
|
||||
int
|
||||
correct_password (pw)
|
||||
struct passwd *pw;
|
||||
{
|
||||
char *unencrypted, *encrypted, *correct;
|
||||
#ifdef HAVE_SHADOW_H
|
||||
/* Shadow passwd stuff for SVR3 and maybe other systems. */
|
||||
struct spwd *sp = getspnam (pw->pw_name);
|
||||
|
||||
endspent ();
|
||||
if (sp)
|
||||
correct = sp->sp_pwdp;
|
||||
else
|
||||
#endif
|
||||
correct = pw->pw_passwd;
|
||||
|
||||
if (getuid () == 0 || correct == 0 || correct[0] == '\0')
|
||||
return 1;
|
||||
|
||||
unencrypted = getpass ("Password:");
|
||||
encrypted = crypt (unencrypted, correct);
|
||||
bzero (unencrypted, strlen (unencrypted));
|
||||
return strcmp (encrypted, correct) == 0;
|
||||
}
|
||||
|
||||
/* Update `environ' for the new shell based on PW, with SHELL being
|
||||
the value for the SHELL environment variable. */
|
||||
|
||||
void
|
||||
modify_environment (pw, shell)
|
||||
struct passwd *pw;
|
||||
char *shell;
|
||||
{
|
||||
char *term;
|
||||
|
||||
if (simulate_login)
|
||||
{
|
||||
/* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
|
||||
Unset all other environment variables. */
|
||||
term = getenv ("TERM");
|
||||
environ = (char **) xmalloc (2 * sizeof (char *));
|
||||
environ[0] = 0;
|
||||
if (term)
|
||||
xputenv (concat ("TERM", "=", term));
|
||||
xputenv (concat ("HOME", "=", pw->pw_dir));
|
||||
xputenv (concat ("SHELL", "=", shell));
|
||||
xputenv (concat ("USER", "=", pw->pw_name));
|
||||
xputenv (concat ("LOGNAME", "=", pw->pw_name));
|
||||
xputenv (concat ("PATH", "=", pw->pw_uid
|
||||
? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set HOME, SHELL, and if not becoming a super-user,
|
||||
USER and LOGNAME. */
|
||||
if (change_environment)
|
||||
{
|
||||
xputenv (concat ("HOME", "=", pw->pw_dir));
|
||||
xputenv (concat ("SHELL", "=", shell));
|
||||
if (pw->pw_uid)
|
||||
{
|
||||
xputenv (concat ("USER", "=", pw->pw_name));
|
||||
xputenv (concat ("LOGNAME", "=", pw->pw_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Become the user and group(s) specified by PW. */
|
||||
|
||||
void
|
||||
change_identity (pw)
|
||||
struct passwd *pw;
|
||||
{
|
||||
#ifdef NGROUPS_MAX
|
||||
errno = 0;
|
||||
if (initgroups (pw->pw_name, pw->pw_gid) == -1)
|
||||
error (1, errno, "cannot set groups");
|
||||
endgrent ();
|
||||
#endif
|
||||
if (setgid (pw->pw_gid))
|
||||
error (1, errno, "cannot set group id");
|
||||
if (setuid (pw->pw_uid))
|
||||
error (1, errno, "cannot set user id");
|
||||
}
|
||||
|
||||
/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
|
||||
If COMMAND is nonzero, pass it to the shell with the -c option.
|
||||
If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
|
||||
arguments. */
|
||||
|
||||
void
|
||||
run_shell (shell, command, additional_args)
|
||||
char *shell;
|
||||
char *command;
|
||||
char **additional_args;
|
||||
{
|
||||
char **args;
|
||||
int argno = 1;
|
||||
|
||||
if (additional_args)
|
||||
args = (char **) xmalloc (sizeof (char *)
|
||||
* (10 + elements (additional_args)));
|
||||
else
|
||||
args = (char **) xmalloc (sizeof (char *) * 10);
|
||||
if (simulate_login)
|
||||
{
|
||||
args[0] = xmalloc (strlen (shell) + 2);
|
||||
args[0][0] = '-';
|
||||
strcpy (args[0] + 1, basename (shell));
|
||||
}
|
||||
else
|
||||
args[0] = basename (shell);
|
||||
if (fast_startup)
|
||||
args[argno++] = "-f";
|
||||
if (command)
|
||||
{
|
||||
args[argno++] = "-c";
|
||||
args[argno++] = command;
|
||||
}
|
||||
if (additional_args)
|
||||
for (; *additional_args; ++additional_args)
|
||||
args[argno++] = *additional_args;
|
||||
args[argno] = 0;
|
||||
execv (shell, args);
|
||||
error (1, errno, "cannot run %s", shell);
|
||||
}
|
||||
|
||||
#if defined (SYSLOG_SUCCESS) || defined (SYSLOG_FAILURE)
|
||||
/* Log the fact that someone has run su to the user given by PW;
|
||||
if SUCCESSFUL is nonzero, they gave the correct password, etc. */
|
||||
|
||||
void
|
||||
log_su (pw, successful)
|
||||
struct passwd *pw;
|
||||
int successful;
|
||||
{
|
||||
char *new_user, *old_user, *tty;
|
||||
|
||||
#ifndef SYSLOG_NON_ROOT
|
||||
if (pw->pw_uid)
|
||||
return;
|
||||
#endif
|
||||
new_user = pw->pw_name;
|
||||
/* The utmp entry (via getlogin) is probably the best way to identify
|
||||
the user, especially if someone su's from a su-shell. */
|
||||
old_user = getlogin ();
|
||||
if (old_user == 0)
|
||||
old_user = "";
|
||||
tty = ttyname (2);
|
||||
if (tty == 0)
|
||||
tty = "";
|
||||
/* 4.2BSD openlog doesn't have the third parameter. */
|
||||
openlog (basename (program_name), 0
|
||||
#ifdef LOG_AUTH
|
||||
, LOG_AUTH
|
||||
#endif
|
||||
);
|
||||
syslog (LOG_NOTICE,
|
||||
#ifdef SYSLOG_NON_ROOT
|
||||
"%s(to %s) %s on %s",
|
||||
#else
|
||||
"%s%s on %s",
|
||||
#endif
|
||||
successful ? "" : "FAILED SU ",
|
||||
#ifdef SYSLOG_NON_ROOT
|
||||
new_user,
|
||||
#endif
|
||||
old_user, tty);
|
||||
closelog ();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if SHELL is a restricted shell (one not returned by
|
||||
getusershell), else 0, meaning it is a standard shell. */
|
||||
|
||||
int
|
||||
restricted_shell (shell)
|
||||
char *shell;
|
||||
{
|
||||
char *line;
|
||||
|
||||
setusershell ();
|
||||
while (line = getusershell ())
|
||||
{
|
||||
if (*line != '#' && strcmp (line, shell) == 0)
|
||||
{
|
||||
endusershell ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
endusershell ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the number of elements in ARR, a null-terminated array. */
|
||||
|
||||
int
|
||||
elements (arr)
|
||||
char **arr;
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (n = 0; *arr; ++arr)
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Add VAL to the environment, checking for out of memory errors. */
|
||||
|
||||
void
|
||||
xputenv (val)
|
||||
char *val;
|
||||
{
|
||||
if (putenv (val))
|
||||
error (1, 0, "virtual memory exhausted");
|
||||
}
|
||||
|
||||
/* Return a newly-allocated string whose contents concatenate
|
||||
those of S1, S2, S3. */
|
||||
|
||||
char *
|
||||
concat (s1, s2, s3)
|
||||
char *s1, *s2, *s3;
|
||||
{
|
||||
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
|
||||
char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
|
||||
|
||||
strcpy (result, s1);
|
||||
strcpy (result + len1, s2);
|
||||
strcpy (result + len1 + len2, s3);
|
||||
result[len1 + len2 + len3] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-flmp] [-c command] [-s shell] [--login] [--fast]\n\
|
||||
[--preserve-environment] [--command=command] [--shell=shell] [-]\n\
|
||||
[user [arg...]]\n", program_name);
|
||||
exit (1);
|
||||
}
|
155
src/tee.c
Normal file
155
src/tee.c
Normal file
@ -0,0 +1,155 @@
|
||||
/* tee - read from standard input and write to standard output and files.
|
||||
Copyright (C) 1985, 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Mike Parker, Richard M. Stallman, and David MacKenzie */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <getopt.h>
|
||||
#include "system.h"
|
||||
|
||||
char *xmalloc ();
|
||||
int tee ();
|
||||
void error ();
|
||||
void xwrite ();
|
||||
|
||||
/* If nonzero, append to output files rather than truncating them. */
|
||||
int append;
|
||||
|
||||
/* If nonzero, ignore interrupts. */
|
||||
int ignore_interrupts;
|
||||
|
||||
/* The name that this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
struct option long_options[] =
|
||||
{
|
||||
{"append", 0, NULL, 'a'},
|
||||
{"ignore-interrupts", 0, NULL, 'i'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int errs;
|
||||
int optc;
|
||||
|
||||
program_name = argv[0];
|
||||
append = 0;
|
||||
ignore_interrupts = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "ai", long_options, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'a':
|
||||
append = 1;
|
||||
break;
|
||||
case 'i':
|
||||
ignore_interrupts = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-ai] [--append] [--ignore-interrupts] [file...]\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore_interrupts)
|
||||
#ifdef _POSIX_VERSION
|
||||
{
|
||||
struct sigaction sigact;
|
||||
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset (&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction (SIGINT, &sigact, NULL);
|
||||
}
|
||||
#else /* !_POSIX_VERSION */
|
||||
signal (SIGINT, SIG_IGN);
|
||||
#endif /* _POSIX_VERSION */
|
||||
|
||||
errs = tee (argc - optind, &argv[optind]);
|
||||
if (close (0) == -1)
|
||||
error (1, errno, "standard input");
|
||||
if (close (1) == -1)
|
||||
error (1, errno, "standard output");
|
||||
exit (errs);
|
||||
}
|
||||
|
||||
/* Copy the standard input into each of the NFILES files in FILES
|
||||
and into the standard output.
|
||||
Return 0 if successful, 1 if any errors occur. */
|
||||
|
||||
int
|
||||
tee (nfiles, files)
|
||||
int nfiles;
|
||||
char **files;
|
||||
{
|
||||
int *descriptors;
|
||||
char buffer[BUFSIZ];
|
||||
register int bytes_read, i, ret = 0, mode;
|
||||
|
||||
if (nfiles)
|
||||
descriptors = (int *) xmalloc (nfiles * sizeof (int));
|
||||
mode = O_WRONLY | O_CREAT;
|
||||
if (append)
|
||||
mode |= O_APPEND;
|
||||
else
|
||||
mode |= O_TRUNC;
|
||||
|
||||
for (i = 0; i < nfiles; i++)
|
||||
{
|
||||
descriptors[i] = open (files[i], mode, 0666);
|
||||
if (descriptors[i] == -1)
|
||||
{
|
||||
error (0, errno, "%s", files[i]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
while ((bytes_read = read (0, buffer, sizeof buffer)) > 0)
|
||||
{
|
||||
xwrite (1, buffer, bytes_read);
|
||||
for (i = 0; i < nfiles; i++)
|
||||
if (descriptors[i] != -1)
|
||||
xwrite (descriptors[i], buffer, bytes_read);
|
||||
}
|
||||
if (bytes_read == -1)
|
||||
{
|
||||
error (0, errno, "read error");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nfiles; i++)
|
||||
if (descriptors[i] != -1 && close (descriptors[i]) == -1)
|
||||
{
|
||||
error (0, errno, "%s", files[i]);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (nfiles)
|
||||
free (descriptors);
|
||||
|
||||
return ret;
|
||||
}
|
1054
src/test.c
Normal file
1054
src/test.c
Normal file
File diff suppressed because it is too large
Load Diff
88
src/tty.c
Normal file
88
src/tty.c
Normal file
@ -0,0 +1,88 @@
|
||||
/* tty -- print the path of the terminal connected to standard input
|
||||
Copyright (C) 1990, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Displays "not a tty" if stdin is not a terminal.
|
||||
Displays nothing if -s option is given.
|
||||
Exit status 0 if stdin is a tty, 1 if not, 2 if usage error.
|
||||
|
||||
Written by David MacKenzie (djm@ai.mit.edu). */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
|
||||
void usage ();
|
||||
|
||||
/* The name under which this program was run. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, return an exit status but produce no output. */
|
||||
int silent;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"silent", 0, NULL, 's'},
|
||||
{"quiet", 0, NULL, 's'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *tty;
|
||||
int optc;
|
||||
|
||||
program_name = argv[0];
|
||||
silent = 0;
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "s", longopts, (int *) 0)) != EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 's':
|
||||
silent = 1;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc)
|
||||
usage ();
|
||||
|
||||
tty = ttyname (0);
|
||||
if (!silent)
|
||||
{
|
||||
if (tty)
|
||||
puts (tty);
|
||||
else
|
||||
puts ("not a tty");
|
||||
}
|
||||
|
||||
exit (tty == NULL);
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-s] [--silent] [--quiet]\n", program_name);
|
||||
exit (2);
|
||||
}
|
155
src/uname.c
Normal file
155
src/uname.c
Normal file
@ -0,0 +1,155 @@
|
||||
/* uname -- print system information
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Option Example
|
||||
|
||||
-s, --sysname SunOS
|
||||
-n, --nodename rocky8
|
||||
-r, --release 4.0
|
||||
-v, --version
|
||||
-m, --machine sun
|
||||
-a, --all SunOS rocky8 4.0 sun
|
||||
|
||||
The default behavior is equivalent to `-s'.
|
||||
|
||||
David MacKenzie <djm@ai.mit.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <getopt.h>
|
||||
#include "system.h"
|
||||
|
||||
void error ();
|
||||
void print_element ();
|
||||
void usage ();
|
||||
|
||||
/* Values that are bitwise or'd into `toprint'. */
|
||||
/* Operating system name. */
|
||||
#define PRINT_SYSNAME 1
|
||||
|
||||
/* Node name on a communications network. */
|
||||
#define PRINT_NODENAME 2
|
||||
|
||||
/* Operating system release. */
|
||||
#define PRINT_RELEASE 4
|
||||
|
||||
/* Operating system version. */
|
||||
#define PRINT_VERSION 8
|
||||
|
||||
/* Machine hardware name. */
|
||||
#define PRINT_MACHINE 16
|
||||
|
||||
/* Mask indicating which elements of the name to print. */
|
||||
unsigned char toprint;
|
||||
|
||||
/* The name this program was run with, for error messages. */
|
||||
char *program_name;
|
||||
|
||||
struct option long_options[] =
|
||||
{
|
||||
{"sysname", 0, NULL, 's'},
|
||||
{"nodename", 0, NULL, 'n'},
|
||||
{"release", 0, NULL, 'r'},
|
||||
{"version", 0, NULL, 'v'},
|
||||
{"machine", 0, NULL, 'm'},
|
||||
{"all", 0, NULL, 'a'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct utsname name;
|
||||
int c;
|
||||
|
||||
program_name = argv[0];
|
||||
toprint = 0;
|
||||
|
||||
while ((c = getopt_long (argc, argv, "snrvma", long_options, (int *) 0))
|
||||
!= EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 's':
|
||||
toprint |= PRINT_SYSNAME;
|
||||
break;
|
||||
case 'n':
|
||||
toprint |= PRINT_NODENAME;
|
||||
break;
|
||||
case 'r':
|
||||
toprint |= PRINT_RELEASE;
|
||||
break;
|
||||
case 'v':
|
||||
toprint |= PRINT_VERSION;
|
||||
break;
|
||||
case 'm':
|
||||
toprint |= PRINT_MACHINE;
|
||||
break;
|
||||
case 'a':
|
||||
toprint = PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE |
|
||||
PRINT_VERSION | PRINT_MACHINE;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc)
|
||||
usage ();
|
||||
|
||||
if (toprint == 0)
|
||||
toprint = PRINT_SYSNAME;
|
||||
|
||||
if (uname (&name) == -1)
|
||||
error (1, errno, "cannot get system name");
|
||||
|
||||
print_element (PRINT_SYSNAME, name.sysname);
|
||||
print_element (PRINT_NODENAME, name.nodename);
|
||||
print_element (PRINT_RELEASE, name.release);
|
||||
print_element (PRINT_VERSION, name.version);
|
||||
print_element (PRINT_MACHINE, name.machine);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* If the name element set in MASK is selected for printing in `toprint',
|
||||
print ELEMENT; then print a space unless it is the last element to
|
||||
be printed, in which case print a newline. */
|
||||
|
||||
void
|
||||
print_element (mask, element)
|
||||
unsigned char mask;
|
||||
char *element;
|
||||
{
|
||||
if (toprint & mask)
|
||||
{
|
||||
toprint &= ~mask;
|
||||
printf ("%s%c", element, toprint ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-snrvma] [--sysname] [--nodename] [--release] [--version]\n\
|
||||
[--machine] [--all]\n", program_name);
|
||||
exit (1);
|
||||
}
|
434
src/who.c
Normal file
434
src/who.c
Normal file
@ -0,0 +1,434 @@
|
||||
/* GNU's who.
|
||||
Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by jla; revised by djm */
|
||||
|
||||
/* Output format:
|
||||
name [state] line time [idle] host
|
||||
state: -T
|
||||
name, line, time: not -q
|
||||
idle: -u
|
||||
|
||||
Options:
|
||||
-m Same as 'who am i', for POSIX.
|
||||
-q Only user names and # logged on; overrides all other options.
|
||||
-s Name, line, time (default).
|
||||
-i, -u Idle hours and minutes; '.' means active in last minute;
|
||||
'old' means idle for >24 hours.
|
||||
-H Print column headings at top.
|
||||
-w, -T -s plus mesg (+ or -, or ? if bad line). */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
#include <time.h>
|
||||
#include <getopt.h>
|
||||
#ifndef _POSIX_SOURCE
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include "system.h"
|
||||
|
||||
#ifndef UTMP_FILE
|
||||
#ifdef _PATH_UTMP /* 4.4BSD. */
|
||||
#define UTMP_FILE _PATH_UTMP
|
||||
#else /* !_PATH_UTMP */
|
||||
#define UTMP_FILE "/etc/utmp"
|
||||
#endif /* !_PATH_UTMP */
|
||||
#endif /* !UTMP_FILE */
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 64
|
||||
#endif
|
||||
|
||||
#define MESG_BIT 020 /* Group write bit. */
|
||||
|
||||
char *ttyname ();
|
||||
|
||||
char *idle_string ();
|
||||
char *xmalloc ();
|
||||
struct utmp *search_entries ();
|
||||
void error ();
|
||||
void list_entries ();
|
||||
void print_entry ();
|
||||
void print_heading ();
|
||||
void scan_entries ();
|
||||
void usage ();
|
||||
void who ();
|
||||
void who_am_i ();
|
||||
|
||||
/* The name this program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, display only a list of usernames and count of
|
||||
the users logged on.
|
||||
Ignored for `who am i'. */
|
||||
int short_list;
|
||||
|
||||
/* If nonzero, display the hours:minutes since each user has touched
|
||||
the keyboard, or "." if within the last minute, or "old" if
|
||||
not within the last day. */
|
||||
int include_idle;
|
||||
|
||||
/* If nonzero, display a line at the top describing each field. */
|
||||
int include_heading;
|
||||
|
||||
/* If nonzero, display a `+' for each user if mesg y, a `-' if mesg n,
|
||||
or a `?' if their tty cannot be statted. */
|
||||
int include_mesg;
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{"count", 0, NULL, 'q'},
|
||||
{"idle", 0, NULL, 'u'},
|
||||
{"heading", 0, NULL, 'H'},
|
||||
{"message", 0, NULL, 'T'},
|
||||
{"mesg", 0, NULL, 'T'},
|
||||
{"writable", 0, NULL, 'T'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int optc, longind;
|
||||
int my_line_only = 0;
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "imqsuwHT", longopts, &longind))
|
||||
!= EOF)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'm':
|
||||
my_line_only = 1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
short_list = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'u':
|
||||
include_idle = 1;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
include_heading = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
case 'T':
|
||||
include_mesg = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir ("/dev"))
|
||||
error (1, errno, "cannot change directory to /dev");
|
||||
|
||||
switch (argc - optind)
|
||||
{
|
||||
case 0: /* who */
|
||||
if (my_line_only)
|
||||
who_am_i (UTMP_FILE);
|
||||
else
|
||||
who (UTMP_FILE);
|
||||
break;
|
||||
|
||||
case 1: /* who <utmp file> */
|
||||
if (my_line_only)
|
||||
who_am_i (argv[optind]);
|
||||
else
|
||||
who (argv[optind]);
|
||||
break;
|
||||
|
||||
case 2: /* who <blurf> <glop> */
|
||||
who_am_i (UTMP_FILE);
|
||||
break;
|
||||
|
||||
default: /* lose */
|
||||
usage ();
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static struct utmp *utmp_contents;
|
||||
|
||||
/* Display a list of who is on the system, according to utmp file FILENAME. */
|
||||
|
||||
void
|
||||
who (filename)
|
||||
char *filename;
|
||||
{
|
||||
int users;
|
||||
|
||||
users = read_utmp (filename);
|
||||
if (short_list)
|
||||
list_entries (users);
|
||||
else
|
||||
scan_entries (users);
|
||||
}
|
||||
|
||||
/* Read the utmp file FILENAME into UTMP_CONTENTS and return the
|
||||
number of entries it contains. */
|
||||
|
||||
int
|
||||
read_utmp (filename)
|
||||
char *filename;
|
||||
{
|
||||
register int desc;
|
||||
struct stat file_stats;
|
||||
|
||||
desc = open (filename, O_RDONLY, 0);
|
||||
if (desc < 0)
|
||||
error (1, errno, "%s", filename);
|
||||
|
||||
fstat (desc, &file_stats);
|
||||
if (file_stats.st_size > 0)
|
||||
utmp_contents = (struct utmp *) xmalloc ((unsigned) file_stats.st_size);
|
||||
else
|
||||
{
|
||||
close (desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use < instead of != in case the utmp just grew. */
|
||||
if (read (desc, utmp_contents, file_stats.st_size) < file_stats.st_size)
|
||||
error (1, errno, "%s", filename);
|
||||
|
||||
if (close (desc))
|
||||
error (1, errno, "%s", filename);
|
||||
|
||||
return file_stats.st_size / sizeof (struct utmp);
|
||||
}
|
||||
|
||||
/* Display a line of information about entry THIS. */
|
||||
|
||||
void
|
||||
print_entry (this)
|
||||
struct utmp *this;
|
||||
{
|
||||
struct stat stats;
|
||||
time_t last_change;
|
||||
char mesg;
|
||||
char line[sizeof (this->ut_line) + 1];
|
||||
|
||||
strncpy (line, this->ut_line, sizeof (this->ut_line));
|
||||
line[sizeof (this->ut_line)] = 0;
|
||||
if (stat (line, &stats) == 0)
|
||||
{
|
||||
mesg = (stats.st_mode & MESG_BIT) ? '+' : '-';
|
||||
last_change = stats.st_atime;
|
||||
}
|
||||
else
|
||||
{
|
||||
mesg = '?';
|
||||
last_change = 0;
|
||||
}
|
||||
|
||||
printf ("%-*.*s",
|
||||
sizeof (this->ut_name), sizeof (this->ut_name),
|
||||
this->ut_name);
|
||||
if (include_mesg)
|
||||
printf (" %c ", mesg);
|
||||
printf (" %-*.*s",
|
||||
sizeof (this->ut_line), sizeof (this->ut_line),
|
||||
this->ut_line);
|
||||
printf (" %-12.12s", ctime (&this->ut_time) + 4);
|
||||
if (include_idle)
|
||||
{
|
||||
if (last_change)
|
||||
printf (" %s", idle_string (last_change));
|
||||
else
|
||||
printf (" . ");
|
||||
}
|
||||
#ifdef HAVE_UT_HOST
|
||||
if (this->ut_host[0])
|
||||
printf (" (%-.*s)", sizeof (this->ut_host), this->ut_host);
|
||||
#endif
|
||||
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* Print the username of each valid entry and the number of valid entries
|
||||
in `utmp_contents', which should have N elements. */
|
||||
|
||||
void
|
||||
list_entries (n)
|
||||
int n;
|
||||
{
|
||||
register struct utmp *this = utmp_contents;
|
||||
register int entries = 0;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (this->ut_name[0]
|
||||
#ifdef USER_PROCESS
|
||||
&& this->ut_type == USER_PROCESS
|
||||
#endif
|
||||
)
|
||||
{
|
||||
printf ("%s ", this->ut_name);
|
||||
entries++;
|
||||
}
|
||||
this++;
|
||||
}
|
||||
printf ("\n# users=%u\n", entries);
|
||||
}
|
||||
|
||||
void
|
||||
print_heading ()
|
||||
{
|
||||
struct utmp *ut;
|
||||
|
||||
printf ("%-*s ", sizeof (ut->ut_name), "USER");
|
||||
if (include_mesg)
|
||||
printf ("MESG ");
|
||||
printf ("%-*s ", sizeof (ut->ut_line), "LINE");
|
||||
printf ("LOGIN-TIME ");
|
||||
if (include_idle)
|
||||
printf ("IDLE ");
|
||||
printf ("FROM\n");
|
||||
}
|
||||
|
||||
/* Display `utmp_contents', which should have N entries. */
|
||||
|
||||
void
|
||||
scan_entries (n)
|
||||
int n;
|
||||
{
|
||||
register struct utmp *this = utmp_contents;
|
||||
|
||||
if (include_heading)
|
||||
print_heading ();
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (this->ut_name[0]
|
||||
#ifdef USER_PROCESS
|
||||
&& this->ut_type == USER_PROCESS
|
||||
#endif
|
||||
)
|
||||
print_entry (this);
|
||||
this++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search `utmp_contents', which should have N entries, for
|
||||
an entry with a `ut_line' field identical to LINE.
|
||||
Return the first matching entry found, or NULL if there
|
||||
is no matching entry. */
|
||||
|
||||
struct utmp *
|
||||
search_entries (n, line)
|
||||
int n;
|
||||
char *line;
|
||||
{
|
||||
register struct utmp *this = utmp_contents;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (this->ut_name[0]
|
||||
#ifdef USER_PROCESS
|
||||
&& this->ut_type == USER_PROCESS
|
||||
#endif
|
||||
&& !strncmp (line, this->ut_line, sizeof (this->ut_line)))
|
||||
return this;
|
||||
this++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Display the entry in utmp file FILENAME for this tty on standard input,
|
||||
or nothing if there is no entry for it. */
|
||||
|
||||
void
|
||||
who_am_i (filename)
|
||||
char *filename;
|
||||
{
|
||||
register struct utmp *utmp_entry;
|
||||
char hostname[MAXHOSTNAMELEN + 1];
|
||||
char *tty;
|
||||
|
||||
if (gethostname (hostname, MAXHOSTNAMELEN + 1))
|
||||
*hostname = 0;
|
||||
|
||||
if (include_heading)
|
||||
{
|
||||
printf ("%*s ", strlen (hostname), " ");
|
||||
print_heading ();
|
||||
}
|
||||
|
||||
tty = ttyname (0);
|
||||
if (tty == NULL)
|
||||
return;
|
||||
tty += 5; /* Remove "/dev/". */
|
||||
|
||||
utmp_entry = search_entries (read_utmp (filename), tty);
|
||||
if (utmp_entry == NULL)
|
||||
return;
|
||||
|
||||
printf ("%s!", hostname);
|
||||
print_entry (utmp_entry);
|
||||
}
|
||||
|
||||
/* Return a string representing the time between WHEN and the time
|
||||
that this function is first run. */
|
||||
|
||||
char *
|
||||
idle_string (when)
|
||||
time_t when;
|
||||
{
|
||||
static time_t now = 0;
|
||||
static char idle[10];
|
||||
time_t seconds_idle;
|
||||
|
||||
if (now == 0)
|
||||
time (&now);
|
||||
|
||||
seconds_idle = now - when;
|
||||
if (seconds_idle < 60) /* One minute. */
|
||||
return " . ";
|
||||
if (seconds_idle < (24 * 60 * 60)) /* One day. */
|
||||
{
|
||||
sprintf (idle, "%02d:%02d",
|
||||
seconds_idle / (60 * 60),
|
||||
(seconds_idle % (60 * 60)) / 60);
|
||||
return idle;
|
||||
}
|
||||
return " old ";
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
fprintf (stderr, "\
|
||||
Usage: %s [-imqsuwHT] [--count] [--idle] [--heading] [--message] [--mesg]\n\
|
||||
[--writable] [file] [am i]\n",
|
||||
program_name);
|
||||
exit (1);
|
||||
}
|
49
src/whoami.c
Normal file
49
src/whoami.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* whoami -- print effective userid
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Equivalent to `id -un'. */
|
||||
/* Written by Richard Mlynarik. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include "system.h"
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register struct passwd *pw;
|
||||
register uid_t uid;
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
fprintf (stderr, "Usage: %s\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
uid = geteuid ();
|
||||
pw = getpwuid (uid);
|
||||
if (pw)
|
||||
{
|
||||
puts (pw->pw_name);
|
||||
exit (0);
|
||||
}
|
||||
fprintf (stderr,"%s: cannot find username for UID %u\n", argv[0], uid);
|
||||
exit (1);
|
||||
}
|
39
src/yes.c
Normal file
39
src/yes.c
Normal file
@ -0,0 +1,39 @@
|
||||
/* yes - output a string repeatedly until killed
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* David MacKenzie <djm@ai.mit.edu> */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc == 1)
|
||||
while (1)
|
||||
puts ("y");
|
||||
|
||||
while (1)
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
fputs (argv[i], stdout);
|
||||
putchar (i == argc - 1 ? '\n' : ' ');
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user