home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
diskutil
/
docp
/
docp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
52KB
|
2,235 lines
/*
docp.c - Directory-Oriented CoPy
Fancy file copy program for Atari ST
Copywrite 1992, Roy Bixler
Originally by: David Oertel
Atari ST port, overall cheez-whiz: Roy Bixler
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 1, 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 <ctype.h>
#include <fcntl.h>
#include <osbind.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
#include <stat.h>
#include <unistd.h>
#define MINT_LIB
#ifdef MINT_LIB
/* long _read(int, void *, long); */
/* long _write(int, const void *, long); */
#define read(x, y, z) _read(x, y, z)
#define write(x, y, z) _write(x, y, z)
#else
#define read(x, y, z) lread(x, y, z)
#define write(x, y, z) lwrite(x, y, z)
#endif
#define MAXDIR 128
#define MAXPATH 128
#define OPT_LIST "abcdfghijlmnorstvwz?"
#define GET_OPT_LIST "AaBbCcD:d:F:f:GgHhIiJjLlMmNnOoRrSsTtVvW:w:Zz?"
#define DOT_NOTATION(dir) !strcmp(dir, ".")
#define MAX_BUF 0xfffeU
#include "docp.h"
#include "doc.h"
#include "elib.h"
#include "protypes.h"
/* options */
extern int Optind;
extern char *optarg;
long Options = 0L;
char Cur_source_dir[FILENAME_MAX], Org_dest_dir[FILENAME_MAX];
ENTRY *Ptr;
void *Buf_ptr;
void *File_buf;
int Reading_flag; /* set if 'reading:' has been printed last
* reset if 'writing:' has been printed last */
/* modes of date compare via 'd' option */
#define D_BEFORE 1
#define D_ON 2
#define D_AFTER 4
DATE_NODE *Fdate; /* used to store date entered via 'd' option */
TIME_NODE *Ftime; /* used to store time entered via 'w' option */
FILE *From_file_ptr; /* file containing file list ('-f' option) */
int Retry = 0; /* set if target disk is full and user chooses to
* continue */
int Copied_a_file = 0; /* set if at least one file was copied */
ENTRY *Src_tab[HASH_TAB_SIZE]; /* contains source-file names */
ENTRY *Dst_tab[HASH_TAB_SIZE]; /* contains destination-file names */
typedef struct file_list {
char *string;
struct file_list *next;
} STDIN_TOKEN;
/* linked list globals containing file list from stdin */
STDIN_TOKEN *Stdin_list_head = NULL;
STDIN_TOKEN *Stdin_list_tail = NULL;
STDIN_TOKEN *Stdin_list_current = NULL;
int main(int argc, char *argv[])
{
char src_dir[FILENAME_MAX];
char dst_dir[FILENAME_MAX];
unsigned long buf_size;
int num_args;
char **argv_ptr;
char *all[2] = { "*.*", NULL };
get_flags(argv, argc);
check_flags();
check_and_format_dirs(argc, argv, src_dir, dst_dir);
check_target_removeable(dst_dir);
File_buf = get_file_buf(&buf_size);
Buf_ptr = File_buf;
argv += Optind + 2;
num_args = argc - Optind - 2;
argv_ptr = argv;
if (Options & O_FROM_STDIN)
build_stdin_file_list(&num_args);
else if (Options & O_FROM_FILE){
char buf[80];
num_args = 0;
while (fgets(buf, 79, From_file_ptr) != NULL)
num_args++;
rewind(From_file_ptr);
} else if (num_args == 0) {
num_args = 1;
argv_ptr = all;
}
strcpy(Org_dest_dir, dst_dir);
if (Options & O_CHECK)
fprintf(stdout, "The following files would be copied or moved:\n");
else if (Options & O_ZAPTARGET)
zap_target(dst_dir, 1);
copy_files(src_dir, dst_dir, argv_ptr,
num_args, File_buf, buf_size);
write_buffer(File_buf);
clear_archive_bits(src_dir);
if (!Copied_a_file)
fprintf(stdout, "no files copied\n");
free(File_buf);
exit(0);
}
/*
* check_and_format_dirs()
*
* Input:
* argc - command line argument count
* argv - command line arguments
* Optind - argument index from getopt()
* Output:
* src_dir - source directory name
* dst_dir - destination directory name
* Comments:
* The source and destination directories are formatted
* The source directory is checked for existence
* The destination directory is created if it doesn't exist
* The two directories are checked to insure that they are
* different
* The destination is checked to insure that it is not a
* subdirectory of the source
*/
void check_and_format_dirs(int argc, char *argv[],
char *src_dir, char *dst_dir)
{
if ((argc-Optind) < 2)
usage();
strcpy(src_dir, argv[Optind]);
check_if_dir_exists(src_dir, 0);
strcpy(dst_dir, argv[Optind + 1]);
check_if_dir_exists(dst_dir, 1);
format_dir(argv[Optind], '\1', src_dir);
format_dir(argv[Optind + 1], '\1', dst_dir);
check_if_dirs_compatible(src_dir, dst_dir);
}
/*
* check_target_removeable()
*
* Input:
* dst_dir - destination directory name
* Output:
* Options - will be modified if target directory is removeable
* (i.e. a floppy disk)
*/
void check_target_removeable(char *dst_dir)
{
char dst_drive;
if (islower(dst_drive = dst_dir[0]))
dst_drive = toupper(dst_drive);
if ((dst_drive == 'A') || (dst_drive == 'B'))
Options |= O_TARGET_REMOVEABLE;
}
/*
* check_if_dirs_compatible()
*
* Input:
* src_dir - The formatted source directory name
* dst_dir - The formatted destination directory name
* Comments:
* terminates if:
* 1 - The two directories are the same
* 2 - The destination is a subdirectory of
* the source
*/
void check_if_dirs_compatible(char *src_dir, char *dst_dir)
{
if (Options & O_CHECK)
return;
if (!strcmp(src_dir, dst_dir)){
fprintf(stderr,
"source and destination directories are the same\n");
exit(-1);
}
if ((Options & O_RECURSIVE) &&
!strncmp(src_dir, dst_dir, strlen(src_dir))){
fprintf(stderr,
"destination directory is a subdirectory of the source directory \nwhile in recursive mode\n");
exit(-1);
}
}
/*
* check_if_dir_exists()
*
* Input:
* dir - the directory name
* is_dest - flag set if directory is a destination directory
* Comments:
* creates destination directory if it doesn't exist
* terminates if the source directory doesn't exist
*/
void check_if_dir_exists(char *dir, int is_dest)
{
int retval;
struct stat statbuf;
if (!((DOT_NOTATION(dir)) ||
((!stat(dir, &statbuf)) && (statbuf.st_mode & S_IFDIR))))
if ((is_dest) && ((Options & O_BATCH) ||
(printf("directory %s does not exist - ", dir),
ask_user("create it (Y/N/Q) ? "))))
create_dir(dir);
else {
printf("docp: directory '%s' does not exist\n", dir);
exit(-1);
}
}
/*
* create_dir()
*
* Input:
* dir - the directory to be created
* Comments:
* creates destination directory
*/
void create_dir(char *dir)
{
int retval;
char next_dir[MAXDIR], *p;
strcpy(next_dir, dir);
for (p=next_dir; *p; p++)
if (*p == '/')
*p = '\\';
p = next_dir;
while ((p = strchr(p, '\\')) != NULL) {
*p = '\0';
mkdir(next_dir, 0);
*p++ = '\\';
}
;
if (mkdir(dir, 0) == -1){
fprintf(stderr, "cannot create directory '%s'\n", dir);
exit(-1);
}
else if (Options & O_VERBOSE)
printf("created directory '%s'\n", dir);
}
/*
* return_to_cur_dir()
*
* Input:
* cur_dir - the current working directory
* other_dir - the current working directory of the
* destination drive
* Comments:
* returns to current working directory
*/
void return_to_cur_dir(char *cur_dir)
{
chdir(cur_dir);
}
/*
* root_dir()
*
* Input:
* dir - the directory to be checked
* Output:
* returns :
* 1 - if 'dir' is a root directory
* 0 - otherwise
*/
int root_dir(char *dir)
{
if (((*(dir + 1) == ':') && (strlen(dir) == 2)) ||
((strlen(dir) == 3) && (*(dir + 2) == '\\')))
return(1);
else
return(0);
}
/*
* copy_files()
*
* Input:
* src_dir - the source directory
* dst_dir - the destination directory
* file_spec - the command-line file list
* num_args - the number of arguments in the file list
* file_buf - the buffer for reading and writing files
* buf_size - the size of 'file_buf'
* Comments:
* copy or move the files from the source directory to the
* destination directory
*/
void copy_files(char *src_dir, char *dst_dir, char *file_spec[], int num_args,
void *file_buf, unsigned long buf_size)
{
struct _dta fblk;
char ref_list[FILENAME_MAX];
char src_file[FILENAME_MAX], dst_file[FILENAME_MAX];
int done, index;
long file_size;
char *file;
strcpy(Cur_source_dir, src_dir);
build_hash_tab(src_dir, Src_tab, num_args, file_spec);
build_hash_tab(dst_dir, Dst_tab, num_args, file_spec);
file = get_first(&index);
while (file != NULL) {
strcpy(src_file, src_dir);
strcat(src_file, file);
strcpy(dst_file, dst_dir);
strcat(dst_file, file);
if (should_file_copy(file, src_file))
if (Options & O_CHECK)
fprintf(stdout, "\t%s -> %s\n", src_file, dst_file);
else
copy_file(Ptr, dst_file, src_file, buf_size);
else
report_not_copied(src_file);
file = get_next(&index);
}
clear_archive_bits(src_dir);
copy_sub_dirs(src_dir, dst_dir, file_spec, num_args, file_buf, buf_size);
if (Options & O_MOVE)
rmdir(src_dir); /* don't try too hard, but do it if we can ... */
if (Options & O_ZAPTARGET)
rmdir(dst_dir);
}
/*
* report_not_copied()
*
* Input:
* src_dir - source directory
* Comments:
* reports that a file was not copied
*/
void report_not_copied(char *src_file)
{
if ((Options & O_X_VERBOSE) && !(Options & O_CHECK)){
if (!Reading_flag){
fprintf(stdout, "reading:\n");
Reading_flag = 1;
}
printf("\t%s ** NOT COPIED **\n", src_file);
}
}
/*
* zap_target()
*
* Input:
* dst_dir - the destination directory
* print_heading - true on entry, false for recursive calls
* Comments:
* zaps the files in the target directory
*/
void zap_target(char *dst_dir, int print_banner)
{
int done, attrib = 0, i;
struct _dta *odta, fblk;
char dst_file[FILENAME_MAX], buf[MAXPATH+20];
odta = (struct _dta *) Fgetdta();
Fsetdta(&fblk);
if (Options & O_COPY_HIDDEN)
attrib |= (FA_HIDDEN|FA_SYSTEM);
if ((Options & O_RECURSIVE) && (!(Options & O_GATHER)))
attrib |= FA_DIR;
strcpy(dst_file, dst_dir);
if (dst_file[(i = strlen(dst_file))-1] != '\\') {
strcat(dst_file, "\\");
i++;
}
strcat(dst_file, "*.*");
done = Fsfirst(dst_file, attrib);
if ((!done) && (Options & O_VERBOSE) && (print_banner))
printf("deleting:\n");
while (!done) {
strcpy(dst_file+i, fblk.dta_name);
if (fblk.dta_attribute & FA_DIR) {
if (!is_special(fblk.dta_name)) {
zap_target(dst_file, 0);
rmdir(dst_file);
}
}
else if ((!(Options & O_INTERACTIVE)) ||
(sprintf(buf, "Delete file %s (Y/N/Q) ?", dst_file),
ask_user(buf))) {
if (Options & O_VERBOSE)
printf("\t%s\n", dst_file);
delete_file(dst_file, '\1');
}
done = Fsnext();
}
Fsetdta(odta);
}
/*
* build_hash_tab()
*
* Input:
* dir - the directory for which to table will be built
* num_args - the number of arguments in the file list
* file_spec - the command-line file list
* Output:
* hash_tab - the hash table containing all the file names
* of the directory 'dir'
* Comments:
* builds a hash table containing all the file names of a
* directory specified by the command-line file list.
* First it adds all the names specified by the file
* list, then it subtracts those specified
* by the '-' notation in the file list.
*/
void build_hash_tab(char *dir, ENTRY *hash_tab[],
int num_args, char *file_spec[])
{
add_to_hash_tab(dir, hash_tab, 1, num_args, file_spec);
take_from_hash_tab(dir, hash_tab, num_args, file_spec);
}
/*
* add_to_hash_tab()
*
* Input:
* dir - the directory for which to table will be built
* from_file_poss - is it possible to get file list from a file?
* num_args - the number of arguments in the file list
* file_spec - the command-line file list
* Output:
* hash_tab - the hash table containing all the file names
* of the directory 'dir'
* Comments:
* adds all the files specified by the file list and within
* the directory 'dir' to the hash table.
*/
void add_to_hash_tab(char *dir, ENTRY *hash_tab[],
int from_file_poss, int num_args, char *file_spec[])
{
int done;
struct _dta *odta, fblk;
char ref_list[FILENAME_MAX];
int i;
int files_added = 0;
char buf[80];
if ((from_file_poss) && (Options & O_FROM_STDIN))
Stdin_list_current = Stdin_list_head;
if ((from_file_poss) && (Options & O_FROM_FILE))
rewind(From_file_ptr);
odta = (struct _dta *) Fgetdta();
Fsetdta(&fblk);
for (i = 0; i < num_args; i++){
strcpy(ref_list, dir);
get_file_spec(buf, file_spec, i);
if (*buf != '-'){
int attrib = 0;
files_added = 1;
strcat(ref_list, (*buf == '\\') ? buf+1 : buf);
if (Options & O_COPY_HIDDEN)
attrib |= (FA_HIDDEN|FA_SYSTEM);
done = Fsfirst(ref_list, attrib);
while (!done) {
if (find_entry(fblk.dta_name, hash_tab) == NULL)
add_entry(&fblk, hash_tab);
done = Fsnext();
}
}
}
if (!files_added){
char *all[2] = { "*.*", NULL };
add_to_hash_tab(dir, hash_tab, 0, 1, all);
}
Fsetdta(odta);
}
/*
* take_from_hash_tab()
*
* Input:
* dir - the directory for which to table will be built
* num_args - the number of arguments in the file list
* file_spec - the command-line file list
* Output:
* hash_tab - the hash table containing all the file names
* of the directory 'dir' and specified by the file
* list, 'file_spec'.
* Comments:
* takes all the files specified by using the '-' notation
* and within the directory 'dir' from the hash table.
*/
void take_from_hash_tab(char *dir, ENTRY *hash_tab[],
int num_args, char *file_spec[])
{
int done;
struct _dta *odta, fblk;
char ref_list[FILENAME_MAX];
int i;
char buf[80];
odta = (struct _dta *) Fgetdta();
Fsetdta(&fblk);
if (Options & O_FROM_STDIN)
Stdin_list_current = Stdin_list_head;
if (Options & O_FROM_FILE)
rewind(From_file_ptr);
for (i = 0; i < num_args; i++){
strcpy(ref_list, dir);
get_file_spec(buf, file_spec, i);
if (*buf == '-'){
int attrib = 0;
strcat(ref_list, buf + 1);
if (Options & O_COPY_HIDDEN)
attrib |= (FA_HIDDEN|FA_SYSTEM);
done = Fsfirst(ref_list, attrib);
while (!done){
remove_entry(fblk.dta_name, hash_tab);
done = Fsnext();
}
}
}
Fsetdta(odta);
}
/*
* get_file_spec()
*
* Input:
* file_spec - the command-line file list
* i - index into the command-line file list
* Output:
* buf - the next token from the command line file list
* Comments:
* gets the next token from the command-line file list
*/
void get_file_spec(char *buf, char *file_spec[], int i)
{
if (Options & O_FROM_STDIN){
strcpy(buf, Stdin_list_current->string);
Stdin_list_current = Stdin_list_current->next;
} else if (Options & O_FROM_FILE){
fgets(buf, 79, From_file_ptr);
zap_trailing_nl(buf, 79, From_file_ptr); /* clobber newline */
} else {
strcpy(buf, file_spec[i]);
}
}
/*
* add_entry()
*
* Input:
* fblk - structure containing the file name, date, and time
* Output:
* hash_tab - add entry to this array of pointers
* Comments:
* ands a file name along with its date and time to a hash table
*/
void add_entry(struct _dta *fblk, ENTRY *hash_tab[])
{
int bucket;
ENTRY *ptr;
bucket = hashpjw(fblk->dta_name);
if (hash_tab[bucket] == NULL){
if ((hash_tab[bucket] = (ENTRY *)malloc(sizeof(ENTRY))) ==
NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
hash_tab[bucket]->next = NULL;
} else {
if ((ptr = (ENTRY *)malloc(sizeof(ENTRY))) == NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
ptr->next = hash_tab[bucket];
hash_tab[bucket] = ptr;
}
strcpy(hash_tab[bucket]->name, fblk->dta_name);
hash_tab[bucket]->attr = fblk->dta_attribute;
hash_tab[bucket]->copied = 0;
hash_tab[bucket]->fdate = fblk->dta_date;
hash_tab[bucket]->ftime = fblk->dta_time;
}
/*
* get_first()
*
* Input:
* none
* Output:
* index - index to first hash table bucket. Each bucket is a
* linked-list of structures, one for each file.
* Ptr - pointer to first hash table file entry
* returns - the name of the first file in the hash table
* Comments:
* selects the proper hash table and finds its first entry
*/
char *get_first(int *index)
{
*index = 0;
Ptr = (Options & O_TARGET_DIR) ? Dst_tab[0] : Src_tab[0];
move_Ptr(index);
return (Ptr == NULL) ? NULL : Ptr->name;
}
/*
* get_next()
*
* Input:
* index - index to current hash-table bucket. Each bucket is a
* linked-list of structures, one for each file.
* Ptr - pointer to current hash-table file entry
* Output:
* index - index to next hash table bucket (may not be different
* from current bucket).
* Ptr - pointer to next hash table file entry
* returns - the name of the next file in the hash table
*
* Comments:
* finds the next entry in the currently selected hash table
* of file names
*/
char *get_next(int *index)
{
if (Ptr != NULL)
Ptr = Ptr->next;
move_Ptr(index);
return (Ptr == NULL) ? NULL : Ptr->name;
}
/*
* move_Ptr()
*
* Input:
* index - index to current hash-table bucket. Each bucket is a
* linked-list of structures, one for each file.
* Ptr - pointer to hash table file entry
* Output:
* index - index to hash-table bucket.
* Ptr - pointer to hash table file entry
* Comments:
* finds the next non-NULL entry, only if the hash-table
* pointer is NULL
*/
void move_Ptr(int *index)
{
if (Ptr == NULL)
for ((*index)++; (*index < HASH_TAB_SIZE); (*index)++)
if ((Ptr = ((Options & O_TARGET_DIR) ? Dst_tab[*index]
: Src_tab[*index])) != NULL)
break;
}
/*
* clear_archive_bits
*
* given a source directory, go through the hash table (up to the value
* of Ptr on entry to this function) and clear the archive bits of all
* file entries. This has the desired effect of clearing archive bits
* of all source files which have been copied.
*/
void clear_archive_bits(char *src_dir)
{
ENTRY *Org_Ptr = Ptr;
char source_file[FILENAME_MAX], *cur_name;
int index, n;
if ((Options & O_ARCHIVE) && (!(Options & O_CHECK))) {
n = strlen(src_dir);
strcpy(source_file, src_dir);
cur_name = get_first(&index);
while (Ptr != NULL) {
if (Ptr->copied) {
strcat(source_file, cur_name);
Fattrib(source_file, 1, ((Ptr->copied)&(~FA_CHANGED)));
source_file[n] = '\0';
}
if (Org_Ptr == Ptr)
break;
else
cur_name = get_next(&index);
}
}
}
/*
* clear_hash_tab()
*
* Input:
* hash_tab - the hash table to be cleared
* Output:
* hash_tab - with all its entries cleared and all its
* buckets set to NULL
* Comments:
* removes all entries from a hash table
*/
void clear_hash_tab(ENTRY *hash_tab[])
{
int i;
ENTRY *ptr, *temp;
for (i = 0; i < HASH_TAB_SIZE; i++){
ptr = hash_tab[i];
while (ptr != NULL){
temp = ptr;
ptr = ptr->next;
free(temp);
}
hash_tab[i] = NULL;
}
}
/*
* remove_entry()
*
* Input:
* file - the name of the file to be removed
* hash_tab - the hash table from which the file is to be
* removed
* Output:
* hash_tab - the hash table with the file removed
* Comments:
* removes one entry from a hash table
*/
void remove_entry(char *file, ENTRY *hash_tab[])
{
int bucket;
ENTRY *ptr, *temp;
ENTRY **lastptr;
bucket = hashpjw(file);
if (hash_tab[bucket] != NULL) {
ptr = hash_tab[bucket];
lastptr = &(hash_tab[bucket]);
while(ptr != NULL){
if (!strcmp(file, ptr->name)){
*lastptr = ptr->next;
free(ptr);
break;
}
lastptr = &(ptr->next);
ptr = ptr->next;
}
}
}
/*
* find_entry()
*
* Input:
* file - the name of the file to be found
* hash_tab - the hash table which is to be searched
* Output:
* returns - a pointer to the entry in the hash table,
* or NULL if not found
* Comments:
* finds an entry in the hash table
*/
ENTRY *find_entry(char *file, ENTRY *hash_tab[])
{
int bucket;
ENTRY *ptr, *temp;
bucket = hashpjw(file);
if (hash_tab[bucket] == NULL){
ptr = NULL;
} else {
ptr = hash_tab[bucket];
while(ptr != NULL){
if (!strcmp(file, ptr->name)){
break;
}
ptr = ptr->next;
}
}
return(ptr);
}
/*
* copy_sub_dirs()
*
* Input:
* src_dir - the source directory
* dst_dir - the destination directory
* file_spec - the command-line file list
* num_args - the number of arguments in the file list
* file_buf - the buffer for reading and writing files
* buf_size - the size of 'file_buf'
* Comments:
* copies the files in the sub-directories if the recursive
* mode is specified
*/
void copy_sub_dirs(char *src_dir, char *dst_dir, char *file_spec[],
int num_args, void *file_buf, unsigned long buf_size)
{
int done;
char ref_list[FILENAME_MAX];
struct _dta *odta, fblk;
if (Options & O_RECURSIVE){
strcpy(ref_list, src_dir);
strcat(ref_list, "*.*");
odta = (struct _dta *) Fgetdta();
Fsetdta(&fblk);
done = Fsfirst(ref_list, FA_DIR);
while (!done){
if ((fblk.dta_attribute & FA_DIR) && (!is_special(fblk.dta_name))) {
char new_src_dir[FILENAME_MAX], new_dst_dir[FILENAME_MAX];
if (should_dir_copy(src_dir, dst_dir, fblk.dta_name,
new_src_dir, new_dst_dir)){
clear_hash_tab(Src_tab);
clear_hash_tab(Dst_tab);
copy_files(new_src_dir, new_dst_dir,
file_spec, num_args,
file_buf, buf_size);
}
}
done = Fsnext();
}
Fsetdta(odta);
}
}
/*
* should_dir_copy()
*
* Input:
* src_dir - the full path of the current source directory
* dst_dir - the full path of the current destination directory
* name - the name of the sub-directory
* Output:
* new_src_dir - the full path of the source sub-directory
* new_dst_dir - the full path of the destination sub-directory
* returns - 1 if sub-directory should be copied
* 0 if sub-directory should NOT be copied
* Comments:
* determines whether a sub-directory should be copied
*/
int should_dir_copy(char *src_dir, char *dst_dir, char *name,
char *new_src_dir, char *new_dst_dir)
{
struct stat src_buf, dst_buf;
int ret_src, ret_dst;
int status;
int ret_val;
strcpy(new_src_dir, src_dir);
strcat(new_src_dir, name);
strcpy(new_dst_dir, dst_dir);
if (Options & O_GATHER)
new_dst_dir[strlen(new_dst_dir) - 1] = '\0'; /* chop slash */
else
strcat(new_dst_dir, name);
ret_src = stat(new_src_dir, &src_buf);
ret_dst = stat(new_dst_dir, &dst_buf);
if (ret_src == -1) /* sub dir does not exist in source dir */
ret_val = 0;
else if (!(src_buf.st_mode & S_IFDIR)) /* src dir is a file */
ret_val = 0;
else if (Options & (O_GATHER|O_CHECK))
ret_val = 1;
else if (ret_dst == -1) { /* destination dir does not exist */
status = mkdir(new_dst_dir, 0);
if (status) {
fprintf(stderr, "unable to create directory\n");
exit(-1);
}
ret_val = 1;
} else
ret_val = 1;
strcat(new_src_dir, "\\");
strcat(new_dst_dir, "\\");
return(ret_val);
}
/*
* should_file_copy()
*
* Input:
* file - name of file to be copied
* src_file - full path of file to be copied
* Output:
* returns: 1 if file should be copied/moved
* 0 if file should NOT be copied/moved
* Comments:
* looks up the file name in the source and destination
* hash tables and determines whether a file should be
* copied/moved
*/
int should_file_copy(char *file, char *src_file)
{
ENTRY *src, *dst;
/* source does not exit */
if ((src = find_entry(file, Src_tab)) != NULL) {
if (Options & O_DATE_CHECK)
if (!(within_date_range(src)))
return 0;
if (Options & O_ARCHIVE)
if (!(src->attr & FA_CHANGED))
return 0;
if ((dst = find_entry(file, Dst_tab)) != NULL) {
if ((Options & (O_CP_IF_SRC_NEWER|O_COPY_IF_SRC_OLDER)) ==
(O_CP_IF_SRC_NEWER|O_COPY_IF_SRC_OLDER))
return 0;
if (Options & O_CP_IF_SRC_NEWER)
if (cmptime_entry(src, dst) <= 0L)
return 0;
if (Options & O_COPY_IF_SRC_OLDER)
if (cmptime_entry(src, dst) >= 0L)
return 0;
}
}
else /* source file missing? of course don't copy (something's fishy!) */
return 0;
if (Options & O_INTERACTIVE) {
char buf[MAXPATH + 20];
sprintf(buf, "copy %s (Y/N/Q) ? ", src_file);
return ask_user(buf); /* user has the final say-so */
}
return 1;
}
/*
* cmptime_entry
*
* given two files, return positive if the first has a more recent modification
* date/time, zero if the files have the same modification date/time or
* negative if the second is more recent.
*/
long cmptime_entry(ENTRY *a, ENTRY *b)
{
return (((unsigned long)a->fdate) << 16 | (unsigned long)a->ftime) -
(((unsigned long)b->fdate) << 16 | (unsigned long)b->ftime);
}
int within_date_range(ENTRY *src)
{
int retval = 1;
DATE_NODE *d = Fdate;
TIME_NODE *t = Ftime;
int saw_after_or_before = 0;
/* AND the 'before' and 'after' modes */
while (d != NULL){
if ((d->mode & D_BEFORE) || (d->mode & D_AFTER))
saw_after_or_before = 1;
if (((d->mode & D_BEFORE) && (src->fdate >= d->fdate)) ||
((d->mode & D_AFTER) && (src->fdate <= d->fdate))){
retval = 0;
}
d = d->next;
}
if (!saw_after_or_before)
retval = 0;
/* OR the 'on' modes */
d = Fdate;
while (d != NULL){
if ((d->mode & D_ON) && (src->fdate == d->fdate))
retval = 1;
d = d->next;
}
/* AND the 'before' and 'after' modes */
if (retval)
while (t != NULL){
if (((t->mode & D_BEFORE) &&
(src->ftime >= t->ftime)) ||
((t->mode & D_AFTER) &&
(src->ftime <= t->ftime)))
retval = 0;
t = t->next;
}
return retval;
}
/*
* file_exists()
*
* Input:
* name - full path of file
* Output:
* returns: 1 if file exists
* 0 if file does NOT exist
*/
int file_exists(char *name)
{
return (access(name, 0) == 0);
}
/*
* get_file_buf()
*
* Input:
* Output:
* buf_size - size of buffer
* returns - pointer to buffer
*/
void *get_file_buf(unsigned long *buf_size)
{
void *buf_mem;
*buf_size = MAX_BUF;
do {
if ((buf_mem = malloc(*buf_size)) != NULL)
break;
*buf_size /= 2;
} while (*buf_size >= 512);
if (buf_mem == NULL){
fprintf(stderr, "could not allocate file buffer\n");
exit(-1);
}
return(buf_mem);
}
/*
* copy_file()
*
* Input:
* ptr - pointer to hash table entry for file
* dst_file - full path of destination file
* src_file - full path of source file
* buf_size - size of buffer for file i/o
* File_buf - buffer for file i/o
* Buf_ptr - pointer to next available memory in i/o buffer
* Reading_flag - indicates whether 'reading:' has been printed
* Comments:
* copies source file to destination file
*/
void copy_file(ENTRY *ptr, char *dst_file, char *src_file,
unsigned long buf_size)
{
int src_handle, dst_handle;
long bytes;
int retval;
long bytes_needed, bytes_left;
struct stat stat_buf;
_DOSTIME ftime_buf;
char fattr;
if ((Options & O_MOVE) && (*src_file == *dst_file)){
if (!Reading_flag && (Options & O_VERBOSE)){
fprintf(stdout, "renaming file:\n");
fprintf(stdout, "\t%s -> %s\n", src_file, dst_file);
Reading_flag = 0;
}
if (rename_file(ptr, src_file, dst_file))
clean_up_and_exit();
} else {
if ((src_handle = open(src_file, O_RDONLY, 0)) < 0){
fprintf(stderr, "unable to open file '%s'\n", src_file);
clean_up_and_exit();
}
Fdatime(&ftime_buf, src_handle, 0);
fstat(src_handle, &stat_buf);
fattr = Fattrib(src_file, 0, 0);
bytes_needed = sizeof(ENTRY *) + (strlen(src_file) + 1) +
(strlen(dst_file) + 1) + sizeof(stat_buf.st_size) +
stat_buf.st_size + sizeof(_DOSTIME) +
sizeof(fattr);
bytes_left = (char *)File_buf - (char *)Buf_ptr + buf_size;
if ((bytes_needed > MAX_BUF) || (Options & O_INTERACTIVE)) {
if (Buf_ptr != File_buf)
write_buffer(File_buf);
copy_file_unbuffered(src_handle, ptr, src_file, dst_file,
stat_buf.st_size, &ftime_buf, fattr,
buf_size);
} else {
if (bytes_left < bytes_needed)
write_buffer(File_buf);
if (!Reading_flag && (Options & O_VERBOSE)){
fprintf(stdout, "reading:\n");
Reading_flag = 1;
}
if (Options & O_VERBOSE)
fprintf(stdout, "\t%s\n", src_file);
copy_file_to_buffer(src_handle, ptr, src_file, dst_file,
&ftime_buf, stat_buf.st_size, fattr);
}
close(src_handle);
}
}
/*
* rename_file()
*
* Input:
* ptr - pointer to hash table entry (so we can mark this as 'copied')
* src_file - source file name (full path)
* dst_file - destination file name (full path)
* Comments:
* renames a file. if the destination file already exits,
* then it is deleted.
*/
int rename_file(ENTRY *ptr, char *src_file, char *dst_file)
{
int old_attrib;
if ((old_attrib = Fattrib(src_file, 0, 0)) < 0) {
fprintf(stderr, "cannot move file %s\n", src_file);
return -1;
}
if (rename(src_file, dst_file) == -1){
if (file_exists(dst_file))
if (delete_file(dst_file, '\0')){
if ((!(Options & O_BATCH)) &&
(printf("Target %s protected - ", dst_file),
!(ask_user("force move onto it (Y/N/Q)? ")))){
fprintf(stderr, "%s NOT moved to %s\n", src_file,
dst_file);
return -1;
}
if (delete_file(dst_file, '\1')){
fprintf(stderr, "could not remove %s\n", dst_file);
return -1;
}
}
if (old_attrib & FA_RDONLY)
Fattrib(src_file, 1, old_attrib&(~FA_RDONLY));
if (rename(src_file, dst_file) == -1){
if (old_attrib & FA_RDONLY)
Fattrib(src_file, 1, old_attrib);
fprintf(stderr, "cannot move file %s\n", src_file);
return -1;
}
}
Fattrib(dst_file, 1, old_attrib);
Copied_a_file = 1;
ptr->copied = (old_attrib) ? old_attrib : FA_CHANGED;
return 0;
}
/*
* copy_file_to_buffer()
*
* Input:
* src_handle - source file handle
* src_file - source file name (full path)
* dst_file - destination file name (full path)
* st_buf - stat buffer of source file
* attrib - file access mode (contains hidden)
* Output:
* Buf_ptr - pointer to unused position in buffer
* Comments:
* copies the source file along with a header to memory.
* the header contains source-file name, dest-file name,
* source-file date, source-file size, and the source-file
* modes.
*/
void copy_file_to_buffer(int src_handle, ENTRY *ptr,
char *src_file, char *dst_file,
_DOSTIME *ftime_buf, long fsize, char fattr)
{
memcpy((char *)Buf_ptr, &ptr, sizeof(ENTRY *));
Buf_ptr = (char *)Buf_ptr + sizeof(ENTRY *);
strcpy((char *)Buf_ptr, src_file);
Buf_ptr = (char *)Buf_ptr + strlen(src_file) + 1;
strcpy((char *)Buf_ptr, dst_file);
Buf_ptr = (char *)Buf_ptr + strlen(dst_file) + 1;
memcpy(Buf_ptr, &fsize, sizeof(fsize));
Buf_ptr = (char *) Buf_ptr + sizeof(long);
memcpy(Buf_ptr, ftime_buf, sizeof(_DOSTIME));
Buf_ptr = (char *) Buf_ptr + sizeof(_DOSTIME);
memcpy(Buf_ptr, &fattr, sizeof(char));
Buf_ptr = (char *) Buf_ptr + sizeof(char);
read(src_handle, Buf_ptr, fsize);
Buf_ptr = (char *) Buf_ptr + fsize;
}
/*
* copy_file_unbuffered()
*
* Input:
* src_handle - handle of source file
* src_file - name of source file (full path name)
* dst_file - name of destination file (full path name)
* buf_size - size of file buffer
* Reading_flag - indicates whether 'reading:' has been printed
* File_buf - buffer for file i/o
* Output:
* Reading_flag - reset to indicate that the message
* 'reading and writing file:' has been printed.
* Comments:
* copies the source file to the destination file without
* buffering (as is done with smaller files). the file modes
* and file date are also copied.
*/
void copy_file_unbuffered(int src_handle, ENTRY *ptr,
char *src_file, char *dst_file,
long fsize, _DOSTIME *ftime_buf, char fattr,
unsigned long buf_size)
{
unsigned bytes = 0;
int dst_handle;
int retval;
do {
Retry = 0;
if (open_dest_file(&dst_handle, dst_file,
(fattr & FA_RDONLY) ? S_IREAD : S_IREAD | S_IWRITE))
return;
if (!Reading_flag && (Options & O_VERBOSE)){
fprintf(stdout, "reading and writing file:\n");
fprintf(stdout, "\t%s -> %s\n", src_file, dst_file);
Reading_flag = 0;
}
if (!(Options & O_LARGEFILES))
lseek(src_handle, 0L, SEEK_SET);
copy_file_contents(src_handle, dst_handle, src_file, dst_file,
buf_size);
} while (Retry);
if (Options & O_MOVE)
delete_file(src_file, '\0');
Copied_a_file = 1;
Fdatime(ftime_buf, dst_handle, 1);
close(dst_handle);
Fattrib(dst_file, 1, fattr);
ptr->copied = (fattr) ? fattr : FA_CHANGED;
}
/*
* ensure_dest_dir_exist
*
* given a destination file name, first ensure the existence of the directory
* which will contain it. This function exists to make a target-disk swap work
* together with the recursive option. Return non-zero on success, zero on
* failure.
*/
int ensure_dest_dir_exist(char *dst_file)
{
int stat_err, ret_val = 1;
struct stat statbuf;
char *p;
if ((p = strrchr(dst_file, '\\')) == NULL)
return 0;
*p = '\0';
if ((!(stat_err = stat(dst_file, &statbuf))) &&
(!(statbuf.st_mode & S_IFDIR)))
ret_val = 0;
else if (stat_err)
create_dir(dst_file);
*p = '\\';
return ret_val; /* if 'create_dir()' returns, it was successful */
}
/*
* target_disk_full
*
* called when the target disk is full. Depending on the options, it may
* be possible to change target disks and go on.
*/
void target_disk_full(char *dst_file, int dst_handle)
{
close(dst_handle);
if (!(Options & O_LARGEFILES))
delete_file(dst_file, '\1');
if (ok_to_retry())
if (ask_user("out of disk space, continue (Y/N/Q) ? ")) {
if (Options & O_ZAPTARGET)
zap_target(Org_dest_dir, 1);
Retry = 1;
}
else
clean_up_and_exit();
else {
fprintf(stderr, "out of disk space\n");
clean_up_and_exit();
}
}
/*
* clean_up_and_exit
*
* error occurred (like write error/target full). Clean up (clear archive
* bits of source files already copied) and exit.
*/
void clean_up_and_exit()
{
clear_archive_bits(Cur_source_dir);
exit(-1);
}
/*
* copy_file_contents()
*
* Input:
* src_handle - handle of source file
* src_handle - handle of destination file
* src_file - name of source file (full path name)
* dst_file - name of destination file (full path name)
* buf_size - size of file buffer
* File_buf - buffer for file i/o
* Comments:
* copies the contents of the source file to the destination
* file.
*/
void copy_file_contents(int src_handle, int dst_handle, char *src_file,
char *dst_file, unsigned long buf_size)
{
long last_read_pos, bytes_read, bytes_written;
while(1){
last_read_pos = tell(src_handle);
bytes_read = read(src_handle, File_buf, buf_size);
if (bytes_read == -1L){
fprintf(stderr, "Can't read file '%s'\n", src_file);
exit(-1);
}
if (bytes_read){
bytes_written = write(dst_handle, File_buf,
(unsigned long) bytes_read);
if (bytes_written == -1L){
fprintf(stderr, "Can't write to file '%s'\n",
dst_file);
exit(-1);
}
} else
break;
if (bytes_read != bytes_written) {
if (Options & O_LARGEFILES)
lseek(src_handle, last_read_pos+bytes_written, SEEK_SET);
target_disk_full(dst_file, dst_handle);
break;
}
}
}
/*
* ok_to_retry()
*
* Input:
* none
* Comments:
* checks if the target directory was used to determine the file
* list. If it was, then the copy is aborted when disk is full
*/
int ok_to_retry()
{
return ((!(Options & O_BATCH)) && (Options & O_TARGET_REMOVEABLE) &&
(!(Options &
(O_TARGET_DIR | O_COPY_IF_SRC_OLDER | O_CP_IF_SRC_NEWER))));
}
void setftime(char *fname, struct stat *statbuf)
{
struct utimbuf ftime;
ftime.actime = statbuf->st_atime;
ftime.modtime = statbuf->st_mtime;
utime(fname, &ftime);
}
/*
* write_buffer()
*
* Input:
* file_buf - memory buffer containing file contents along
* with their headers
* File_buf - starting location of memory buffer
* Output:
* Reading_flag - reset to indicate recent output of message,
* 'writing:'
* Buf_ptr - location of available memory in memory buffer
* Comments:
* copies all the files contained in the memory buffer to their
* destination files
*/
void write_buffer(void *file_buf)
{
ENTRY *ptr;
int dst_handle;
unsigned retval;
char src_file[FILENAME_MAX];
char dst_file[FILENAME_MAX];
_DOSTIME ftime_buf;
long fsize;
char fattr;
if ((Options & O_VERBOSE) && (file_buf < Buf_ptr))
printf("writing:\n");
Reading_flag = 0;
while (file_buf < Buf_ptr){
file_buf = get_header_info(file_buf, &ptr, src_file, dst_file,
&ftime_buf, &fsize, &fattr);
if (!(Options & O_CHECK))
if (!write_dest_file(&dst_handle, dst_file, file_buf, fsize,
fattr)) {
if (Options & O_MOVE)
delete_file(src_file, '\0');
Copied_a_file = 1;
Fdatime(&ftime_buf, dst_handle, 1);
close(dst_handle);
Fattrib(dst_file, 1, fattr);
ptr->copied = (fattr) ? fattr : FA_CHANGED;
}
file_buf = (char *)file_buf + fsize;
}
Buf_ptr = File_buf;
}
/*
* get_header_info()
*
* Input:
* file_buf - pointer to memory buffer containing file
* contents and header
* Output:
* src_file - source file name (full path)
* dst_file - destination file name (full path)
* stat_buf - file status buffer
* mode - mode settings of source file
* returns - location of next file in memory buffer
* Comments:
* gets a file's header information from the memory buffer
*/
void *get_header_info(void *file_buf, ENTRY **ptr,
char *src_file, char *dst_file, _DOSTIME * ftimebuf,
long *fsize, char *fattr)
{
memcpy(ptr, (char *)file_buf, sizeof(ENTRY *));
file_buf = (char *)file_buf + sizeof(ENTRY *);
strcpy(src_file, (char *)file_buf);
file_buf = (char *)file_buf + strlen((char *)file_buf) + 1;
strcpy(dst_file, (char *)file_buf);
file_buf = (char *)file_buf + strlen((char *)file_buf) + 1;
memcpy(fsize, file_buf, sizeof(long));
file_buf = (char *) file_buf + sizeof(long);
memcpy(ftimebuf, file_buf, sizeof(_DOSTIME));
file_buf = (char *) file_buf + sizeof(_DOSTIME);
memcpy(fattr, file_buf, sizeof(char));
file_buf = (char *) file_buf + sizeof(char);
return(file_buf);
}
/*
* write_dest_file()
*
* Input:
* dst_handle - handle of file to be written
* dst_file - full-path name of file to be written
* file_buf - memory buffer containing file contents
* file_size - size of file to be written
* fattr - file attributes
* Comments:
* copies a file's contents from a memory buffer to a disk file.
* Returns 0 normally, 1 if the destination couldn't be opened for write.
*/
int write_dest_file(int *dst_handle, char *dst_file, void *file_buf,
long file_size, int fattr)
{
long bytes_written, written_so_far = 0L;
do {
Retry = 0;
if (Options & O_VERBOSE)
printf("\t%s\n", dst_file);
if (open_dest_file(dst_handle, dst_file, ((fattr & FA_RDONLY)
? S_IREAD
: S_IREAD | S_IWRITE)))
break;
bytes_written = write(*dst_handle, file_buf+written_so_far,
(unsigned long) file_size-written_so_far);
if (bytes_written == -1L){
fprintf(stderr, "Can't write to file '%s'\n", dst_file);
exit(-1);
}
if (bytes_written != (file_size-written_so_far)) {
if (Options & O_LARGEFILES)
written_so_far += bytes_written;
target_disk_full(dst_file, *dst_handle);
}
else
return 0;
} while (Retry);
return 1;
}
/*
* open_dest_file()
*
* Input:
* dst_handle - handle of file to be opened
* dst_file - full-path name of file to be opened
* mode - mode settings of file to be opened
* Comments:
* opens a file for write. If not successful because file is read-only,
* tries to recover.
*/
int open_dest_file(int *handle, char *name, unsigned modes)
{
if ((*handle = open((char *)name,
(Options & O_JOIN) ? O_WRONLY | O_APPEND | O_CREAT
: O_WRONLY | O_TRUNC | O_CREAT,
(unsigned)modes)) < 0){
struct stat statbuf;
if (stat(name, &statbuf)) {
ensure_dest_dir_exist(name);
if ((*handle = open((char *)name,
(Options & O_JOIN)
? O_WRONLY | O_APPEND | O_CREAT
: O_WRONLY | O_TRUNC | O_CREAT,
(unsigned)modes)) < 0){
fprintf(stderr, "unable to open file '%s' for write\n", name);
return -1;
}
}
else if ((Options & O_BATCH) ||
(printf("file '%s' is not writeable.\n", name),
ask_user("Attempt to delete and overwrite it (Y/N/Q) ? "))) {
delete_file(name, '\1');
if ((*handle = open((char *)name,
(Options & O_JOIN)
? O_WRONLY | O_APPEND | O_CREAT
: O_WRONLY | O_TRUNC | O_CREAT,
(unsigned)modes)) < 0) {
fprintf(stderr, "unable to open file '%s' for write\n",
name);
return -1;
}
}
else {
printf("Skipped copy to '%s' (open for write failed).\n",
name);
return -1;
}
}
return 0;
}
/*
* usage()
*
* Comments:
* outputs brief instructions on the proper use of docp
*/
void usage()
{
fprintf(stderr, USAGE_MESS);
exit(-1);
}
/*
* get_flags()
*
* Input:
* argv - command line arguments
* argc - count of the command line arguments
* Output:
* From_file_ptr - pointer to file containing file list
* Comments:
* parses the flags specified on the command line, and sets
* the appropriate bit fields in a variable called 'options'
*/
void get_flags(char *argv[], int argc)
{
int c;
char from_file[FILENAME_MAX];
while ((c = getopt(argc, argv, GET_OPT_LIST)) != EOF) {
if (isupper(c))
c = tolower(c);
switch(c){
case 'a': /* copy using archive bit */
Options |= O_ARCHIVE;
break;
case 'b': /* batch mode - don't ask questions */
Options |= O_BATCH;
break;
case 'c': /* check mode, don't copy files */
Options |= O_VERBOSE | O_X_VERBOSE | O_CHECK;
break;
case 'd': /* date check */
Options |= O_DATE_CHECK;
set_Fdate(optarg);
break;
case 'f': /* file list from file */
strcpy(from_file, optarg);
if (!strcmp(from_file, "-"))
Options |= O_FROM_STDIN;
else {
Options |= O_FROM_FILE;
if ((From_file_ptr = fopen(from_file, "r"))
== NULL){
fprintf(stderr, "unable to open '-f' file '%s'\n", from_file);
exit(-1);
}
}
break;
case 'g': /* gather files into one directory */
Options |= O_GATHER | O_RECURSIVE;
break;
case 'h': /* copy hidden files as well */
Options |= O_COPY_HIDDEN;
break;
case 'i': /* interactive confirm */
Options |= O_INTERACTIVE;
break;
case 'j': /* join files */
Options |= O_JOIN;
break;
case 'l': /* large files (split) */
Options |= O_LARGEFILES;
break;
case 'm': /* move mode */
Options |= O_MOVE;
break;
case 'n': /* no action */
Options |= O_CP_IF_SRC_NEWER;
break;
case 'o': /* copy if source is older */
Options |= O_COPY_IF_SRC_OLDER;
break;
case 'r': /* update subdirectories */
Options |= O_RECURSIVE;
break;
case 's': /* reference list from source */
Options |= O_SOURCE_DIR;
break;
case 't': /* get file list from target */
Options |= O_TARGET_DIR;
break;
case 'v': /* verbose */
if (Options & O_VERBOSE)
Options |= O_X_VERBOSE;
else
Options |= O_VERBOSE;
break;
case 'w': /* time check */
Options |= O_TIME_CHECK;
set_Ftime(optarg);
break;
case 'z': /* zap the target before copying */
Options |= O_ZAPTARGET;
break;
case '?': /* documentation */
show_doc();
break;
case '\0':
usage();
break;
default:
break;
}
}
set_defaults();
}
/*
* set_defaults()
*
* Input:
* none
* Output:
* none
* Comments:
* sets the default command-line flags
*/
void set_defaults()
{
if (!(Options &
(O_ARCHIVE | O_COPY_IF_SRC_OLDER | O_CP_IF_SRC_NEWER |
O_DATE_CHECK | O_TIME_CHECK)))
Options |= O_COPY_ALL;
if (!(Options & (O_SOURCE_DIR | O_TARGET_DIR)))
Options |= O_SOURCE_DIR;
if ((Options & O_TIME_CHECK) && !(Options & O_DATE_CHECK)){
Options |= O_DATE_CHECK;
set_todays_date();
}
}
/*
* check_flags()
*
* Input:
* none
* Comments:
* terminates if the command-line flags are inconsistent
*/
void check_flags()
{
if ((Options & O_SOURCE_DIR) && (Options & O_TARGET_DIR)){
fprintf(stderr, "specify only one of '-s' and '-t' options\n");
exit(-1);
}
if ((Options & O_BATCH) && (Options & O_INTERACTIVE)) {
fprintf(stderr, "specify only one of '-b' and '-i' options\n");
exit(-1);
}
}
/*
* show_doc()
*
* Comments:
* outputs expanded description of docp
*/
void show_doc()
{
fprintf(stdout, FULL_DOC1);
fprintf(stdout, FULL_DOC2);
fprintf(stdout, FULL_DOC3);
fprintf(stdout, FULL_DOC4);
exit(0);
}
/*
* set_Ftime()
*
* Input:
* time_str - time string following '-w' option. includes relation
* followed by time (e.g. "a3:15pm")
* Output:
* Ftime - global with reference time
* Time_check_mode - global with relationship to reference time
* Comments:
* takes time string specified in '-w' option and stores the
* time in Ftime and the relationship in Time_check_mode.
*/
void set_Ftime(char *time_str)
{
TIME time;
int i;
char *time_arg = time_str;
time.mode = 0;
while ((*time_str == 'o') || (*time_str == 'b') || (*time_str == 'a'))
switch(*time_str){
case 'o':
time_str++;
time.mode |= D_ON;
break;
case 'b':
time_str++;
time.mode |= D_BEFORE;
break;
case 'a':
time_str++;
time.mode |= D_AFTER;
break;
default:
break;
}
time.hour = atoi(time_str);
if ((time_str = get_field(time_str, (int *)&(time.min))) == NULL)
bad_time(time_arg);
while (*time_str != '\0')
if (((*time_str == 'p') || (*time_str == 'P')) &&
(time.hour < 13)){
time.hour += 12;
break;
} else time_str++;
check_time(&time, time_arg);
store_time(&time);
}
/*
* store_time()
*
* Input:
* time - structure containing time
* Output:
* Ftime - time in form returned by findnext()
* Comments:
* converts time to form returned by findnext()
*/
void store_time(TIME *time)
{
TIME_NODE *d;
if ((d = (TIME_NODE *)malloc(sizeof(TIME_NODE))) == NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
d->ftime = (time->min << 5) | (time->hour << 11);
d->mode = time->mode;
d->next = Ftime;
Ftime = d;
}
/*
* check_time()
*
* Input:
* time - structure containing time
* Comments:
* does a crude check on the time entered
*/
void check_time(TIME *time, char *time_arg)
{
if ((time->hour < 1) || (time->hour > 24) ||
(time->min < 0) || (time->min > 60))
bad_time(time_arg);
}
/*
* bad_time()
*
* Comments:
* termination routine called when a bad time is found
*/
void bad_time(char *time_arg)
{
fprintf(stderr, "bad time specified, '%s'\n", time_arg);
exit(-1);
}
/*
* set_Fdate()
*
* Input:
* date_str - date string following '-d' option. includes relation
* followed by date (e.g. ">=3/23/91")
* Output:
* Fdate - global with reference date
* Date_check_mode - global with relationship to reference date
* Comments:
* takes date string specified in '-d' option and stores the
* date in Fdate and the relationship in Date_check_mode.
*/
void set_Fdate(char *date_str)
{
DATE date;
int *p;
int i;
date.mode = 0;
while ((*date_str == 'o') || (*date_str == 'b') || (*date_str == 'a')){
switch(*date_str){
case 'o':
date_str++;
date.mode |= D_ON;
break;
case 'b':
date_str++;
date.mode |= D_BEFORE;
break;
case 'a':
date_str++;
date.mode |= D_AFTER;
break;
default:
break;
}
}
convert_date_str(&date, date_str);
check_date(&date, date_str);
store_date(&date);
}
/*
* convert_date_str()
*
* Input:
* date_str - date string from command line
* Output:
* date - numeric date structure
* Comments:
* converts command-line date string into numeric structure
*/
void convert_date_str(DATE *date, char *date_str)
{
char *new_date_str;
date->mo = atoi(date_str);
if ((date_str = get_field(date_str, (int *)&(date->day))) == NULL)
return;
if ((date_str = get_field(date_str, (int *)&(date->year))) == NULL)
return;
}
/*
* get_field()
*
* Input:
* date_str - current position in date string from command line
* Output:
* date_str - new position in date string from command line
* date_field - numeric value of date field (day or year)
* Comments:
* gets numeric date from field of command-line date string
*/
char *get_field(char *string, int *field)
{
char *new_string;
new_string = strchr(string, '/');
if (new_string == NULL)
new_string = strchr(string, '-');
if (new_string == NULL)
new_string = strchr(string, ':');
if (new_string == NULL){
*field = 0;
} else {
new_string++;
*field = atoi(new_string);
}
return(new_string);
}
/*
* set_todays_date()
*
* Output:
* Fdate - adds today's date in date table with ON option set.
* Comments:
* stores today's date in date table. Done when user only
* specifies time option without date option.
*/
void set_todays_date()
{
DATE date;
get_todays_date(&date);
date.mode = D_ON;
store_date(&date);
}
/*
* get_todays_date()
*
* Output:
* date - today's date from the operating system
* Comments:
* gets the current date from the operating system
*/
void get_todays_date(DATE *date)
{
short cur_date = Tgetdate();
date->year = (cur_date >> 9) + 80;
date->mo = (cur_date >> 5) & 0xf;
date->day = (cur_date) & 0x1f;
}
/*
* store_date()
*
* Input:
* date - structure containing date
* Output:
* Fdate - date in form returned by findnext()
* Comments:
* converts date to form returned by findnext()
*/
void store_date(DATE *date)
{
DATE_NODE *d;
if ((d = (DATE_NODE *)malloc(sizeof(DATE_NODE))) == NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
d->fdate = date->day | (date->mo << 5) | ((date->year - 80) << 9);
d->mode = date->mode;
d->next = Fdate;
Fdate = d;
}
/*
* check_date()
*
* Input:
* date - structure containing date
* date_str - date string from command line
* Comments:
* does a crude check on the date entered
*/
void check_date(DATE *date, char *date_str)
{
if ((date->mo < 1) || (date->mo > 12) ||
(date->day < 1) || (date->day > 31))
bad_date(date_str);
}
/*
* bad_date()
*
* Input:
* date_str - date string from command line
* Comments:
* termination routine called when a bad date is found
*/
void bad_date(char *date_str)
{
fprintf(stderr, "bad date specified '%s'\n", date_str);
exit(-1);
}
/*
* build_stdin_file_list()
*
* Output:
* num_args - the number of args in the stdin file list
* Comments:
* builds linked list containing file list tokens from stdin.
*/
void build_stdin_file_list(int *num_args)
{
char s[80];
while (fgets(s, 79, stdin) != NULL){
zap_trailing_nl(s, 79, stdin); /* clobber newline */
add_to_stdin_list(s);
(*num_args)++;
}
if (*num_args == 0){
add_to_stdin_list("*.*");
*num_args = 1;
}
}
/*
* add_to_stdin_list()
*
* input:
* s - the file list token
* Output:
* Stdin_list_head - first element of file list
* Stdin_list_tail - last element of file list
* Comments:
* adds a file list token to a linked list
*/
void add_to_stdin_list(char *s)
{
STDIN_TOKEN *new_token;
if ((new_token = (STDIN_TOKEN *)malloc(sizeof(STDIN_TOKEN))) == NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
if ((new_token->string = (char *)malloc(strlen(s) + 1)) == NULL){
fprintf(stderr, "out of memory");
exit(-1);
}
strcpy(new_token->string, s);
new_token->next = NULL;
if (Stdin_list_head == NULL){
Stdin_list_head = Stdin_list_tail = new_token;
} else {
Stdin_list_tail->next = new_token;
Stdin_list_tail = new_token;
}
}