home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
maint
/
part05
/
misc.c
Wrap
C/C++ Source or Header
|
1992-05-13
|
62KB
|
2,433 lines
/******************************************************************************
*******************************************************************************
Site: Western Michigan University Academic Computer Center
System: Directory/File System Maintenance
Program: maint
Version=01 Level=00 01/24/92 Leonard J. Peirce
Purpose: Miscellaneous routines for MAINT.
Arguments: See individual routines.
External variables: curr_year
spec_win
stat_win
main_win
args
External functions:
Defined: add_filetype, banystr, cat, check_marks, cont_after_stop,
follow_link, get_bnum, get_dir, get_dir_mem, get_filemarks,
get_num_file, make_ent, make_screen, mystrcpy, mystrmcpy,
padcpy, prot_str_to_val, prot_val_to_str, rename, set_args,
set_date, set_nodes, set_screen, set_width, spawn,
squeeze_str, strindex, strtcpy
Called: date_qsort, make_slot, name_qsort, put_pool, put_slot,
size_qsort, sort_files
Files accessed: See individual routines.
Return codes: See individual routines.
Compiling instructions: See Makefile.
Linking instructions: See Makefile.
Other information: (C) Copyright 1992, Leonard J. Peirce
********************************************************************************
*******************************************************************************/
/******************************************************************************/
/* */
/* # I N C L U D E F I L E S */
/* */
/******************************************************************************/
#ifdef ultrix
#include <cursesX.h>
#else
#include <curses.h>
#endif
#include <sys/param.h>
#include <malloc.h>
#include <time.h>
#include <string.h>
#if !defined(SYSV) || defined(sun)
#include <sys/wait.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <varargs.h>
#include "maint.h"
#include <sys/stat.h>
/******************************************************************************/
/* */
/* # D E F I N E S */
/* */
/******************************************************************************/
/******************************************************************************/
/* */
/* S T R U C T U R E S , U N I O N S , T Y P E D E F S */
/* */
/******************************************************************************/
/******************************************************************************/
/* */
/* E X T E R N A L D E F I N I T I O N S & D E C L A R A T I O N S */
/* */
/******************************************************************************/
extern int curr_year;
extern ENT_DEF *baseptr;
extern WINDOW *spec_win,
*main_win,
*stat_win;
extern ARG_DEF args;
extern char *getenv();
extern int execve(),
vfork(),
put_slot(),
make_slot();
extern u_short cont_flag;
extern void put_pool(),
date_qsort(),
size_qsort(),
name_qsort(),
sort_files();
char *mystrcpy(),
*mystrmcpy(),
*prot_val_to_str(),
*padcpy(),
*set_date(),
*cat();
#if !defined(SYSV) || defined(sun)
long get_bnum();
#endif
int check_marks(),
strtcpy(),
follow_link(),
make_ent(),
#if defined(SYSV) && !defined(sun)
rename(),
#endif
strindex();
u_short add_filetype();
short banystr(),
get_num_file(),
prot_str_to_val();
u_char filetype_char();
void set_screen(),
set_width(),
set_args(),
set_nodes(),
get_dir_mem(),
get_dir(),
message(),
squeeze_str(),
make_screen(),
cont_after_stop(),
get_filemarks();
/******************************************************************************/
/* */
/* S T A T I C D E F I N I T I O N S & D E C L A R A T I O N S */
/* */
/******************************************************************************/
static char *get_name();
static u_short check_nlen();
static u_char set_type();
/*******************************************************************************
********************************************************************************
Function: set_screen
Purpose: Compute values for parameters that relate to the screen,
including number of columns, number of files, and the number
of screens needed for the directory.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
COLS X
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void set_screen(num_screen,scr_file,num_file,slot_width,node_row_max,num_col)
/******* FORMAL PARAMETERS *******/
short *num_screen, /* number of screens in directory */
*scr_file, /* number of file slots per screen */
num_file, /* number of files in directory */
slot_width; /* width of file slot */
u_short node_row_max; /* max. # of rows in node array */
short *num_col; /* number of columns for full screen */
{ /*** set_screen ***/
/* compute the number of files per row of the screen */
*num_col = (short) COLS/(slot_width + SLOT_GAP + 1);
if(*num_col == 0)
*num_col = 1; /* must have at least one column */
/* now compute how many file slots will fit on a screen */
*scr_file = *num_col * (short) node_row_max;
/* compute how many screens will be needed for this directory */
*num_screen = num_file/(*scr_file);
if((num_file % (*scr_file)) != 0)
*num_screen += 1;
return;
} /*** set_screen ***/
/*******************************************************************************
********************************************************************************
Function: set_nodes
Purpose: Initialize the screen slot node pointers for the current
directory.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void set_nodes(nodes,node_row_max,scr_file,num_screen,curr_screen,num_file,
slot_width,num_col)
/******* FORMAL PARAMETERS *******/
register NODE_DEF nodes[][MAX_NODE_COL+1]; /* screen node matrix */
u_short node_row_max; /* max. # of rows in node array */
short *scr_file, /* number of files on current screen */
num_screen, /* number of screens for directory */
curr_screen, /* current screen */
num_file, /* number of files in directory */
slot_width, /* number of characters for file slot */
num_col; /* number of columns per screen */
{ /*** set_nodes ***/
/******** LOCAL VARIABLES ********/
register NODE_DEF *tptr; /* temporary node pointer */
register int i, /* loop and array index */
j; /* ditto.... */
static short left_val, /* left pointer for node */
up_val, /* up pointer for node */
column_val, /* current column value */
num_row, /* number of rows for this screen */
full_row, /* number of full rows for screen */
full_col; /* number of full columns */
if(curr_screen == num_screen) /* if this is the last page */
{
/* recompute the number of columns; it might be different because
* this is the last page of the directory
*/
/* compute how many files will be on this screen of the directory */
*scr_file = num_file - (num_col * node_row_max * (curr_screen - 1));
/* now compute how many columns are needed for the last screen */
num_col = *scr_file / node_row_max;
if((*scr_file % node_row_max) != 0)
num_col++;
}
else
{
/* compute how many files will be on this screen of the directory */
*scr_file = num_col * (short) node_row_max;
}
if(*scr_file < node_row_max) /* determine number of rows */
num_row = *scr_file;
else
num_row = node_row_max;
left_val = num_col - 1; /* set left and right pointers */
j = 0; /* start with the first column */
column_val = 0; /* cursor on screen starts @ (0,0) */
full_col = *scr_file / node_row_max; /* calculate number of full columns */
if(full_col == 0) /* must have at least one full column */
full_col = 1;
full_row = *scr_file - (full_col * num_row);
if(full_row == 0)
full_row = *scr_file / full_col;
/* first initialize the node matrix just like it would be a full screen;
* then we will "trim" the edges to make sure that things point to the right
* places in case the cursor would to need to wrap around the screen
*/
up_val = num_row - 1;
i = 0;
while(i < num_row)
{
j = 0;
left_val = num_col - 1; /* left j value */
column_val = 0;
while(j < num_col)
{
tptr = &(nodes[i][j]); /* get a pointer to the current node */
tptr->right_col = (j + 1) % num_col;
tptr->left_col = left_val;
tptr->up_col = j;
tptr->down_col = j;
tptr->right_row = i;
tptr->left_row = i;
tptr->up_row = up_val;
tptr->down_row = (i + 1) % num_row;
tptr->row = i;
tptr->column = column_val;
column_val = column_val + slot_width + SLOT_GAP + 1;
left_val = (left_val + 1) % num_col;
j++;
}
up_val = (up_val + 1) % num_row;
i++;
}
/* now trim the edges of the matrix just in case this is the last screen
* of the directory
*/
/* first go along the top of the screen */
i = 0;
for(j = 0; j < num_col; j++)
{
tptr = &(nodes[i][j]); /* get a pointer to the node */
if(!j) /* are we in the top left node? */
{
/* top left node; the values for going up from this node should
* point to bottom node in the last column on the screen
*/
tptr->up_row = full_row - 1;
tptr->up_col = num_col - 1;
}
else
{
tptr->up_col = j - 1;
tptr->up_row = num_row - 1;
}
}
/* now go along the left of the screen */
j = 0;
for(i = 0; i < num_row; i++)
{
tptr = &(nodes[i][j]);
if(!i)
{
/* we are in the top left of the screen; going left from here
* should go to the bottom, right-most node
*/
tptr->left_row = full_row - 1;
tptr->left_col = num_col - 1;
}
else
{
if(i < full_row + 1)
tptr->left_col = num_col - 1;
else
tptr->left_col = full_col - 1;
tptr->left_row = (i - 1) % num_row;
}
}
/* trim the bottom full columns */
i = num_row - 1;
for(j = 0; j < full_col; j++)
{
tptr = &(nodes[i][j]); /* get a pointer to the node */
tptr->down_col = j + 1;
}
/* now go along the right side of the last full column */
j = full_col - 1;
for(i = full_row; i < num_row; i++)
{
tptr = &(nodes[i][j]);
tptr->right_row = (i + 1) % num_row;
tptr->right_col = 0;
}
/* trim along the last column, whether it be full or not */
j = num_col - 1;
for(i = 0; i < full_row; i++)
{
tptr = &(nodes[i][j]);
tptr->right_row = (i + 1) % num_row;
tptr->right_col = 0;
}
/* set the last node on the screen; this is a special case */
tptr = &(nodes[full_row-1][num_col-1]);
tptr->down_row = 0;
tptr->down_col = 0;
return;
} /*** set_nodes ***/
/*******************************************************************************
********************************************************************************
Function: make_ent
Purpose: Gather all the information about an individual file, including
the protection string and filename that will be displayed on
the screen. This information is stored in the directory entry.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
SUCCESS
FAILURE
********************************************************************************
*******************************************************************************/
int make_ent(ent,filename,num_block)
/******* FORMAL PARAMETERS *******/
register ENT_DEF *ent; /* pointer to file entry */
register char *filename; /* file to be looked up */
long *num_block; /* number of blocks in directory */
{ /*** make_ent ***/
/******** LOCAL VARIABLES ********/
static int status; /* return code status holder */
static struct stat statbuf; /* file stat structure */
#if !defined(SYSV) || defined(sun)
status = lstat(filename,&statbuf);
#else
status = stat(filename,&statbuf);
#endif
if(status != 0)
return(FAILURE);
ent->type = set_type(statbuf.st_mode);
ent->prot = statbuf.st_mode;
ent->time = statbuf.st_mtime;
ent->size = statbuf.st_size;
ent->command = NULL;
ent->text = NULL;
ent->gid = statbuf.st_gid;
ent->uid = statbuf.st_uid;
ent->name_len = check_nlen(filename);
/* set the filename that will be displayed on the screen */
strcpy(ent->scr_name,get_name(filename,&(ent->disp_len),ent->prot,
ent->type));
#if defined(SYSV) && !defined(sun)
*num_block += kbytes(statbuf.st_size);
#else
*num_block += statbuf.st_blocks;
#endif
return(SUCCESS);
} /*** make_ent ***/
/*******************************************************************************
********************************************************************************
Function: make_screen
Purpose: Create the individual screen entries for the current screen
of the directory and write them to the virtual display.
This routine will also clear out the slots on the screen where
the files should not appear. This would happen only on the
last page of a directory.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void make_screen(window,nodes,dirptr,args,curr_screen,node_row_max,
node_col_max,scr_file,num_slot,slot_width,text_flag)
/******* FORMAL PARAMETERS *******/
WINDOW *window; /* window to write to */
NODE_DEF nodes[][MAX_NODE_COL+1]; /* screen node matrix */
ENT_DEF *dirptr; /* pointer to directory information */
register ARG_DEF *args; /* command-line arguments */
short curr_screen; /* current screen number */
u_short node_row_max, /* max. # of rows in node array */
node_col_max; /* max. # of columns in node array */
register short scr_file; /* number of files for current screen */
short num_slot, /* number of slots per screen */
slot_width, /* width of a filename screen slot */
text_flag; /* whether we display text descrips */
{ /*** make_screen ***/
/******** LOCAL VARIABLES ********/
register ENT_DEF *ent; /* pointer to current directory entry */
register short file_count = 0; /* number of files processed */
static int rend_set, /* rendition setting for slots */
scr_row, /* what row on screen to write to */
scr_col; /* what column on screen to write to */
static short i, /* loop and array index */
j; /* " " " " */
char buf[BUFSIZ+1]; /* formatting buffer */
/* get pointer to the first directory entry for the current screen */
ent = dirptr + (u_long) ((curr_screen - 1) * num_slot);
j = 0;
while((j < node_col_max) && (file_count < scr_file))
{
i = 0;
scr_col = nodes[i][j].column + 1; /* get column value for now */
scr_row = 0;
while((i < node_row_max) && (file_count < scr_file))
{
/* create the screen slot for the file; this included determining
* if we need to put something special up in case the file has
* some command(s) associated with it
*/
rend_set = make_slot(buf,ent,args,slot_width,text_flag);
/* now write the file information to the screen in the right spot */
put_slot(window,scr_row,scr_col,buf,rend_set);
i++; /* move to next column */
file_count++; /* count this file as processed */
scr_row++; /* move to next row on screen */
ent++; /* go to next directory entry */
}
j++; /* go down the screen node matrix */
}
if(num_slot > scr_file) /* do we need to clear out some of */
{ /* the slots on the screen? */
/* clear out the slots */
while(i++ < node_row_max)
{
wmove(window,scr_row++,scr_col);
wclrtoeol(window);
}
if(j < node_col_max)
{
/* we have more than one column to clear out */
scr_col += slot_width + 1;
scr_row = 0;
while(scr_row < node_row_max)
{
wmove(window,scr_row++,scr_col);
wclrtoeol(window);
}
}
}
return;
} /*** make_screen ***/
/*******************************************************************************
********************************************************************************
Function: check_marks
Purpose: Check to see if there are any marks in the current directory.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
TRUE marks exist in current directory
FALSE no marks in current directory
********************************************************************************
*******************************************************************************/
int check_marks(ent,num_files)
/******* FORMAL PARAMETERS *******/
register ENT_DEF *ent; /* pointer to current file entry */
register short num_files; /* number of files in directory */
{ /*** check_marks ***/
while(num_files--) /* check all entries if necessary */
{
if(ent->command) /* command for this file? */
return(TRUE); /* yes, no need to check any more */
ent++; /* nope, go to next entry */
}
return(FALSE);
} /*** check_marks ***/
/*******************************************************************************
********************************************************************************
Function: get_dir_mem
Purpose: Compute the amount of memory needed for the current directory
and allocate it. Also set the global pointer to the base of
the memory so that it may be used for sorting if so desired.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
baseptr X X
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void get_dir_mem(dirptr,dirsize,num_file)
/******* FORMAL PARAMETERS *******/
ENT_DEF **dirptr; /* where to store pointer to memory */
u_int *dirsize; /* amount of memory allocated */
short num_file; /* number of files in directory */
{ /*** get_dir_mem ***/
/******** LOCAL VARIABLES ********/
u_int memsize; /* amount of memory to allocated */
/* allocate enough memory to hold the information about each of the
* files in the current directory; we get the amount of memory by multi-
* plying the number of files (plus 1, in case we want to sort them)
* in the directory by the length the structure definition that holds
* the information about a file
*/
/* compute how much memory to allocate */
memsize = (u_int) ((num_file + 1) * sizeof(ENT_DEF));
*dirsize = memsize;
baseptr = (ENT_DEF *) malloc(memsize);
if(baseptr == NULL)
{
exit(CANT_ALLOCATE);
}
else
*dirptr = baseptr;
/* memory allocated for the directory */
return;
} /*** get_dir_mem ***/
/*******************************************************************************
********************************************************************************
Function: get_dir
Purpose: Get the number of files in the current directory, allocate the
necessary memory to store the information about the directory,
and obtain the information about the individual files.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void get_dir(dirptr,args,num_block,curr_pool,num_file,pool_length)
/******* FORMAL PARAMETERS *******/
register ENT_DEF *dirptr; /* pointer to allocated memory */
register ARG_DEF *args; /* run-time argument flags */
long *num_block; /* number of blocks in directory */
POOL_DEF **curr_pool; /* pointer to current memory pool */
short *num_file; /* number of files in directory */
size_t pool_length; /* length to allocate for new pools */
{ /*** get_dir ***/
/******** LOCAL VARIABLES ********/
#if !defined(SYSV)
register struct direct *dir_ent; /* pointer to directory file entry */
#else
register struct dirent *dir_ent; /* Suns use this as well as SysV */
#endif
size_t name_length; /* length of filename */
DIR *dptr; /* pointer to directory file */
dptr = opendir("."); /* open directory so we can read it */
if(dptr == NULL)
return;
/* process all of the directory entries that we can get */
while((dir_ent = readdir(dptr)) != NULL)
{
/*try to make the directory entry for this file */
if(args->dot_files == TRUE || dir_ent->d_name[0] != '.')
{
if(make_ent(dirptr,dir_ent->d_name,num_block) == SUCCESS)
{
/* everything ok so far; store the full filename in a memory pool */
name_length = strlen(dir_ent->d_name);
put_pool(&(dirptr->filename),curr_pool,dir_ent->d_name,name_length,
pool_length);
dirptr++;
}
else
*num_file -= 1; /* bummer; subtract one from num_file */
}
}
closedir(dptr);
/* create a dummy entry at the end in case we want to sort */
if(sizeof(int) == 4)
{
dirptr->size = 0xEFFFFFFF;
dirptr->time = 0xEFFFFFFF;
}
else
{
dirptr->size = 0xEFFF;
dirptr->time = 0xEFFF;
}
put_pool(&(dirptr->filename),curr_pool,"~~~~~~~~~~",10,pool_length);
if(args->sort)
sort_files(*num_file - 1,args->sort);
/* *num_block = (long) kbytes(dbtob(*num_block)); */
return;
} /*** get_dir ***/
/*******************************************************************************
********************************************************************************
Function: get_num_file
Purpose: Get the number of files in the current directory.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
count number of files in directory
-1 failure
********************************************************************************
*******************************************************************************/
short get_num_file(args)
/******* FORMAL PARAMETERS *******/
register ARG_DEF *args; /* run-time arguments */
{ /*** get_num_file ***/
/******** LOCAL VARIABLES ********/
register DIR *dptr; /* pointer to directory file entry */
register short count; /* number of files in directory */
#if !defined(SYSV)
register struct direct *dir_ent; /* pointer to directory file entry */
#else
register struct dirent *dir_ent; /* Suns use this as well as SysV */
#endif
dptr = opendir("."); /* open the current directory */
if(dptr == NULL)
return(-1);
count = 0;
if(args->dot_files == TRUE)
{
while(readdir(dptr) != NULL)
++count;
}
else
{
while((dir_ent = readdir(dptr)) != NULL)
{
if(dir_ent->d_name[0] != '.')
++count;
}
}
closedir(dptr);
return(count); /* return number of files */
} /*** get_num_file ***/
/*******************************************************************************
********************************************************************************
Function: mystrcpy
Purpose: Version of strcpy that copies a string and returns a pointer
to the null character in the destination string.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
dest - 1 pointer to null character terminating the
destionation string
********************************************************************************
*******************************************************************************/
char *mystrcpy(dest,source)
/******* FORMAL PARAMETERS *******/
char *dest, /* destination string */
*source; /* source string */
{ /*** mystrcpy ***/
while(*dest++ = *source++) /* copy the source string to the dest */
;
return(dest - 1); /* return pointer to null character */
} /*** mystrcpy ***/
/*******************************************************************************
********************************************************************************
Function: mystrmcpy
Purpose: Version of strncpy that copies exactly n characters and
returns a pointer to the null character in the destination
string.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
dest - 1 pointer to null character terminating the
destionation string
********************************************************************************
*******************************************************************************/
char *mystrmcpy(dest,source,length)
/******* FORMAL PARAMETERS *******/
char *dest, /* destination string */
*source; /* source string */
int length; /* max. length to copy */
{ /*** mystrmcpy ***/
while(*source != '\0' && length-- >= 0)
*dest++ = *source++;
*(dest - 1) = '\0'; /* make sure it's a string */
return(dest - 1); /* return pointer to null character */
} /*** mystrmcpy ***/
/*******************************************************************************
********************************************************************************
Function: prot_val_to_str
Purpose: Create the string representing the file protection for a
specific file from the integer value for the protection.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
buf protection string
********************************************************************************
*******************************************************************************/
char *prot_val_to_str(prot)
/******* FORMAL PARAMETERS *******/
register u_short prot; /* protection word value */
{ /*** prot_val_to_str ***/
/******** LOCAL VARIABLES ********/
register char *str; /* pointer to buffer */
register short i, /* loop and array index */
j,
k;
static char buf[PROT_MAX+1]; /* where to put the protection string */
/* first determine what type of file it is */
str = buf;
switch(prot & S_IFMT)
{
case(S_IFREG):
*str = '-'; /* regular file */
break;
case(S_IFDIR):
*str = 'd'; /* directory */
break;
case(S_IFCHR):
*str = 'c'; /* character special file */
break;
case(S_IFIFO):
*str = 'p'; /* named pipe */
break;
case(S_IFBLK):
*str = 'b'; /* block special file */
break;
#if !defined(SYSV) || defined(sun)
case(S_IFLNK):
*str = 'l'; /* symbolic link */
break;
#endif
default:
*str = '-';
}
/* create the permission string */
k = 1; /* skip over filetype in string */
j = 0;
for(i = 0; i < 3; i++)
{
if(prot & (S_IREAD >> j)) /* check for read permission */
*(str + k) = 'r';
else
*(str + k) = '-';
if(prot & (S_IWRITE >> j)) /* check for write permission */
*(str + k + 1) = 'w';
else
*(str + k + 1) = '-';
if(prot & (S_IEXEC >> j)) /* check for execute permission */
*(str + k + 2) = 'x';
else
*(str + k + 2) = '-';
k += 3;
j += 3;
}
/* check the setuid bit */
if(prot & S_ISUID)
{
/* setuid is set; now see if it is executable */
if(*(str + 3) == 'x')
*(str + 3) = 's';
else
*(str + 3) = 'S';
}
if(prot & S_ISGID)
{
/* setgid is set; now see if it is executable */
if(*(str + 6) == 'x')
*(str + 6) = 's';
else
*(str + 6) = 'S';
}
if(prot & S_ISVTX)
{
/* sticky bit is set */
*(str + 9) = 't';
}
*(str + PROT_MAX) = '\0'; /* make it a string */
return(buf);
} /*** prot_val_to_str ***/
/*******************************************************************************
********************************************************************************
Function: prot_str_to_val
Purpose: Given a protection string and the original integer value
for a file's protection, edit the string and if it is valid,
calculate the new protection integer value.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
SUCCESS
FAILURE invalid protection specification
********************************************************************************
*******************************************************************************/
short prot_str_to_val(str,new_val)
/******* FORMAL PARAMETERS *******/
register char *str; /* protection string */
u_short *new_val; /* calculated protection value */
{ /*** prot_str_to_val ***/
/******** LOCAL VARIABLES ********/
u_short mode, /* protection mode value */
val, /* temporary value */
j, /* loop and array index */
scale; /* scaling factor for current field */
mode = 0;
val = 0; /* digit value */
j = 0; /* start with first group */
scale = 0100;
while(j < (PROT_MAX - 1))
{
switch(*(str + j))
{
case('r'):
val += 4;
break;
case('-'):
break;
default:
return(FAILURE);
}
switch(*(str + j + 1))
{
case('w'):
val += 2;
break;
case('-'):
break;
default:
return(FAILURE);
}
/* add the mode for the current octal digit to the overall mode value */
mode = mode + (scale * val);
scale /= 010; /* scale down for next digit */
val = 0; /* reset temporary digit value */
j += 3;
}
/* now handle the x/s/S field of the first TWO digits in the mode string;
* we'll do the sticky bit last
*/
switch(*(str + 2))
{
case('-'):
break;
case('x'):
mode += 0100;
break;
case('s'):
mode += 04100;
break;
case('S'):
mode += 04000;
break;
default:
return(FAILURE);
}
switch(*(str + 5))
{
case('-'):
break;
case('x'):
mode += 010;
break;
case('s'):
mode += 02010;
break;
case('S'):
mode += 02000;
break;
default:
return(FAILURE);
}
/* check for the last field */
switch(*(str + 8))
{
case('-'):
break;
case('x'):
mode++;
break;
case('t'):
mode += 01000; /* sticky bit; only works for root */
break;
default:
return(FAILURE);
}
if(*(str + 9))
return(FAILURE); /* string too long */
*new_val = mode; /* ok here; set the return value */
return(SUCCESS);
} /*** prot_str_to_val ***/
/*******************************************************************************
********************************************************************************
Function: set_args
Purpose: Set the original values for ent_factor and slot_width along
with initializing some of the other flags that provide infor-
mation about what run-time arguments were specified.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
COLS
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void set_args(args,slot_width,ent_factor)
/******* FORMAL PARAMETERS *******/
register ARG_DEF *args; /* run-time argument flags */
short *slot_width; /* starting slot width */
size_t *ent_factor; /* ent. size memory allocation factor */
{ /*** set_args ***/
/* initialize the width to include the length of the filename that
* will be displayed and the spot to hold the cursor; also update
* the entry size factor for later
*/
*slot_width = DISP_MAX;
*ent_factor = FUDGE_FACTOR;
/* we have to see what info should be included to get the
* slot width and the entry factor
*/
if(args->date)
*slot_width = *slot_width + DATE_MAX + FIELD_GAP;
if(args->size)
*slot_width = *slot_width + SIZE_MAX + FIELD_GAP;
if(args->prot)
*slot_width = *slot_width + PROT_MAX + FIELD_GAP;
if(args->owner)
*slot_width = *slot_width + OWNER_MAX + FIELD_GAP;
if(args->group)
*slot_width = *slot_width + GROUP_MAX + FIELD_GAP;
if(args->text)
{
/* the user wants text descriptors */
*ent_factor = *ent_factor + TEXT_MAX + 1;
*slot_width = *slot_width + TEXT_MAX + FIELD_GAP;
/* now see if there is enough room to include the text descriptors on
* the screen
*/
if(*slot_width > (COLS - 1))
{
args->text = SLOT_OVF; /* they overflow the file slots */
*slot_width = *slot_width - (TEXT_MAX + FIELD_GAP);
}
}
if(*slot_width == DISP_MAX)
args->def = 1; /* just default info on screen */
else
args->def = 0; /* clear to be thorough..... */
return;
} /*** set_args ***/
/*******************************************************************************
********************************************************************************
Function: set_width
Purpose: Set the slot width for the current directory based on whether
or not text descriptors will be included on the screen
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void set_width(slot_width,text_flag)
/******* FORMAL PARAMETERS *******/
short *slot_width, /* current slot width */
text_flag; /* text descrips included for dir? */
{ /*** set_width ***/
/* should we at least TRY to get text descriptors on the screen? */
if(text_flag == DISPLAY_TEXT)
{
/* yes, they need to be displayed; increase the slot_width
* to accommodate them
*/
*slot_width = *slot_width + TEXT_MAX + 1;
}
return;
} /*** set_width ***/
/*******************************************************************************
********************************************************************************
Function: banystr
Purpose: Determine if a finite-length character string contains
any characters from a second null-terminated character
string.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
>=0 match was found; return code is the offset
into str1 where the character is found
-1 no common characters in the two strings
********************************************************************************
*******************************************************************************/
short banystr(str1,str2,length)
/******* FORMAL PARAMETERS *******/
register char *str1, /* string to search */
*str2; /* what to look for */
short length; /* when to stop searching */
{ /*** banystr ***/
/******** LOCAL VARIABLES ********/
register int offset1, /* offset into string str1 */
offset2; /* offset into string str2 */
if(str1 == NULL || str2 == NULL || length <= 0)
return(-1);
if((*str1 == '\0') || (*str2 == '\0'))
return(-1);
offset1 = 0;
while(*(str1+offset1) != '\0' && length--)
{
offset2 = 0;
while(*(str2+offset2) != '\0')
{
if(*(str1+offset1) == *(str2+offset2))
{
return(offset1); /* match found; return offset */
}
++offset2;
}
++offset1;
}
return(-1); /* no match; return -1 */
} /*** banystr ***/
/*******************************************************************************
********************************************************************************
Function: set_type
Purpose: Determine the type of a file and return it.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
REGULAR regular file
DIRECTORY directory
CHARACTER character-type special file
BLOCK block special file
FIFO FIFO (named pipe)
SOCKET socket file
LINK symbolic link
********************************************************************************
*******************************************************************************/
static u_char set_type(mode)
/******* FORMAL PARAMETERS *******/
u_short mode; /* protection mode to examine */
{ /*** set_type ***/
switch(mode & S_IFMT)
{
#if !defined(SYSV) || defined(sun)
case(S_IFLNK):
return(LINK);
#endif
case(S_IFREG):
return(REGULAR);
case(S_IFDIR):
return(DIRECTORY);
case(S_IFCHR):
return(CHARACTER);
case(S_IFBLK):
return(BLOCK);
#if !defined(SYSV) || defined(sun)
case(S_IFSOCK):
return(SOCKET);
#endif
case(S_IFIFO):
return(FIFO);
default:
break;
}
return(REGULAR); /* default is regular type */
} /*** set_type ***/
/*******************************************************************************
********************************************************************************
Function: set_date
Purpose: Create a date string for a file.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
curr_year X
Return Codes:
Code Reason
---- ------
date_buf buffer where date string is stored
********************************************************************************
*******************************************************************************/
char *set_date(time_val)
/******* FORMAL PARAMETERS *******/
time_t time_val; /* binary time value */
{ /*** set_date ***/
/******** LOCAL VARIABLES ********/
struct tm *time_str; /* time structure */
static char date_buf[DATE_MAX+1];
static char *month[] =
{"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
time_str = localtime(&time_val);
if(time_str->tm_year == curr_year)
sprintf(date_buf,"%3s %2d %2d:%1d%1d",month[time_str->tm_mon],
time_str->tm_mday,time_str->tm_hour,time_str->tm_min/10,
time_str->tm_min%10);
else
sprintf(date_buf,"%3s %2d %4d",month[time_str->tm_mon],
time_str->tm_mday,time_str->tm_year + 1900);
return(date_buf);
} /*** set_date ***/
/*******************************************************************************
********************************************************************************
Function: padcpy
Purpose: Copy a counted string, padding with spaces.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
date_buf buffer where date string is stored
********************************************************************************
*******************************************************************************/
char *padcpy(dest,source,length)
/******** LOCAL VARIABLES ********/
char *dest, /* destination string */
*source; /* source string */
int length; /* length that destination should be */
{ /*** padcpy ***/
if(source != NULL && *source != '\0')
{
while(*source && length--) /* copy it */
*dest++ = *source++;
}
while(length-- > 0) /* pad it */
*dest++ = ' ';
*dest = '\0'; /* make it a string */
return(dest);
} /*** padcpy ***/
/*******************************************************************************
********************************************************************************
Function: add_filetype
Purpose: Set the filetype in an integer file mode.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
prot new protection value
********************************************************************************
*******************************************************************************/
u_short add_filetype(type,prot)
/******* FORMAL PARAMETERS *******/
u_char type; /* type of file */
u_short prot; /* protection mode to work with */
{ /*** add_filetype ***/
switch(type)
{
case(REGULAR):
prot |= S_IFREG;
break;
case(DIRECTORY):
prot |= S_IFDIR;
break;
case(CHARACTER):
prot |= S_IFCHR;
break;
case(BLOCK):
prot |= S_IFBLK;
break;
case(FIFO):
prot |= S_IFIFO;
break;
#if !defined(SYSV) || defined(sun)
case(SOCKET):
prot |= S_IFSOCK;
break;
case(LINK):
prot |= S_IFLNK;
break;
#endif
default:
prot |= S_IFREG;
break;
}
return(prot);
} /*** add_filetype ***/
/*******************************************************************************
********************************************************************************
Function: spawn
Purpose: Fork off a process to let the user return to the shell.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
SUCCESS
FAILURE
********************************************************************************
*******************************************************************************/
int spawn()
{ /*** spawn ***/
/******** LOCAL VARIABLES ********/
char *tptr, /* temporary pointer */
*shell; /* pointer to the user's shell */
int child, /* pid of child process */
i; /* loop and return value */
#if !defined(SYSV) || defined(sun)
union wait status;
#else
int status;
#endif
shell = getenv("SHELL"); /* get what shell to use */
if(shell == NULL || *shell == '\0')
shell = DEFAULT_SHELL; /* user didn't have a SHELL variable */
tptr = strrchr(shell,'/'); /* find last level of shell name */
if(tptr == NULL)
tptr = shell;
else
tptr++;
if((child = vfork()) == 0)
{
/* we're in the child */
endwin(); /* make sure tty is reset */
execlp(shell,tptr,NULL); /* no return from this */
return(FAILURE); /* failure if we get here */
}
else if(child > 0)
{
/* we're in the parent; wait for the child to finish */
while(((i = wait(&status)) != child) && i > 0)
;
}
else
return(FAILURE); /* can't fork */
return(SUCCESS);
} /*** spawn ***/
/*******************************************************************************
********************************************************************************
Function: check_nlen
Purpose: Check if a filename (as displayed) would be longer than
DISP_MAX. This info is useful in make_slot() when we are
deciding what has to be tagged.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
count displayed length of filename
********************************************************************************
*******************************************************************************/
static u_short check_nlen(filename)
/******* FORMAL PARAMETERS *******/
register char *filename; /* filename to be checked */
{ /*** check_nlen ***/
/******** LOCAL VARIABLES ********/
register u_short count; /* length of displayed filename */
count = 0;
while(*filename)
{
if(!iscntrl(*filename))
count++;
else
count += 2;
++filename;
}
return(count);
} /*** check_nlen ***/
/*******************************************************************************
********************************************************************************
Function: strtcpy
Purpose: Copy one string to another, translating control characters to
a two-character pair of ^ and the printable control character.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
count displayed length of filename
********************************************************************************
*******************************************************************************/
int strtcpy(dest,source)
/******* FORMAL PARAMETERS *******/
register char *dest, /* destination string */
*source; /* source string */
{ /*** strtcpy ***/
/******** LOCAL VARIABLES ********/
register int length; /* length of resulting string */
length = 0;
while(*source)
{
if(iscntrl(*source))
{
*dest++ = '^';
*dest++ = *source++ + '@'; /* make it printable */
length += 2;
}
else
{
*dest++ = *source++;
++length;
}
}
*dest = '\0'; /* make it a string */
return(length);
} /*** strtcpy ***/
/*******************************************************************************
********************************************************************************
Function: get_filemarks
Purpose: Recreate the displayed names for all of the files in the
current directory so that they include the filemarks. This
is normally only done after the filemarks are selected from
the options menu.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void get_filemarks(dirptr,num_file)
/******* FORMAL PARAMETERS *******/
register ENT_DEF *dirptr; /* pointer to directory information */
register short num_file; /* number of files in directory */
{ /*** get_filemarks ***/
while(num_file-- > 0)
{
strcpy(dirptr->scr_name,get_name(dirptr->filename,&dirptr->name_len));
dirptr++;
}
return;
} /*** get_filemarks ***/
/*******************************************************************************
********************************************************************************
Function: get_name
Purpose: Create the filename that will be displayed in a slot, including
translating non-printable characters.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
args.filemarks X
Return Codes:
Code Reason
---- ------
retptr pointer to displayed filename string
********************************************************************************
*******************************************************************************/
static char *get_name(filename,length,prot,type)
/******* FORMAL PARAMETERS *******/
char *filename; /* original filename */
u_short *length, /* length of filename minus padding */
prot; /* integer protection value */
u_char type; /* file type */
{ /*** get_name ***/
/******** LOCAL VARIABLES ********/
register char *tptr; /* temporary character pointer */
register u_short i; /* loop and array index */
static char newname[DISP_MAX+1]; /* where to store translated name */
i = 0;
tptr = newname;
while((i < DNAME_MAX) && (*filename != '\0'))
{
if(*filename >= ' ')
{
*tptr = *filename;
tptr++;
filename++;
++i;
}
else
{
*tptr++ = '^'; /* non-printable; translate it */
++i;
if(i < DNAME_MAX)
{
*tptr = *filename + '@';
++i;
tptr++;
}
filename++;
}
}
/* pad the name with spaces */
if(args.filemarks)
*tptr++ = filetype_char(prot,type);
else
*tptr++ = ' ';
*length = ++i; /* count the filemark char */
while(i++ < DISP_MAX)
*tptr++ = ' ';
*tptr = '\0'; /* make sure it's a string */
return(newname);
} /*** get_name ***/
/*******************************************************************************
********************************************************************************
Function: filetype_char
Purpose: Determine what character should be appended to the filename
for the -F option.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
retval filetype character
********************************************************************************
*******************************************************************************/
u_char filetype_char(prot,type)
/******* FORMAL PARAMETERS *******/
u_short prot; /* file protection word */
u_char type; /* type of file */
{ /*** filetype_char ***/
/******** LOCAL VARIABLES ********/
u_char retval; /* file type char (for -F) */
switch(type)
{
case(DIRECTORY):
retval = '/';
break;
case(SOCKET):
retval = '=';
break;
#if !defined(SYSV) || defined(sun)
case(LINK):
retval = '@';
break;
#endif
case(REGULAR):
/* determine if the file is executable */
if(prot & (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)))
retval = '*';
else
retval = ' ';
break;
default:
retval = ' ';
break;
}
return(retval);
} /*** filetype_char ****/
/*******************************************************************************
********************************************************************************
Function: squeeze_str
Purpose: Squeeze the whitespace characters out of a string
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void squeeze_str(str)
/******* FORMAL PARAMETERS *******/
register char *str; /* string to be squeezed */
{ /*** squeeze_str ***/
/******** LOCAL VARIABLES ********/
register char *ptr; /* temporary pointer */
ptr = str;
while(*ptr)
{
if(!isspace(*ptr))
*str++ = *ptr++;
else
ptr++;
}
*str = '\0'; /* make sure it's a string */
return;
} /*** squeeze_str ***/
/*******************************************************************************
********************************************************************************
Function: follow_link
Purpose: Given a filename that is a symbolic link, try to find out what
it points to.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
REGULAR
DIRECTORY
CHARACTER
BLOCK
LINK
SOCKET
********************************************************************************
*******************************************************************************/
int follow_link(linkname)
/******* FORMAL PARAMETERS *******/
char *linkname; /* link to follow */
{ /*** follow_link ***/
/******** LOCAL VARIABLES ********/
struct stat statbuf; /* for stat'ing the file */
if(stat(linkname,&statbuf) == -1)
return(FAILURE);
switch(statbuf.st_mode & S_IFMT)
{
case(S_IFREG):
return(REGULAR);
case(S_IFDIR):
return(DIRECTORY);
case(S_IFCHR):
return(CHARACTER);
case(S_IFBLK):
return(BLOCK);
#if !defined(SYSV) || defined(sun)
case(S_IFLNK):
return(LINK);
case(S_IFSOCK):
return(SOCKET);
#endif
default:
break;
}
return(REGULAR);
} /*** follow_link ***/
/*******************************************************************************
********************************************************************************
Function: get_bnum
Purpose: Get the number of blocks that a file occupies and return it.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
kbytes(...) number of blocks the file occupies
********************************************************************************
*******************************************************************************/
long get_bnum(filename)
/******* FORMAL PARAMETERS *******/
char *filename; /* file to be examined */
{ /*** get_bnum ***/
/******** LOCAL VARIABLES ********/
struct stat statbuf; /* for doing a stat */
if(stat(filename,&statbuf) != 0)
return(0L);
#if !defined(SYSV) || defined(sun)
return((long) statbuf.st_blocks);
#else
return((long) statbuf.st_size);
#endif
} /*** get_bnum ***/
/*******************************************************************************
********************************************************************************
Function: cont_after_stop
Purpose: Signal hander called when restarting after being suspended
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
main_win X
spec_win X
stat_win X
Return Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
void cont_after_stop()
{ /*** cont_after_stop ***/
/* redraw the screen after resuming */
touchwin(spec_win);
touchwin(main_win);
touchwin(stat_win);
wrefresh(spec_win);
wrefresh(main_win);
wrefresh(stat_win);
return;
} /*** cont_after_stop ***/
/*******************************************************************************
********************************************************************************
Function: cat
Purpose: Concatenate strings into one string.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
retval pointer to destination string
NULL null string pointer; returned when
no arguments are passed
Termination Codes:
Code Reason
---- ------
none
Description of Linkage:
char *rc,
*cat();
rc = cat(num_args,dest,source1,source2,...sourcen);
where dest is a pointer to a character string allocated by
the caller and is large enough to hold the resulting string
and source1, source2,...sourcen are pointers to character
strings to be concatenated.
********************************************************************************
*******************************************************************************/
char *cat(va_alist)
/******* FORMAL PARAMETERS *******/
va_dcl /* variable-length parameter list */
{ /*** cat ***/
/******** LOCAL VARIABLES ********/
static char *dest, /* pointer to destination string */
*source; /* pointer to current source string */
static char *retval; /* to save pointer to destination */
static int count; /* number of arguments passed */
static va_list incrmtr; /* argument list incrementor */
va_start(incrmtr); /* begin everything.... */
count = va_arg(incrmtr,int); /* get number of arguments */
if(count <= 1) /* enough arguments? */
return(NULL); /* nope, get out of here... */
dest = va_arg(incrmtr,char*); /* get the destination pointer */
retval = dest; /* save pointer to destination */
--count; /* subtract for first argument */
while(count > 0) /* process all of the source strings */
{
source = va_arg(incrmtr,char*); /* get the next argument */
while(*dest++ = *source++) /* cat the source to the destination */
;
dest--; /* back over the null character */
count--;
}
*dest = '\0'; /* terminate the destination */
va_end(incrmtr); /* end varargs session */
return(retval); /* return pointer to destination */
} /*** cat ***/
/*******************************************************************************
********************************************************************************
Function: strindex
Purpose: Return the position of one string in another.
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
-1 key not found in str or key is a null
pointer or str is a null pointer
offset offset into str where key is located
Termination Codes:
Code Reason
---- ------
none
Description of Linkage:
int strindex();
rc = strindex(str,key);
********************************************************************************
*******************************************************************************/
int strindex(str,key)
/******* FORMAL PARAMETERS *******/
register char *str, /* string to be searched */
*key; /* string to be searched for */
{ /*** strindex ***/
/******** LOCAL VARIABLES ********/
register int i, /* primary pointer to str */
j, /* secondary pointer to str for com- */
/* parison */
k; /* pointer to key for comparison */
if(str == NULL || key == NULL || *str == '\0' || *key == '\0')
return(-1);
i = 0;
while(*(str+i) != '\0')
{
j = i;
k = 0;
/* look for a match */
while((*(str+j) == *(key+k)) && (*(str+j) != '\0') && (*(key+k) != '\0'))
{
++j;
++k;
}
if(*(key+k) == '\0')
return(i); /* key was found */
else if(*(str+j) == '\0')
return(-1); /* key was not found */
++i; /* not sure yet; keep trying... */
}
/* if we get to here, the key was not found */
return(-1);
} /*** strindex ***/
/*******************************************************************************
********************************************************************************
Function: rename
Purpose: Fake a rename function for System V machines
Global variables:
Name Examine/Modify/Use/Read/Write
---- -----------------------------
none
Return Codes:
Code Reason
---- ------
-1 key not found in str or key is a null
pointer or str is a null pointer
offset offset into str where key is located
Termination Codes:
Code Reason
---- ------
none
********************************************************************************
*******************************************************************************/
#if defined(SYSV) && !defined(sun)
int rename(source,dest)
/******* FORMAL PARAMETERS *******/
char *source, /* file to be renamed */ *dest; /* what to call it */
{ /*** rename ***/
if(link(source,dest))
return(-1);
if(unlink(source))
return(-1);
return(0);
} /*** rename ***/
#endif