minix/commands/de/de_stdout.c
2010-05-12 16:28:54 +00:00

1173 lines
25 KiB
C

/****************************************************************/
/* */
/* de_stdout.c */
/* */
/* Displaying information from the "Disk editor". */
/* */
/****************************************************************/
/* origination 1989-Jan-15 Terrence W. Holm */
/****************************************************************/
#include <minix/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <grp.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <termcap.h>
#include <time.h>
#include <unistd.h>
#include <minix/const.h>
#include <minix/type.h>
#include "mfs/const.h"
#include "mfs/type.h"
#include "mfs/inode.h"
#include <minix/fslib.h>
#include "de.h"
#ifndef major
#define major(x) ( (x>>8) & 0377)
#define minor(x) (x & 0377)
#endif
/****************************************************************/
/* Code for handling termcap */
/****************************************************************/
#define TC_BUFFER 1024 /* Size of termcap(3) buffer */
#define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
static char *Tmove; /* (cm) - Format for tgoto */
static char *Tclr_all; /* (cl) - Clear screen */
static char *Treverse; /* (so) - Start reverse mode */
static char *Tnormal; /* (se) - End reverse mode */
char Kup = 0; /* (ku) - Up arrow key */
char Kdown = 0; /* (kd) - Down arrow key */
char Kleft = 0; /* (kl) - Left arrow key */
char Kright = 0; /* (kr) - Right arrow key */
_PROTOTYPE(void Goto , (int column , int line ));
_PROTOTYPE(void Block_Type , (de_state *s ));
_PROTOTYPE(void Draw_Words , (de_state *s ));
_PROTOTYPE(void Draw_Info , (de_state *s ));
_PROTOTYPE(void Draw_Block , (char *block ));
_PROTOTYPE(void Draw_Map , (char *block , int max_bits ));
_PROTOTYPE(void Draw_Offset , (de_state *s ));
_PROTOTYPE(void Word_Pointers , (off_t old_addr , off_t new_addr ));
_PROTOTYPE(void Block_Pointers , (off_t old_addr , off_t new_addr ));
_PROTOTYPE(void Map_Pointers , (off_t old_addr , off_t new_addr ));
_PROTOTYPE(void Print_Number , (Word_t number , int output_base ));
_PROTOTYPE(void Draw_Zone_Numbers , (de_state *s , struct inode *inode ,
int zindex , int zrow ));
/****************************************************************/
/* */
/* Init_Termcap() */
/* */
/* Initializes the external variables for the */
/* current terminal. */
/* */
/****************************************************************/
int Init_Termcap()
{
char *term;
char buffer[ TC_BUFFER ];
static char strings[ TC_STRINGS ];
char *s = &strings[0];
char *Kcode;
term = getenv( "TERM" );
if ( term == NULL )
return( 0 );
if ( tgetent( buffer, term ) != 1 )
return( 0 );
if ( (Tmove = tgetstr( "cm", &s )) == NULL )
return( 0 );
if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
return( 0 );
if ( (Treverse = tgetstr( "so", &s )) == NULL )
{
Treverse = Tnormal = s;
*s = '\0';
++s;
}
else if ( (Tnormal = tgetstr( "se", &s )) == NULL )
return( 0 );
/* See if there are single character arrow key codes */
if ( (Kcode = tgetstr( "ku", &s )) != NULL && strlen( Kcode ) == 1 )
Kup = Kcode[0];
if ( (Kcode = tgetstr( "kd", &s )) != NULL && strlen( Kcode ) == 1 )
Kdown = Kcode[0];
if ( (Kcode = tgetstr( "kl", &s )) != NULL && strlen( Kcode ) == 1 )
Kleft = Kcode[0];
if ( (Kcode = tgetstr( "kr", &s )) != NULL && strlen( Kcode ) == 1 )
Kright = Kcode[0];
return( 1 );
}
/****************************************************************/
/* */
/* Goto( column, line ) */
/* */
/* Use the termcap string to move the cursor. */
/* */
/****************************************************************/
void Goto( column, line )
int column;
int line;
{
fputs( tgoto( Tmove, column, line ), stdout );
}
/****************************************************************/
/* Output routines */
/****************************************************************/
/****************************************************************/
/* */
/* Draw_Help_Screen() */
/* */
/****************************************************************/
void Draw_Help_Screen( s )
de_state *s;
{
int down;
int right;
switch ( s->mode )
{
case WORD : down = 2; right = 32; break;
case BLOCK : down = 64; right = 1; break;
case MAP : down = 256; right = 4; break;
}
printf( "%s ", Tclr_all );
printf( "%sDE COMMANDS%s\r\n\n\n", Treverse, Tnormal );
printf( " PGUP b Back one block h Help\r\n" );
printf( " PGDN f Forward one block q Quit\r\n" );
printf( " HOME B Goto first block m Minix shell\r\n" );
printf( " END F Goto last block\r\n" );
printf( " v Visual mode (w b m)\r\n" );
printf( " g Goto specified block o Output base (h d o b)\r\n" );
printf( " G Goto block indirectly\r\n" );
printf( " i Goto i-node c Change file name\r\n" );
printf( " I Filename to i-node w Write ASCII block\r\n" );
printf( " W Write block exactly\r\n" );
printf( " / Search\r\n" );
printf( " n Next occurrence x Extract lost entry\r\n" );
printf( " p Previous address X Extract lost blocks\r\n" );
printf( " s Store word\r\n" );
printf( " UP u Move back %d bytes\r\n", down );
printf( " DOWN d Move forward %d bytes\r\n", down );
printf( " LEFT l Move back %d byte%s\r\n", right,
right == 1 ? "" : "s" );
printf( " RIGHT r Move forward %d byte%s\r\n\n\n", right,
right == 1 ? "" : "s" );
}
/****************************************************************/
/* */
/* Wait_For_Key() */
/* */
/* The user must press a key to continue. */
/* */
/****************************************************************/
void Wait_For_Key()
{
Draw_Prompt( "Press a key to continue..." );
Get_Char();
}
/****************************************************************/
/* */
/* Draw_Prompt( string ) */
/* */
/* Write a message in the "prompt" area. */
/* */
/****************************************************************/
void Draw_Prompt( string )
char *string;
{
Goto( PROMPT_COLUMN, PROMPT_LINE );
printf( "%s%s%s ", Treverse, string, Tnormal );
}
/****************************************************************/
/* */
/* Erase_Prompt() */
/* */
/* Erase the message in the "prompt" area. */
/* */
/****************************************************************/
void Erase_Prompt()
{
Goto( PROMPT_COLUMN, PROMPT_LINE );
printf( "%77c", ' ' );
Goto( PROMPT_COLUMN, PROMPT_LINE );
}
/****************************************************************/
/* */
/* Draw_Screen( state ) */
/* */
/* Redraw everything, except pointers. */
/* */
/****************************************************************/
void Draw_Screen( s )
de_state *s;
{
fputs( Tclr_all, stdout );
Draw_Strings( s );
Block_Type( s );
switch ( s->mode )
{
case WORD : Draw_Words( s );
Draw_Info( s );
break;
case BLOCK : Draw_Block( s->buffer );
break;
case MAP : {
int max_bits = 2 * K;
/* Don't display the bits after the end */
/* of the i-node or zone bit maps. */
if ( s->block == 2 + s->inode_maps - 1 )
max_bits = (int)
(s->inodes_in_map
- CHAR_BIT * K * (ino_t) (s->inode_maps - 1)
- CHAR_BIT * (ino_t) (s->offset & ~ MAP_MASK));
else if ( s->block == 2 + s->inode_maps + s->zone_maps - 1 )
max_bits = (int)
(s->zones_in_map
- CHAR_BIT * K * (zone_t) (s->zone_maps - 1)
- CHAR_BIT * (zone_t) (s->offset & ~ MAP_MASK));
if ( max_bits < 0 )
max_bits = 0;
Draw_Map( &s->buffer[ s->offset & ~ MAP_MASK ], max_bits );
break;
}
}
}
/****************************************************************/
/* */
/* Draw_Strings( state ) */
/* */
/* The first status line contains the device name, */
/* the current write file name (if one is open) */
/* and the current search string (if one has */
/* been defined). */
/* */
/* Long strings are truncated. */
/* */
/****************************************************************/
void Draw_Strings( s )
de_state *s;
{
int len;
int i;
Goto( STATUS_COLUMN, STATUS_LINE );
printf( "Device %s= %-14.14s ",
s->device_mode == O_RDONLY ? "" : "(w) ", s->device_name );
switch ( s->magic )
{
case SUPER_MAGIC : printf( "V1 file system ");
break;
case SUPER_REV : printf( "V1-bytes-swapped file system (?) ");
break;
case SUPER_V2 : printf( "V2 file system ");
break;
case SUPER_V2_REV : printf( "V2-bytes-swapped file system (?) ");
break;
case SUPER_V3 : printf( "V3 file system ");
break;
default : printf( "not a Minix file system ");
break;
}
len = strlen( s->file_name );
if ( len == 0 )
printf( "%29s", " " );
else if ( len <= 20 )
printf( "File = %-20s ", s->file_name );
else
printf( "File = ...%17.17s ", s->file_name + len - 17 );
len = strlen( s->search_string );
if ( len == 0 )
printf( "%20s", " " );
else
{
printf( "Search = " );
if ( len <= 11 )
{
for ( i = 0; i < len; ++i )
Print_Ascii( s->search_string[ i ] );
for ( ; i < 11; ++i )
putchar( ' ' );
}
else
{
for ( i = 0; i < 8; ++i )
Print_Ascii( s->search_string[ i ] );
printf( "..." );
}
}
}
/****************************************************************/
/* */
/* Block_Type( state ) */
/* */
/* Display the current block type. */
/* */
/****************************************************************/
void Block_Type( s )
de_state *s;
{
Goto( STATUS_COLUMN, STATUS_LINE + 1 );
printf( "Block = %5u of %-5u ", s->block, s->zones );
if ( !s->is_fs )
return;
if ( s->block == BOOT_BLOCK )
printf( "Boot block" );
else if ( s->block == 1 )
printf( "Super block" );
else if ( s->block < 2 + s->inode_maps )
printf( "I-node bit map" );
else if ( s->block < 2 + s->inode_maps + s->zone_maps )
printf( "Zone bit map" );
else if ( s->block < s->first_data )
printf( "I-nodes" );
else
printf( "Data block (%sin use)",
In_Use( (bit_t) (s->block - (s->first_data - 1)), s->zone_map )
? "" : "not " );
}
/****************************************************************/
/* */
/* Draw_Words( state ) */
/* */
/* Draw a page in word format. */
/* */
/****************************************************************/
void Draw_Words( s )
de_state *s;
{
int line;
int addr = s->offset & ~ PAGE_MASK;
for ( line = 0; line < 16; ++line, addr += 2 )
{
Goto( BLOCK_COLUMN, BLOCK_LINE + line );
printf( "%5d ", addr );
Print_Number( *( (word_t *) &s->buffer[ addr ] ), s->output_base );
}
Goto( BLOCK_COLUMN + 64, BLOCK_LINE );
printf( "(base %d)", s->output_base );
}
/****************************************************************/
/* */
/* Draw_Info( state ) */
/* */
/* Add information to a page drawn in word format. */
/* The routine recognizes the super block, inodes, */
/* executables and "ar" archives. If the current */
/* page is not one of these, then ASCII characters */
/* are printed from the data words. */
/* */
/****************************************************************/
char *super_block_info[] = { "number of inodes",
"V1 number of zones",
"inode bit map blocks",
"zone bit map blocks",
"first data zone",
"blocks per zone shift & flags",
"maximum file size",
"",
"magic number",
"fsck magic number",
"V2 number of zones" };
void Draw_Info( s )
de_state *s;
{
int i;
int page = s->offset >> PAGE_SHIFT;
dev_t dev;
if ( s->is_fs && s->block == 1 && page == 0 )
for ( i = 0; i < 11; ++i )
{
Goto( INFO_COLUMN, INFO_LINE + i );
printf( "%s", super_block_info[ i ] );
}
else if ( s->is_fs && s->block >= s->first_data - s->inode_blocks &&
s->block < s->first_data )
{
struct inode core_inode;
d1_inode *dip1;
d2_inode *dip2;
struct inode *inode = &core_inode;
int special = 0;
int m;
struct passwd *user;
struct group *grp;
dip1 = (d1_inode *) &s->buffer[ s->offset & ~ PAGE_MASK ];
dip2 = (d2_inode *) &s->buffer[ s->offset & ~ PAGE_MASK
& ~ (V2_INODE_SIZE-1) ];
conv_inode( inode, dip1, dip2, READING, s->magic );
user = getpwuid( inode->i_uid );
grp = getgrgid( inode->i_gid );
if ( s->magic != SUPER_MAGIC && page & 1 )
{
Draw_Zone_Numbers( s, inode, 2, 0 );
return;
}
Goto( INFO_COLUMN, INFO_LINE );
switch( inode->i_mode & S_IFMT )
{
case S_IFDIR : printf( "directory " );
break;
case S_IFCHR : printf( "character " );
special = 1;
break;
case S_IFBLK : printf( "block " );
special = 1;
break;
case S_IFREG : printf( "regular " );
break;
#ifdef S_IFIFO
case S_IFIFO : printf( "fifo " );
break;
#endif
#ifdef S_IFLNK
case S_IFLNK : printf( "symlink " );
break;
#endif
#ifdef S_IFSOCK
case S_IFSOCK: printf( "socket " );
break;
#endif
default : printf( "unknown " );
}
for ( m = 11; m >= 0; --m )
putchar( (inode->i_mode & (1<<m)) ? "xwrxwrxwrtgu"[m] : '-' );
if ( s->magic == SUPER_MAGIC )
{
/* V1 file system */
Goto( INFO_COLUMN, INFO_LINE + 1 );
printf( "user %s", user ? user->pw_name : "" );
Goto( INFO_COLUMN, INFO_LINE + 2 );
printf( "file size %lu", inode->i_size );
Goto( INFO_COLUMN, INFO_LINE + 4 );
printf( "m_time %s", ctime( &inode->i_mtime ) );
Goto( INFO_COLUMN, INFO_LINE + 6 );
printf( "links %d, group %s",
inode->i_nlinks, grp ? grp->gr_name : "" );
Draw_Zone_Numbers( s, inode, 0, 7 );
}
else
{
/* V2 file system, even page. */
Goto( INFO_COLUMN, INFO_LINE + 1 );
printf( "links %d ", inode->i_nlinks);
Goto( INFO_COLUMN, INFO_LINE + 2 );
printf( "user %s", user ? user->pw_name : "" );
Goto( INFO_COLUMN, INFO_LINE + 3 );
printf( "group %s", grp ? grp->gr_name : "" );
Goto( INFO_COLUMN, INFO_LINE + 4 );
printf( "file size %lu", inode->i_size );
Goto( INFO_COLUMN, INFO_LINE + 6 );
printf( "a_time %s", ctime( &inode->i_atime ) );
Goto( INFO_COLUMN, INFO_LINE + 8 );
printf( "m_time %s", ctime( &inode->i_mtime ) );
Goto( INFO_COLUMN, INFO_LINE + 10 );
printf( "c_time %s", ctime( &inode->i_ctime ) );
Draw_Zone_Numbers( s, inode, 0, 12 );
}
if ( special )
{
Goto( INFO_COLUMN, INFO_LINE + 7 );
dev = (dev_t) inode->i_zone[0];
printf( "major %d, minor %d", major(dev), minor(dev) );
}
}
else /* Print ASCII characters for each byte in page */
{
char *p = &s->buffer[ s->offset & ~ PAGE_MASK ];
for ( i = 0; i < 16; ++i )
{
Goto( INFO_COLUMN, INFO_LINE + i );
Print_Ascii( *p++ );
Print_Ascii( *p++ );
}
if ( s->block >= s->first_data && page == 0 )
{
unsigned magic = ((s->buffer[1] & 0xff) << 8) | (s->buffer[0] & 0xff);
unsigned second = ((s->buffer[3] & 0xff) << 8) | (s->buffer[2] & 0xff);
/* Is this block the start of an executable file? */
if ( magic == (unsigned) A_OUT )
{
Goto( INFO_COLUMN, INFO_LINE );
printf( "executable" );
Goto( INFO_COLUMN, INFO_LINE + 1 );
if ( second == (unsigned) SPLIT )
printf( "separate I & D" );
else
printf( "combined I & D" );
}
}
}
}
/****************************************************************/
/* */
/* Draw_Block( block ) */
/* */
/* Redraw a 1k block in character format. */
/* */
/****************************************************************/
void Draw_Block( block )
char *block;
{
int line;
int column;
int reverse = 0;
int msb_flag = 0;
for ( line = 0; line < 16; ++line )
{
Goto( BLOCK_COLUMN, BLOCK_LINE + line );
for ( column = 0; column < 64; ++column )
{
char c = *block++;
if ( c & 0x80 )
{
msb_flag = 1;
c &= 0x7f;
}
if ( c >= ' ' && c < DEL )
{
if ( reverse )
{ fputs( Tnormal, stdout ); reverse = 0; }
putchar( c );
}
else
{
if ( ! reverse )
{ fputs( Treverse, stdout ); reverse = 1; }
putchar( c == DEL ? '?' : '@' + c );
}
} /* end for ( column ) */
} /* end for ( line ) */
if ( reverse )
{ fputs( Tnormal, stdout ); reverse = 0; }
if ( msb_flag )
{
Goto( BLOCK_COLUMN + 68, BLOCK_LINE + 6 );
fputs( "(MSB)", stdout );
}
}
/****************************************************************/
/* */
/* Draw_Map( block, max_bits ) */
/* */
/* Redraw a block in a bit map format. */
/* Display min( max_bits, 2048 ) bits. */
/* */
/* The 256 bytes in "block" are displayed from */
/* top to bottom and left to right. Bit 0 of */
/* a byte is towards the top of the screen. */
/* */
/* Special graphic codes are used to generate */
/* two "bits" per character position. So a 16 */
/* line by 64 column display is 32 "bits" by */
/* 64 "bits". Or 4 bytes by 64 bytes. */
/* */
/****************************************************************/
void Draw_Map( block, max_bits )
char *block;
int max_bits;
{
int line;
int column;
int bit_count = 0;
for ( line = 0; line < 16; ++line )
{
char *p = &block[ (line & 0xC) >> 2 ];
int shift = (line & 0x3) << 1;
Goto( BLOCK_COLUMN, BLOCK_LINE + line );
for ( column = 0; column < 64; ++column, p += 4 )
{
char c = (*p >> shift) & 0x3;
int current_bit = ((p - block) << 3) + shift;
/* Don't display bits past "max_bits" */
if ( current_bit >= max_bits )
break;
/* If "max_bits" occurs in between the two bits */
/* I am trying to display as one character, then */
/* zero off the high-order bit. */
if ( current_bit + 1 == max_bits )
c &= 1;
switch ( c )
{
case 0 : putchar( BOX_CLR );
break;
case 1 : putchar( BOX_TOP );
++bit_count;
break;
case 2 : putchar( BOX_BOT );
++bit_count;
break;
case 3 : putchar( BOX_ALL );
bit_count += 2;
break;
}
} /* end for ( column ) */
} /* end for ( line ) */
Goto( BLOCK_COLUMN + 68, BLOCK_LINE + 6 );
printf( "(%d)", bit_count );
}
/****************************************************************/
/* */
/* Draw_Pointers( state ) */
/* */
/* Redraw the pointers and the offset field. */
/* The rest of the screen stays intact. */
/* */
/****************************************************************/
void Draw_Pointers( s )
de_state *s;
{
Draw_Offset( s );
switch ( s->mode )
{
case WORD : Word_Pointers( s->last_addr, s->address );
break;
case BLOCK : Block_Pointers( s->last_addr, s->address );
break;
case MAP : Map_Pointers( s->last_addr, s->address );
break;
}
Goto( PROMPT_COLUMN, PROMPT_LINE );
}
/****************************************************************/
/* */
/* Draw_Offset( state ) */
/* */
/* Display the offset in the current buffer */
/* and the relative position if within a map */
/* or i-node block. */
/* */
/****************************************************************/
void Draw_Offset( s )
de_state *s;
{
Goto( STATUS_COLUMN, STATUS_LINE + 2 );
printf( "Offset = %5d ", s->offset );
if ( s->block < 2 )
return;
if ( s->block < 2 + s->inode_maps )
{
long bit = (s->address - 2 * K) * 8;
if ( bit < s->inodes_in_map )
printf( "I-node %ld of %d ", bit, s->inodes );
else
printf( "(padding) " );
}
else if ( s->block < 2 + s->inode_maps + s->zone_maps )
{
long bit = (s->address - (2 + s->inode_maps) * K) * 8;
if ( bit < s->zones_in_map )
printf( "Block %ld of %u ", bit + s->first_data - 1, s->zones );
else
printf( "(padding) " );
}
else if ( s->block < s->first_data )
{
bit_t node = (s->address - (2 + s->inode_maps + s->zone_maps) * K) /
s->inode_size + 1;
if ( node <= s->inodes )
printf( "I-node %lu of %lu (%sin use) ",
(unsigned long) node, (unsigned long) s->inodes,
In_Use( node, s->inode_map ) ? "" : "not " );
else
printf( "(padding) " );
}
}
/****************************************************************/
/* */
/* Word_Pointers( old_addr, new_addr ) */
/* */
/* Block_Pointers( old_addr, new_addr ) */
/* */
/* Map_Pointers( old_addr, new_addr ) */
/* */
/* Redraw the index pointers for a each type */
/* of display. The pointer at "old_addr" is */
/* erased and a new pointer is positioned */
/* for "new_addr". This makes the screen */
/* update faster and more pleasant for the user. */
/* */
/****************************************************************/
void Word_Pointers( old_addr, new_addr )
off_t old_addr;
off_t new_addr;
{
int from = ( (int) old_addr & PAGE_MASK ) >> 1;
int to = ( (int) new_addr & PAGE_MASK ) >> 1;
Goto( BLOCK_COLUMN - 2, BLOCK_LINE + from );
putchar( ' ' );
Goto( BLOCK_COLUMN - 2, BLOCK_LINE + to );
putchar( '>' );
}
void Block_Pointers( old_addr, new_addr )
off_t old_addr;
off_t new_addr;
{
int from = (int) old_addr & ~K_MASK;
int to = (int) new_addr & ~K_MASK;
Goto( BLOCK_COLUMN - 2, BLOCK_LINE + from / 64 );
putchar( ' ' );
Goto( BLOCK_COLUMN - 2, BLOCK_LINE + to / 64 );
putchar( '>' );
Goto( BLOCK_COLUMN + from % 64, BLOCK_LINE + 17 );
putchar( ' ' );
Goto( BLOCK_COLUMN + to % 64, BLOCK_LINE + 17 );
putchar( '^' );
}
void Map_Pointers( old_addr, new_addr )
off_t old_addr;
off_t new_addr;
{
int from = ( (int) old_addr & MAP_MASK ) >> 2;
int to = ( (int) new_addr & MAP_MASK ) >> 2;
Goto( BLOCK_COLUMN + from, BLOCK_LINE + 17 );
putchar( ' ' );
Goto( BLOCK_COLUMN + to, BLOCK_LINE + 17 );
putchar( '^' );
}
/****************************************************************/
/* */
/* Print_Number( number, output_base ) */
/* */
/* Output "number" in the output base. */
/* */
/****************************************************************/
void Print_Number( number, output_base )
word_t number;
int output_base;
{
switch ( output_base )
{
case 16 : printf( "%5x", number );
break;
case 10 : printf( "%7u", number );
break;
case 8 : printf( "%7o", number );
break;
case 2 : {
unsigned int mask;
char pad = ' ';
for ( mask = 0x8000; mask > 1; mask >>= 1 )
putchar( (mask & number) ? (pad = '0', '1') : pad );
putchar( (0x01 & number) ? '1' : '0' );
break;
}
default : Error( "Internal fault (output_base)" );
}
}
/****************************************************************/
/* */
/* Print_Ascii( char ) */
/* */
/* Display a character in reverse mode if it */
/* is not a normal printable ASCII character. */
/* */
/****************************************************************/
void Print_Ascii( c )
char c;
{
c &= 0x7f;
if ( c < ' ' )
printf( "%s%c%s", Treverse, '@' + c, Tnormal );
else if ( c == DEL )
printf( "%s?%s", Treverse, Tnormal );
else
putchar( c );
}
/****************************************************************/
/* */
/* Warning( text, arg1, arg2 ) */
/* */
/* Display a message for 2 seconds. */
/* */
/****************************************************************/
#if __STDC__
void Warning( const char *text, ... )
#else
void Warning( text )
char *text;
#endif
{
va_list argp;
printf( "%c%s", BELL, Tclr_all );
Goto( WARNING_COLUMN, WARNING_LINE );
printf( "%s Warning: ", Treverse );
va_start( argp, text );
vprintf( text, argp );
va_end( argp );
printf( " %s", Tnormal );
fflush(stdout); /* why does everyone forget this? */
sleep( 2 );
}
void Draw_Zone_Numbers( s, inode, zindex, zrow )
de_state *s;
struct inode *inode;
int zindex;
int zrow;
{
static char *plurals[] = { "", "double ", "triple " };
zone_t zone;
for ( ; zrow < 16;
++zindex, zrow += s->zone_num_size / sizeof (word_t) )
{
Goto( INFO_COLUMN, INFO_LINE + zrow );
if ( zindex < s->ndzones )
printf( "zone %d", zindex );
else
printf( "%sindirect", plurals[ zindex - s->ndzones ] );
if ( s->magic != SUPER_MAGIC )
{
zone = inode->i_zone[ zindex ];
if ( zone != (word_t) zone )
{
Goto( INFO_COLUMN + 16, INFO_LINE + zrow );
printf("%ld", (long) zone );
}
}
}
}