home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
ddjmag
/
ddj8808.arc
/
DDJ0888.SRC
Wrap
Text File
|
1988-08-03
|
73KB
|
2,679 lines
/*
[76703,4265]
CCOL.LST 01-Aug-88 1608
Keywords: AUG88 C COLUMN STEVENS
Source for Al Stevens C column in the August 1988 DDJ
EXAMPLE 1
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
char crypto [80]; /* encrypted message */
char decoded [80]; /* decrypted message */
char alphabet [] = "\nabcdefghijklmnopqrstuvwxyz";
char subs [] = " ";
/* ------ ANSI.SYS screen driver ---------- */
#define cursor(x,y) printf("\033[%02d;%02dH",y,x)
#define clear_screen() puts("\033[2J")
main()
{
int i, cp, a, b;
char sb [3];
clear_screen();
cursor(1, 6);
puts("Enter the encrypted quote:\n");
fgets(crypto, 80, stdin);
for (i = 0; i < strlen(crypto); i++)
decoded[i] = ' '; /* clear the decrypted msg */
decoded[i] = '\0';
while (1) {
cursor(1, 9);
puts(decoded);
puts(alphabet); /* display the alphabet */
puts(subs); /* display the substitutions */
puts("\nEnter 2 letter substitution: (xy):");
fgets(sb, 3, stdin);
if (strncmp(sb, "99", 2) == 0)
break;
a = *sb, b = *(sb+1);
if (isalpha(a) && isalpha(b)) {
for (cp = 0; cp < 26; cp++)
if (subs[cp] == a)
subs[cp] = ' ';
subs[b - 'a'] = a;
for (cp = 0; cp < strlen(crypto); cp++) {
if (decoded[cp] == b)
decoded[cp] = ' ';
if (tolower(crypto[cp]) == a)
decoded[cp] = b;
}
}
}
}
/*
[76703,4265]
CRYPTO.LST 01-Aug-88 3552
Keywords: AUG88 CRYPTOGRAPHY
Source from Micheners article on Enigma style encryption.
_A TOOL FOR SECRET KEY CRYPTOGRAPHY_
by
John R. Michener
LISTING 1
*/
/* -------------------- Listing 1 -----------------------------*/
/* this routine uses a supplied file (n>64K) of random one byte
numbers to generate a set of encryption and
decryption rotors. These rotors are supplied sequentially in a
128K file. The first 64K of the file contains
the encryption rotors in series, the second 64K contains the
decryption rotors in series. The order within the
file is the 256 elements of the first rotor in sequence followed
by the 256 elements of the second rotor, on
through all the rotors in the set.
Since random files are not easily created by users it is
necessary to create a close approximation to random
files. This can be done by taking a variety of text and program
files, compressing them, encrypting them with
random keys, and concatenating them to form a long binary file.
If English text was the source material this
compressed, binary file should be at least 256K bytes long
(making allowances for the redundancy of English).
The resulting 4:1 overlap of compressed English removes the
redundancies and residual order present in the
original language file. The length of the binary file should be
entered into the #define NN line since the
binary nature of the file prevents EOF characters. Use command
line file direction to read the random file
into the program and direct the output into the rotor file. */
#include <stdio.h>
#define NN /* length of random file in bytes */
main()
{
unsigned char rnd[65536]; /* random number array */
unsigned char rotor[2*65536];
register int k, temp, c;
register long i, j;
for(i=0, j=0; i<NN; i++)
{
rnd[j++] ^= ((unsigned char)(c=getchar()));
if (j==65536)
j = 0;
}
for(i=0; i<65536; i+=256)
for(j=0; j<256; j++)
rotor[i+j] = j;
for(i=0; i<65536; i+=256)
for(j=0; j<256; j++)
{
k=rnd[i+j];
temp = rotor[i+j];
rotor[i+j] = rotor[i+k];
rotor[i+k] = temp;
rotor[65536 + i + rotor[i+j]] = j;
rotor[65536 + i + rotor[i+k]] = k;
}
for(i=0; i<2*65536; i++)
putchar(rotor[i]);
}
-------------------------------------------------------------------------
/*
LISTING 2
*/
/* ----------------------------Listing 2 -------------------------------*/
/* in the following subroutines the PR numbers used for GR
operations are stored in rndout[] and are accessed
by the offset values ro. These values are incremented by 8 for
each character processed to allow for the 8 PR
numbers needed per GR operation. */
/*________ character substitution encryption _________________*/
unsigned char sub(ch,ro)
unsigned char ch; /* character to be encrypted */
int ro; /* offset in random number array */
{
int i;
for(i=0;i<4;i++)
ch=rotor[(int)((rndout[i+ro])<<8)+(int)((rndout[i+4+ro]+ch)&255)];
return(ch);
}
/*__________ character substitution decryption _____________*/
unsigned char unsub(ch,ro)
unsigned char ch; /* character to be decrypted */
int ro; /* offset in random number array */
{
int i;
for(i=3;i>=0;i--)
ch=(rotor[65536+(int)((rndout[i+ro])<<8)+(int)ch]-rndout[i+4+ro])&255;
return(ch);
}
/*
[76703,4265]
FINDFU.LST 01-Aug-88 26692 Accesses: 27
Keywords: AUG88
Source code for the article Find that Function in the August 1988 issue of
DDJ
_FIND THAT FUNCTION_
by
Marvin Hymowech
LISTING 1
*/
/*
* bldfuncs.c: Construct a table of the functions defined in source files.
* Copyright (c) 1988 Marvin Hymowech
*
* Usage: bldfuncs file1.c file2.c ...
* (wildcards are allowed also, e.g. *.c )
* The output table is named funcs.txt.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define LINT_ARGS
#define TRUE 1
#define FALSE 0
#define OK 0
#define ERROR 1
/* return values for filter functions below.
* EOF or any character is also possible.
*/
#define BRACES -2
#define PARENS -3
#define QUOTES -4
/* function declarations for type checking */
char *get_fn_name(char *);
int get_names_one_file(char *, FILE *);
main(argc, argv)
int argc;
char **argv;
{
FILE *fp_out;
char *current_file;
int num_files, i;
if( argc < 2 )
{
fprintf( stderr, "wrong number of parameters" );
exit(1);
}
if( (fp_out = fopen("funcs.txt", "w")) == NULL )
{
fprintf( stderr, "can't open %s\n", "funcs.txt" );
exit(1);
}
/* build a function list for each file on the command line,
* and write the list to the file funcs.txt.
*/
printf( "Creating funcs.txt...\n" );
num_files = argc - 1;
for ( i = 1; i <= num_files; i++ )
{ /* tell the user where we're at */
printf( "%30s: %3d of %3d files\n",
current_file = strlwr(*++argv), i, num_files );
if( get_names_one_file( current_file, fp_out ) != OK )
{ /* use strlwr to lower-case the name - cosmetic only */
fprintf( stderr, "can't process %s", current_file );
exit(1);
}
}
fclose(fp_out);
exit(0);
}
/* open the .c file source_file_name, scan it for function definitions,
* and write a listing to fp_out in the form:
* source_file_name:
* function-1
* function-2 ...
* function-n;
* Return values: OK or ERROR
*/
int
get_names_one_file(source_file_name, fp_out)
char *source_file_name;
FILE *fp_out;
{
int line_len, c, got_fn_defn = FALSE;
#define LINE_LEN 8192
char line[LINE_LEN], *name_ptr, fn_name[64];
FILE *fp_source;
/* open the input source file */
if( (fp_source = fopen(source_file_name, "r")) == NULL )
return ERROR;
/* write "source file name:" */
sprintf( line, "\n%s:", source_file_name );
fprintf( fp_out, line );
while( TRUE )
{
line_len = 0; /* using the filter_data() char stream */
/* collect chars until a semicolon or PARENS */
while( (c = filter_data(fp_source)) != EOF && c != ';' && c != PARENS )
line[line_len++] = c;
if( c == EOF )
break;
if( c == ';' ) /* Bypass externals representing data items. */
continue; /* Now we know line ended with PARENS. */
line[ line_len ] = 0; /* Terminate line. */
/* At this point, line either contains a function definition
* or a function type declaration or something else, perhaps
* an occurrence of parenthese in a data item definition.
* We only want function definitions.
*/
/* Extract the function name from this possible */
/* function definition, and save it in fn_name. */
strcpy( fn_name, get_fn_name(line) );
/* Exclude the case of parenthetical expressions */
/* in a data defintion, e.g. within array brackets. */
if( !fn_name[0] )
continue;
/* skip white space */
while( (c = filter_data(fp_source)) != EOF && isspace(c) )
;
if( c == ';' || c == ',' ) /* functions type check declaration */
continue; /* so bypass it */
if( c == EOF )
break;
/* skip any parameter declarations - */
while( c != BRACES && c != EOF ) /* eat until braces or EOF */
c = filter_data(fp_source);
/* append this function definition to the output table */
fprintf( fp_out, "\n\t%s", fn_name );
got_fn_defn = TRUE;
}
fclose(fp_source);
/* got_fn_defn FALSE if no functions in file */
/* write file terminator */
fputs( got_fn_defn ? ";\n" : "\n\t;\n", fp_out );
return OK;
}
/* assuming that the input line ends with a function name,
* extract and return this name (as a pointer into the input line).
*/
char *
get_fn_name(line)
char *line;
{
char *name_ptr;
int len;
if( !(len = strlen(line)) )
return line;
name_ptr = line + len - 1;
while( isspace(*name_ptr) ) /* skip trailing white space */
name_ptr--;
*(name_ptr + 1) = 0; /* terminate fn name */
/* function names consist entirely of */
/* alphanumeric characters and underscores */
while( (isalnum(*name_ptr) || *name_ptr == '_') && name_ptr >= line )
name_ptr--;
/* if this alleged function name begins */
if( isdigit(*++name_ptr) ) /* with a digit, return an empty string */
return( name_ptr + strlen(name_ptr) );
return name_ptr; /* else return the function name */
}
/* using the stream returned by filter_parens() as input,
* return a character stream in which any data initialization
* expressions between an equals sign and a semicolon
* have been replaced by a single semicolon.
* This will filter out anything involving parentheses in a
* data initialization expression, which might otherwise be
* mistaken for a function defintion.
*/
int filter_data(fp_source)
FILE *fp_source;
{
int c;
if( (c = filter_parens(fp_source)) != '=' )
return c;
while( (c = filter_parens(fp_source)) != ';' && c != EOF )
;
return c;
}
/* using the stream returned by filter_curly_braces() as input,
* return a character stream in which all characters
* between '(' and the matching ')' have been replaced
* by the single special value PARENS (any nested parentheses within
* this top level pair will also have been eaten).
* This will filter out anything within the parentheses delimiting
* the arguments in a function definition.
*/
int
filter_parens(fp_source)
FILE *fp_source;
{
int paren_cnt, c;
if( (c = filter_curly_braces(fp_source)) != '(' )
return c;
paren_cnt = 1;
while( paren_cnt )
switch( filter_curly_braces(fp_source) )
{
case ')':
paren_cnt--;
break;
case '(':
paren_cnt++;
break;
case EOF:
return EOF;
}
return PARENS;
}
/* using the stream returned by filter_ppdir() as input,
* return a character stream in which all characters
* between '{' and the matching '}' have been replaced
* by the single special value BRACES (any nested braces within
* this top level pair will also have been eaten).
* This will filter out anything internal to a function.
*/
int
filter_curly_braces(fp_source)
FILE *fp_source;
{
int brace_cnt, c;
if( (c = filter_ppdir(fp_source)) != '{' )
return c;
brace_cnt = 1;
while( brace_cnt ) /* wait for brace count to return to zero */
switch( filter_ppdir(fp_source) )
{
case '}':
brace_cnt--; /* subtract right braces */
break;
case '{':
brace_cnt++; /* add left braces */
break;
case EOF:
return EOF;
}
return BRACES; /* brace count is now zero */
}
#define MAXLINE 1024
/* using the stream returned by filter_quotes() as input,
* return a character stream in which all preprocessor
* directives have been eaten.
*/
int
filter_ppdir(fp_source)
FILE *fp_source;
{
int c, i;
char line[MAXLINE + 1];
while(TRUE)
{ /* does this line begin a preprocessor directive? */
if( (c = filter_quotes(fp_source)) != '#' )
return c; /* no, return character */
/* yes, store until newline or EOF */
if( (c = get_ppdir_line( fp_source, line )) == EOF )
return EOF;
if( strncmp( line, "define", 6 ) ) /* if not #define directive */
continue; /* eat this line */
if( line[ strlen(line) - 1 ] != '\\' ) /* if #define line ends */
continue; /* with "\" */
else
while(TRUE) /* keep eating lines */
{ /* which also end with "\" */
/* store until newline or EOF */
if( (c = get_ppdir_line( fp_source, line )) == EOF )
return EOF;
/* done with this #define directive if this */
/* line is not also a continuation line */
if( line[ strlen(line) - 1 ] != '\\' )
break;
}
}
}
/* Utility routine used by filter_ppdir() -
/* read the character stream using filter_quotes, storing characters
* in the parameter "line", until EOF or '\n' is encountered.
* Return EOF or '\n' accordingly.
*/
int
get_ppdir_line(fp_source, line)
FILE *fp_source;
char *line;
{
int i, c;
/* store until newline or EOF */
for( i = 0; i < MAXLINE && (c = filter_quotes(fp_source)) != '\n'
&& c != EOF; i++ )
line[i] = c;
line[i] = 0; /* terminate string */
if( c == EOF )
return EOF;
return '\n';
}
/* using the stream returned by filter_cmt() as input,
* return a character stream in which any quoted character
* or quoted string has been collapsed to the single special value QUOTES
* to avoid considering special characters like '{', '}', '(', or ')'
* which may occur within quotes.
*/
int
filter_quotes(fp_source)
FILE *fp_source;
{
int c1, c2;
if( (c1 = filter_cmt(fp_source)) != '\'' && c1 != '"' )
return c1; /* pass char through if not single or double quote */
while( TRUE )
switch( c2 = filter_cmt(fp_source) )
{
case '\\': /* beginning of an escape sequence */
filter_cmt(fp_source); /* so eat next char */
break;
case EOF:
return EOF;
default:
if( c2 == c1 ) /* found end of quoted char or string */
return QUOTES;
}
}
/* Returns character stream, eating comments. */
/* Returns EOF if end of file. */
/* Nested comments are allowed. */
int
filter_cmt(fp_source)
FILE *fp_source;
{
/* values for state */
#define STABLE 0 /* not in process of changing the comment */
/* level: i.e., not in the middle of a */
/* slash-star or star-slash combination. */
#define IN_CMT_FS 1 /* got '/', looking for '*' */
#define OUT_CMT_STAR 2 /* got '*', looking for '/' */
int c, state = STABLE, cmt_level = 0;
while( TRUE )
{
c = fgetc(fp_source);
if( c == EOF )
return EOF;
switch(state)
{
case STABLE:
if( c == '*' )
state = OUT_CMT_STAR;
else if( c == '/' )
state = IN_CMT_FS;
break;
case IN_CMT_FS:
if( c == '*' )
{
state = STABLE;
cmt_level++; /* descend one comment level */
continue;
}
else if( !cmt_level ) /* if '/' not followed by '*' */
{ /* and outside any comment */
ungetc( c, fp_source ); /* push back this char */
return '/'; /* and return the '/' */
}
else if( c != '/' ) /* stay in state IN_CMT_FS */
state = STABLE; /* if next char is '/' as well */
break;
case OUT_CMT_STAR:
if( c == '/' )
{
cmt_level--; /* ascend one comment level */
state = STABLE;
continue;
}
else if( !cmt_level ) /* if '*' not followed by '/' */
{ /* and outside any comment */
ungetc( c, fp_source ); /* push back this char */
return '*'; /* and return the '*' */
}
else if( c != '*' ) /* stay in state IN_CMT_FS */
state = STABLE; /* if next char is '*' as well */
break;
}
if( state == STABLE && !cmt_level ) /* if outside any comment */
return c; /* return character */
}
}
/*
LISTING 2
NAME: bldfuncs - construct a table of C source file names together with
a list of the names of all functions defined in these source files.
USAGE: bldfuncs source_file_1 source_file_2 ...
(wildcard characters are allowed)
DESCRIPTION: bldfuncs is used to construct the list file needed by getf.
The output file is named "funcs.txt", and has the format:
source_file_1.c:
function_1
function_2
...
function_n;
source_file_2.c:
...
Of course this file could be constructed or modified using a
text editor, but bldfuncs is designed to automate this process.
bldfuncs is run at relatively infrequent intervals to update
the list file, whereas getf is run frequently to locate functions.
EXAMPLES: bldfuncs *.c This will construct a funcs.txt file
in the current directory which will
contain a list of all .c files in
that directory, together with a list
of the functions defined in these
files.
bldfuncs *.c \source1\*.c \source2\*.c
This will construct a funcs.txt file
in the current directory which will
contain the above information for
the current directory, \source1,
and \source2 combined.
bldfuncs prog1.c prog2.c prog3.c
This will construct a funcs.txt file
in the current directory which will
contain the above information for
the selected files prog1.c, prog2.c
and prog3.c combined.
LISTING 3
*/
/*
* getf.c - locate the source file containing a specified function and
* present it in your favorite editor.
* Copyright (c) 1988 Marvin Hymowech
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINT_ARGS
#define TRUE 1
#define FALSE 0
#define LINE_LEN 256
/* function declarations */
int patn_match(char *, char *);
void edit( char *, char * );
void ask_for_file(char **, char **, unsigned int);
unsigned int num_ctl_patns; /* number of %s symbols in GETFEDIT var */
char *file_token, *func_token;
char arg1[64]; /* argument for editor command line */
char *arg1_ctl; /* ctl string for building arg1 */
char *pgm_name; /* name of editor to invoke */
main(argc, argv)
int argc;
char **argv;
{
char file_line[LINE_LEN], func_line[LINE_LEN];
char func_name[64], edit_cmd[128];
char *env_edit_cmd, *ctl_patn;
unsigned int last_func, len, eof = FALSE;
static char file_name[] = "funcs.txt"; /* input file name */
FILE *funcs_file;
static char delim[] = "\n\t "; /* white space delimiters */
#define MAX_CHOICES 256
unsigned int num_choices = 0;
char *func_choices[ MAX_CHOICES ], *file_choices[ MAX_CHOICES ];
if( argc != 2 )
{
fprintf( stderr, "getf: wrong number of arguments" );
exit(1);
}
/* the argument is the function name to find */
strcpy( func_name, *++argv );
if( (env_edit_cmd = getenv( "GETFEDIT" )) == NULL )
{
fprintf( stderr, "getf: missing environment variable GETFEDIT" );
exit(1);
}
/* check if GETFEDIT environment variable has a place for
* function name as well as file name - note function name
* is assumed to go in the first %s pattern if there are
* two %s patterns.
*/
if( (ctl_patn = strstr( env_edit_cmd, "%s" )) == NULL )
{
fprintf( stderr,
"getf: environment variable GETFEDIT has no %%s pattern" );
exit(1);
}
num_ctl_patns = strstr( ++ctl_patn, "%s" ) == NULL ? 1 : 2;
strcpy( edit_cmd, env_edit_cmd );
if( (pgm_name = strtok( edit_cmd, " " )) == NULL )
{
fprintf( stderr,
"getf: environment variable GETFEDIT has incorrect format" );
exit(1);
}
/* point to argument following program name */
arg1_ctl = edit_cmd + strlen(pgm_name) + 1;
if( (funcs_file = fopen( file_name, "r" )) == NULL )
{
fprintf( stderr, "getf: can't open %s\n", *argv );
exit(1);
}
while( !eof ) /* loop thru file names, which end with colon */
{
if( fgets( file_line, LINE_LEN, funcs_file ) == NULL )
break;
/* bypass any line consisting of white space */
if( (file_token = strtok( file_line, delim )) == NULL )
continue;
if( file_token[ len = strlen(file_token) - 1 ] != ':' )
{
fprintf(stderr, "getf: incorrect file format on %s", file_name);
exit(1);
}
file_token[ len ] = 0; /* kill trailing colon */
last_func = FALSE; /* set up to detect last func this file */
while( !eof && !last_func ) /* loop thru func names this file */
{ /* last such ends with semicolon */
if( fgets( func_line, LINE_LEN, funcs_file ) == NULL )
{
eof = TRUE;
break;
}
/* bypass any line consisting of white space */
if( (func_token = strtok( func_line, delim )) == NULL )
continue;
if( func_token[ len = strlen(func_token) - 1 ] == ';' )
{
last_func = TRUE; /* break loop after this one */
func_token[ len ] = 0; /* kill trailing semi-colon */
}
if( patn_match( func_name, func_token ) )
{
func_choices[num_choices] = strdup( func_token );
file_choices[num_choices++] = strdup( file_token );
}
}
}
switch( num_choices )
{
case 0:
fprintf( stderr, "getf: no match for %s in %s",
func_name, file_name );
exit(1);
case 1:
edit( func_choices[0], file_choices[0] );
default:
ask_for_file(func_choices, file_choices, num_choices);
}
}
/* return TRUE if string s matches pattern patn,
* or FALSE if it does not. Allowable wildcards
* in patn are: ? for any one character, % for
* any string of characters up to the next underscore
* or end of string, and * for any string of characters
* up to end of string.
*/
int
patn_match(patn, s)
char *patn; /* pattern */
char *s; /* string */
{
for( ; *patn; patn++ )
{
if( !*s ) /* if out of s chars, no match */
return /* unless patn ends with * or % */
((*patn == '*' || *patn == '%') && !*(patn + 1) );
switch( *patn )
{
case '%':
while( *s != '_' && *s )
s++;
break;
case '*':
while( *s++ )
;
break;
case '?':
s++;
break;
default:
if( *s != *patn )
return FALSE;
s++;
}
}
return *s == 0;
}
void
ask_for_file(func_choices, file_choices, num_choices)
char *func_choices[], *file_choices[];
unsigned int num_choices;
{
int i;
char line[LINE_LEN];
while( TRUE )
{
printf( "Which one? (CR to exit)\n" );
for( i = 1; i <= num_choices; i++ )
printf( "\t%3d: %20.20s in %-30.30s\n", i, func_choices[i-1],
file_choices[i-1] );
printf( "\nEnter number:" );
fgets( line, LINE_LEN, stdin );
if( line[0] == '\n' )
break;
if( (i = atoi(line)) < 1 || i > num_choices )
printf( "\nInvalid choice!\007\n" );
else
edit( func_choices[i-1], file_choices[i-1] );
}
}
void
edit(func, file)
char *func, *file;
{
/* execlp will overlay this program with the editor */
if( num_ctl_patns == 1 )
sprintf( arg1, arg1_ctl, file );
else
sprintf( arg1, arg1_ctl, func, file );
execlp( pgm_name, pgm_name, arg1, NULL);
/* if we're still here, print error msg */
fprintf( stderr, "getf: exec failed" );
exit(1);
}
/*
LISTING 4
NAME: getf - locate the source file containing a C function
and present it in a specified editor.
USAGE: getf [list_file_name] function name
DESCRIPTION: getf looks for the file funcs.txt, which is
presumed to be a listing of C source file names together
with a list of the C functions defined in these source
files; the expected format is
source_file_1.c:
function_1
function_2
...
function_n;
source_file_2.c:
...
(This list file can be conveniently built using the companion
program bldfuncs.c.)
The editor to be used is specified in the DOS environment
variable GETFEDIT, which is presumed to have the form:
editor_name control_string
where control_string is an sprintf control string which may have
either one or two occurrences of the pattern "%s": if one such
pattern exist, it is replaced by the appropriate source file
name in which the requested function resides; if two such
patterns exist, the first "%s" is replaced by the function name
and the second by the source file name. This latter format allows
the use of an editor-specific search command to position the
source file to the requested function automatically. After
replacing the "%s" patterns as above, the GETFEDIT string is
executed via a DOS exec call, thus overlaying the current program
getf.
The wildcards ?, * and % are allowed in the function name
argument for getf, and are interpreted as: ? matches any single
character, * matches the remainder of any string, and % matches
all characters up to the next underscore or until the end of
string.
EXAMPLES: Assume the editor is BRIEF; possible GETFEDIT strings might be:
b %s this will simply bring up the
desired source file in BRIEF
without any attempt at positioning
the cursor to the requested function.
b -m"search_fwd %s" %s this will bring up the desired
source file and position the cursor
to the first occurrence of the
requested function.
b -m"funcsrch %s" %s (see funcsrch.doc for an explanation
of this customized BRIEF macro.)
this will bring up the desired
source file, seek to the end of
the file, then seek backwards for
the LAST occurrence of the requested
function. In practice, this is the
approach most likely to position the
cursor to the actual definition of
the function.
To illustrate wildcards:
getf func* matches func, func1, func_2;
getf func% mathces func, func1, but not func_2.
getf func?_%_* matches func1_new_, funca_old_stuff,
but not func1_stuff.
NOTE: Remember that to set GETFEDIT in your autoexec.bat file (or in
any other batch file) you must use TWO percent signs instead of
one:
set GETFEDIT=b -m"funcsrch %%s" %%s
This is necessary to avoid interpretation of the percent signs
by command.com.
*/
\ [76703,4265]
\ FORTH.LST 01-Aug-88 1158
\ Keywords: FORTH AUG88
\ Source from Martin Tracy's forth column
\ _THE FORTH COLUMN_
\ by
\ Martin Tracy
\ LISTING 1
\ Dr. C.H. Ting's Simplest Line Drawing Algorithm
HEX
CODE VIDEO ( cx dx ax -- ) \ IBM BIOS video service
AX POP DX POP CX POP 10 INT NEXT END-CODE
: TEXT 0 0 2 VIDEO ; \ Return to text mode.
: GRAPH 0 0 4 VIDEO ; \ Set high-resolution graphics mode.
CODE PLOT ( x y color -- )
\ Given a coordinate pair and a color code,
\ paint one dot on the screen.
AX POP 0200 # AX ADD DX POP CX POP 10 INT
NEXT END-CODE
DECIMAL
\ Dr. C. H. Ting's Simplest Line Drawing Algorithm
: draw ( x1 y1 x2 y2 -- )
\ Draw a straight line between (x1, y1) and (x2,y2).
\ Determine the end condition, where (x1,y1) and (x2,y2)
\ are within one pixel distance.
\ Find the mid point between (x1,y1) and (x2,y2).
\ Insert mid point between 1 and 2, then recurse twice
\ to draw the two segments.
2over 2over rot - abs >r
- abs r> max 2 < if 2drop 3 plot exit then
2over 2over rot + 1+ 2/ >r ( y3)
+ 1+ 2/ ( x3) r> 2dup 2rot recurse recurse ;
: test1 640 0 do 0 0 i 400 draw 10 +loop ;
: test2 400 0 do 0 0 640 i draw 10 +loop ;
/*
[76703,4265]
NUTTER.LST 01-Aug-88 29168
Keywords: NUTTER AUG88 C SOURCE CONTROL
Automatic Module Control in C - source listings from Stewart Nutters
article in the August 1988 issue of DDJ.
LISTING 1
*/
/* print a visual tree representation of a 'C' program */
/* cp.c */
/***********************************************************
cprinter - print a visual tree representation
of a 'C' program
copyright 1987, Stewart A. Nutter
Please do not distribute this for profit. For
individual use only.
written by: Stewart A. Nutter
**********************************************************/
#define MAINMODULE 1
#include "cpheader.h"
main( argc, argv )
char **argv;
int argc;
{
char szName[20]; /* input file name */
int iRet;
int l, i, j, k; /* index variables */
int sflag;
int pcnt;
int tmp;
int pmax; /* max number of xref columns */
int index;
FILE *stream;
struct Pages *p;
long int total; /* total number of bytes */
long int ltotal; /* total number of lines */
pFlist = Flist;
pMlist = Mlist;
pMnames = Mnames;
for ( i=0; i<50; i++ ) /* clear out the recursion list */
rlist[i] = NULL;
printf( "\ncp - ver. 1.3, (C) 1987, 1988 Stewart A. Nutter" );
printf( "\n written by Stewart A. Nutter\n" );
/* no arguments - print instructions */
if ( argc < 2 )
{
printf( "\ncp listfile [ outfile ] [ /l:xx /w:yy /t:main /s:z ]\n" );
printf( " outfile = \"prn\" \n" );
printf( " l: page length = 66 [0, 50-255]\n" );
printf( " w: page width = 80 [80-255]\n" );
printf( " m: left margin = 8 [0-30]\n" );
printf( " r: right margin = 8 [0-30]\n" );
printf( " t: target function = \"main\"\n" );
printf( " s: statistics only = 0 [0=all, 1=stats only]\n" );
printf( "\n" );
printf( "Notes: 1. Maximum recursive function displacement of 50.\n" );
printf( " 2. Maximum number of functions calls is %d.\n", MAXFNCTS );
printf( " 3. Maximum number of modules is %d.\n", MAXMODULES );
exit( 0 );
}
if ( ( stream = fopen( argv[1], "r" ) ) == NULL )
{
fprintf( stderr, "\n%s", strerror( errno ) );
exit( 1 );
}
/* an output file name was given? */
index = 2;
if ( argc > 2 && argv[index][0] != '/' )
{
output = fopen( argv[2], "w+" );
index++;
}
else
output = fopen( "prn","w+" ); /* prn device by default */
for ( i=index; i<argc; i++ )
{
if ( argv[i][0] == '/' && strlen( argv[i] ) > 3 && argv[i][2] == ':' )
{
switch ( argv[i][1] )
{
case 'l' : /* change the page length */
tmp = atoi( &argv[i][3] );
if ( ( tmp > 50 && tmp < 256 ) || tmp == 0 )
pl = tmp;
break;
case 'm' : /* change the left margin */
tmp = atoi( &argv[i][3] );
if ( tmp >= 0 && tmp <= 30 )
lm = tmp;
break;
case 'r' : /* change the rignt margin */
tmp = atoi( &argv[i][3] );
if ( tmp >= 0 && tmp <= 30 )
rm = tmp;
break;
case 's' : /* set the stats only? */
stats = atoi( &argv[i][3] );
break;
case 't' : /* change the target function */
strcpy( target, &argv[i][3] );
break;
case 'w' : /* change the width */
tmp = atoi( &argv[i][3] );
if ( tmp > 79 && tmp < 256 )
pw = tmp;
break;
}
}
else
{
printf( "\nUnknown argument: %s", argv[i] );
exit( 1 );
}
}
if ( output == NULL )
{
fprintf( stderr, "\n%s", strerror( errno ) );
exit( 1 );
}
width = pw - lm - rm;
if ( width < 40 )
{
fprintf( stderr, "\nThe page width is too narrow." );
exit( 1 );
}
printf( "\n" );
/* read the input file for file names */
while ( !feof( stream ) )
{
szName[0] = '\0';
fgets( szName, 19, stream );
if ( ( l = strlen( szName ) ) > 1 )
{
if ( szName[l - 1] == '\n' )
szName[l - 1] = '\0'; /* remove newline char */
xref( szName );
}
}
/* pointer list for sort */
for ( i=0, pMlist=Mlist; i<Mqty; i++ )
{
pm[i] = pMlist++;
}
printf( "\n\nSorting the function list...\n" );
sflag = 1;
while ( sflag ) /* sort the function names */
{
sflag = 0;
for ( i=0; i<Mqty-1; i++ )
{
if ( strcmp( pm[i]->function, pm[i+1]->function )>0 )
{
sflag = 1;
pMlist = pm[i];
pm[i] = pm[i+1];
pm[i+1] = pMlist;
}
}
}
i = find_mod( target ); /* must start with the target function */
if ( i >= 0 ) /* 'main' must exist */
{
depth = 0;
printf( "Checking for usage...\n" );
/* check how many times each function is used */
getstats( );
depth = 0;
bfr[0] = 0;
printf( "Starting the printout...\n" );
line = 0;
if ( stats == 0 )
{
pm[i]->used = 1; /* set so main shows up in the list */
doprint( i ); /* print the non-library functions */
for ( i=0; i<Mqty; i++ ) /* print defined functions now */
{
fprintf( output, "\n" );
line++;
if ( pm[i]->used > 1 ) /* must be used more than once */
{
doprint( i ); /* print the tree structure */
}
}
}
/* print statistics on the modules */
line = 9999; /* force a new page */
pMnames = Mnames;
pagebreak( );
leftmargin( output );
fprintf( output, "Module statistics :\n" );
line++;
total = 0L;
ltotal = 0L;
for ( i=0; i<Mcnt; i++ ) /* print module names & sizes */
{
pagebreak( );
leftmargin( output );
fprintf( output,
"%-12s - %5u lines, %6ld bytes\n",
pMnames->name, pMnames->length,
pMnames->size );
total += pMnames->size;
ltotal += pMnames->length;
line++;
pMnames++;
}
fputc( '\n', output );
leftmargin( output );
fprintf( output,
"Total source size = %ld bytes in %ld lines for %d modules\n",
total, ltotal, Mcnt );
/* print the used function page index */
line = 9999; /* force a new page */
pagebreak( );
leftmargin( output );
fprintf( output, "Function index :\n" );
line++;
for ( i=0; i<Mqty; i++ ) /* print used function names */
{
pMlist = pm[i];
if ( pMlist->used > 0 )
{
pagebreak( );
leftmargin( output );
fprintf( output,
"%-25s - %-12s - used =%d \n",
pMlist->function, ( pMlist->name )->name,
pMlist->used );
line++;
}
}
/* print the function page cross reference */
if ( stats == 0 && pl > 0 ) /* print everything */
{
pmax = ( int )( width - 27 )/5;
line = 9999; /* force a new page */
pagebreak( );
leftmargin( output );
fprintf( output, "Function cross reference :\n" );
line++;
for ( i=0; i<Mqty; i++ ) /* print used function names */
{
pMlist = pm[i];
if ( pMlist->used > 0 )
{
pagebreak( );
leftmargin( output );
fprintf( output, "%-25s- ", pMlist->function );
p = pMlist->pg;
if ( p != NULL )
{
pcnt = 0;
while ( p->next != NULL )
{
fprintf( output, "%4d,", p->pg );
p = p->next;
pcnt++;
if ( pcnt >= pmax )
{
fputc( '\n', output );
leftmargin( output );
fprintf( output, "%27s", " " );
line++;
pcnt = 0;
}
}
fprintf( output, "%4d\n", p->pg );
line++;
}
else
fprintf( output, "\n" );
}
}
}
/* print statistics on all unused modules */
line = 9999; /* force a new page */
pagebreak( );
leftmargin( output );
fprintf( output, "Un-used function list :\n" );
line++;
pcnt = 0;
for ( i=0; i<Mqty; i++ ) /* print unused function names */
{
pMlist = pm[i];
if ( pMlist->used == 0 )
{
pagebreak( );
pcnt++;
leftmargin( output );
fprintf( output,
"%-25s - %-12s \n",
pMlist->function, ( pMlist->name )->name );
line++;
}
}
if ( pcnt == 0 )
{
leftmargin( output );
fprintf( output,
"No un-used functions in the list.\n" );
}
/* print module comments */
line = 9999; /* force a new page */
pMnames = Mnames;
pagebreak( );
leftmargin( output );
fprintf( output, "Module comments :\n" );
line++;
for ( i=0; i<Mcnt; i++ ) /* print module names & comments */
{
pagebreak( );
leftmargin( output );
fprintf( output,
"%12s -%s\n",
pMnames->name, pMnames->cmt );
line++;
pMnames++;
}
fprintf( output, "%c", 0x0c ); /* ending formfeed */
}
}
/* process the file for function names */
xref( fname )
char *fname;
{
int done; /* loop termination flag */
int brace_cnt; /* count of the open braces */
int open_paren; /* open paranthisis count */
int ret; /* return value */
int indx; /* for/next index */
int dflg; /* function definition flag */
static int wflg = 0;
char c; /* character read from disk file */
char buffer[50]; /* temporary buffer */
char bufr[256]; /* temporary buffer */
register char *p; /* fast character pointer */
FILE *stream; /* module file pointer */
struct Mod_list *cptr; /* pointer to the module list structure */
static char back[] =
{8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8};
printf( "%cProcessing file: %-12s ", 0x0d, fname );
if ( ( stream = fopen( fname, "r" ) ) == NULL )
return( -1 );
pp = pc;
if ( ( pMnames->name = strdup( fname ) ) == NULL )
{
fprintf( stderr, "Ran out of memory.\n" );
exit( 1 );
}
pMnames->length = 0;
pMnames->size = 0L;
buffer[0] = 0;
p = buffer;
open_paren = 0;
brace_cnt = 0;
firstcmt = 0;
filecmt[0] = 0;
done = 0;
ret = 0;
while ( !ret )
{
c = getnext( stream );
switch ( c )
{
case '{' :
brace_cnt++; /* increment the open brace count */
break;
case '}' :
brace_cnt--; /* decrement the open brace count */
break;
case '(' :
if ( open_paren == 0 ) /* first open paren only */
{
open_paren = 1;
}
wflg = 1;
break;
case ' ' : /* skip tabs and spaces */
case '\t' :
do
{
c = getnext( stream );
}
while ( c == '\t' || c == ' ' );
if ( c != '(' )
wflg = 1;
pushc( c );
break;
case 0x1a : /* end of the file indicator */
ret = 1;
wflg = 1;
default :
/* the character must be a variable character */
if ( strcheck( c ) )
{
*p++ = c;
*p = 0;
}
else
wflg = 1;
break;
}
if ( wflg )
{
if ( buffer[0] && ( buffer[0] < '0' || buffer[0] > '9' ) )
{
done = 1;
}
else
{
p = buffer;
buffer[0] = 0;
open_paren = 0;
}
wflg = 0;
}
/* if done != 0 there is a token */
if ( done )
{
done = 0;
*p = 0;
if ( open_paren ) /* functions start with an open paren */
{
open_paren = 0;
if ( brace_cnt == 0 ) /* and no braces */
{
dflg = 0;
for ( indx=0; indx<256 && dflg==0; indx++ )
{
c = getnext( stream );
if ( c == ';' )
dflg = 1;
else if ( c == '\n' )
dflg = 2;
bufr[indx] = c;
}
if ( dflg == 0 )
{
fprintf( stderr, "\nSyntax error: " );
fprintf( stderr, "Module description.\n" );
bufr[indx] = 0;
fprintf( stderr, "\n%s\n", bufr );
exit( 1 );
}
/* put the characters back to be read */
while ( indx )
{
pushc( bufr[indx-1] );
indx--;
}
/* this is a function definition */
if ( dflg == 2 )
{
printf( "%-40s%s", buffer, back );
pMlist->name = pMnames;
pMlist->qty = 0;
pMlist->ptr = pFlist;
/* allocate memory for name */
if ( ( pMlist->function = strdup( buffer ) )
== NULL )
{
fprintf( stderr, "\nRan out of memory." );
exit( 1 );
}
pMlist->used = 0;
pMlist->pg = NULL;
cptr = pMlist;
pMlist++;
Mqty++;
if ( Mqty > MAXMODULES )
{
fprintf( stderr,
"Too many new functions\n" );
exit( 1 );
}
}
}
else
{
cptr->qty += addlist( cptr->ptr,
buffer, cptr->qty );
}
}
p = buffer;
*p = 0;
}
}
fclose( stream );
pMnames->cmt = strdup( filecmt );
pMnames++; /* point to the next function data structure */
Mcnt++; /* count of the different functions */
return( ret );
}
LISTING 2
cp.obj : cp.c cpheader.h
cl -Ox -AL cp.c -c
cpfuncts.obj : cpfuncts.c cpheader.h
cl -Ox -AL cpfuncts.c -c
cp.exe : cpfuncts.obj cp.obj
link cp+cpfuncts/st:4096;
/*
LISTING 3
*/
/* function module for the program 'cp'
the cp program must be compiled with the large model */
/***********************************************************
cpfuncts.c - function module for the program 'cp'
copyright 1987, Stewart A. Nutter
written by: Stewart A. Nutter
***********************************************************/
#define MAINMODULE 0
#include "cpheader.h"
/* getnext - get the next character from the stream */
getnext( stream )
FILE *stream;
{
register char c;
static int qflag=0, cflag=0, eflag=0;
static int dflag=0, aflag=0, ncnt=0;
static int fp;
int b, done;
done = 1;
do
{
if ( ( qflag | cflag | eflag | dflag | aflag ) == 0 )
done = 1;
c = getchars( stream );
/* process escape sequence characters */
if ( eflag && c != 0x1a )
{
if ( c >= '0' && c <= '7' && ncnt < 3 )
ncnt++;
else
{
/* had less than the 3 octal digits */
if ( ncnt < 3 && ncnt > 0 )
pushc( c );
ncnt = 0;
eflag = 0;
}
}
else if ( cflag && c != 0x1a ) /* skipping a comment */
{
if ( firstcmt == 1 )
{
if ( c != '\n' && strlen( filecmt ) < ( width - 14 ) )
{
filecmt[fp] = c;
fp++;
filecmt[fp] = 0;
}
else
{
do /* remove extraneous spaces and tabs */
{
b = getchars( stream );
}
while ( b == ' ' || b == '\t' );
pushc( b );
filecmt[ fp++ ] = ' ';
filecmt[ fp ] = '\0';
}
}
if ( c == '*' )
{
b = getchars( stream );
if ( b == '/' )
{
firstcmt = 2; /* done with the comment */
if ( fp > 0 )
filecmt[fp - 1] = 0; /* terminate the line */
cflag = 0;
}
else
pushc( b );
}
}
else if ( qflag && c != 0x1a ) /* skipping a string */
{
if ( c == 0x27 )
eflag = 1;
else if ( c == '\"' )
{
pushc( 0x1b );
qflag = 0;
}
}
else if ( dflag && c != 0x1a ) /* defines/includes etc. */
{
if ( c == '\n' )
dflag = 0;
}
else if ( aflag && c != 0x1a ) /* skip a character */
{
if ( c == 0x27 )
{
aflag = 0;
pushc( 0x1b );
}
else if ( c == '\\' )
eflag = 1;
}
else
{
switch ( c )
{
case '\"' :
qflag = 1;
break;
case 0x27 :
aflag = 1;
break;
case '#' :
dflag = 1;
break;
case '/' :
b = getchars( stream );
if ( b == '*' )
{
/* this is the first comment of the file */
if ( firstcmt == 0 )
{
firstcmt = 1;
filecmt[0] = 0;
fp = 0;
}
cflag = 1;
}
else
{
pushc( b );
}
break;
}
}
if ( aflag || dflag || qflag || eflag || cflag )
done=0;
}
while ( !done && c != 0x1a );
if ( c == 0x1a )
{
ncnt = 0;
aflag = 0;
dflag = 0;
qflag = 0;
eflag = 0;
cflag = 0;
}
return( c );
}
/* getchars - read inputs from the file */
getchars( stream )
FILE *stream;
{
register char c;
if ( pp != pc )
c = *--pp;
else
{
c = fgetc( stream );
if ( c == EOF )
c = 0x1a;
if ( c == 0x0a )
{
pMnames->length++;
pMnames->size++; /* count the unseen <cr> */
}
pMnames->size++;
}
return( c );
}
/* pushc - save the char. in a last in first out stack */
pushc( c )
char c;
{
if ( ( pp - pc ) < 1000 )
*pp++ = c;
else
{
fprintf( stderr, "\nProgram syntax error:" );
fprintf( stderr, " Too many pushed characters.\n" );
exit( 1 );
}
}
/* addlist - add the name to the list if different */
/* and if not one of the 'c' key words */
#define KEYS 5
addlist( p, buf, cnt )
struct Func_list *p;
char *buf;
int cnt;
{
int i, ret;
static char *keywords[KEYS] =
{
"while",
"if",
"for",
"switch",
"return",
};
for ( i=0; i<KEYS && strcmp( buf, keywords[i] )!=0; i++ )
;
if ( i < KEYS )
return( 0 );
for ( i=0; i<cnt && strcmp( buf, p->name ); i++ )
p++;
if ( i == cnt )
{
ret = 1;
if ( ( pFlist->name = strdup( buf ) ) == NULL )
{
fprintf( stderr, "Ran out of memory.\n" );
exit( 1 );
}
pFlist->used = 1;
pFlist++; /* point to the next empty cell */
Fqty++;
if ( Fqty > MAXFNCTS )
{
fprintf( stderr, "Too many functions.\n" );
exit( 1 );
}
}
else
{
ret = 0;
p->used++;
}
return( ret );
}
/* find_mod - return the index of the linked list for
the indicated function. A -1 means that
the function name was not found in the list */
find_mod( buf )
char *buf;
{
int lo, hi, mid;
int d;
lo = 0;
hi = Mqty - 1;
mid = ( hi + lo )/2;
while ( 1 )
{
d = strcmp( buf, pm[mid]->function );
if ( d == 0 )
break;
if ( lo >= hi )
{
mid = -1;
break;
}
if ( d < 0 )
{
hi = mid - 1;
}
else
{
lo = mid + 1;
}
mid = ( hi + lo )/2;
}
return( mid );
}
/* doprint - print the function name and sub - functions */
static char lib[] = {"(library)"};
static char use[] = {"Used="};
static char fct[] = {"Functs="};
doprint( n )
int n;
{
int i, j, k, l, ret;
struct Mod_list *p;
struct Func_list *q;
l = n;
p = pm[l];
/* add function to list for recursion check */
rlist[depth] = p->function;
pagebreak( );
setpage( pm[l] );
ret = page - 1;
pblock( bfr, p->function, ( p->name )->name, fct, p->qty );
depth++;
strcat( bfr, " |" );
k = p->qty;
for ( j=0, q = p->ptr; j<k; j++, q++ )
{
pagebreak( );
i = find_mod( q->name );
if ( recur_chk( q->name ) )
{
leftmargin( output );
fprintf( output, "%s\n", bfr );
if ( i >= 0 )
setpage( pm[i] );
pblock( bfr, q->name, "(recursive)", "", 0 );
line++;
}
else
{
if ( i >= 0 )
{
if ( pm[i]->used == 1 )
{
/* got a new function */
leftmargin( output );
fprintf( output, "%s\n", bfr );
line++;
doprint( i ); /* used only once */
}
else
{
/* a previously defined function */
leftmargin( output );
fprintf( output, "%s\n", bfr );
setpage( pm[i] );
pblock( bfr, q->name, "(defined)",
use, q->used );
line++;
}
}
else
{
/* a library function */
leftmargin( output );
fprintf( output, "%s\n", bfr );
pblock( bfr, q->name, lib, use, q->used );
line++;
}
}
}
/* remove the function from the recursion list */
rlist[depth] = NULL;
bfr[strlen( bfr )-4] = 0;
depth--;
return( ret );
}
/* getstats - get the number of times each
function is used */
getstats( )
{
register int i;
int j;
register struct Func_list *p;
p = Flist;
for ( i=0; i<Fqty; i++ )
{
j = find_mod( p->name ); /* see if the name exists */
if ( j >= 0 )
pm[j]->used += p->used;
p++;
}
}
/* pblock - print a function block */
pblock( pre, fptr, mptr, sptr, cnt )
char *pre, *fptr, *sptr, *mptr;
int cnt;
{
leftmargin( output );
fprintf( output, "%s %s\n", pre, tline );
leftmargin( output );
fprintf( output, "%s-+%-25s|\n", pre, fptr );
leftmargin( output );
fprintf( output, "%s |%-12s %8s%3d |\n",
pre, mptr, sptr, cnt );
leftmargin( output );
fprintf( output, "%s %s\n", pre, tline );
line += 4;
}
/* pagebreak - check for a page break and if so
then print the page header */
pagebreak( )
{
int i;
static char title[] = { "C PRINTER - (c) 1987, 1988 rev. 1.2" };
if ( pl == 0 && line == 9999 )
{
fprintf( output, "\n\n\n\n" );
line = 0;
}
else if ( pl != 0 )
{
if ( line > ( pl - 11 ) )
{
fprintf( output, "%c", 0x0c );
line = 0;
}
if ( line == 0 )
{
leftmargin( output );
fprintf( output, "%s", title );
for ( i=strlen( title ); i<width-10; i++ )
fputc( ' ', output );
fprintf( output, "Page:%4d\n", page );
leftmargin( output );
for ( i=0; i<width; i++ )
fputc( '-', output );
fprintf( output, "\n\n" );
line = 3;
page++;
}
}
}
/* recur_chk - check if the function just called
is one being processed */
recur_chk( buf )
char *buf;
{
register char **p;
int ret;
p = rlist;
while ( *p != NULL && strcmp( *p, buf ) )
{
p++;
}
if ( *p == NULL )
ret = 0; /* the function was not in the list */
else
ret = 1; /* found it */
return ret;
}
/* setpage - put the current page number
into the linked page list */
setpage( ptr )
struct Mod_list *ptr;
{
struct Pages *p;
p = ptr->pg;
if ( p == NULL )
{
p = ( struct Pages * )malloc( sizeof( struct Pages ) );
if ( p == NULL )
{
fprintf( stderr,
"Ran out of memory for page # list.\n" );
exit( 1 );
}
ptr->pg = p;
p->next = NULL;
p->pg = page - 1;
}
else
{
while ( p->next != NULL )
p=p->next;
p->next = ( struct Pages * )malloc( sizeof( struct Pages ) );
if ( p->next == NULL )
{
fprintf( stderr,
"Ran out of memory for page # list.\n" );
exit( 1 );
}
p = p->next;
p->next = NULL;
p->pg = page - 1;
}
}
/* strcheck - check if the character is
in the variable name set */
strcheck( c )
char c;
{
if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) ||
c == '_' || ( c >= '0' && c <= '9' ) )
return( 1 );
else
return( 0 );
}
stop( )
{
printf( "hello" );
}
/* print the left margin for the printout */
leftmargin( output )
FILE *output; /* the output device pointer */
{
register int i;
for ( i=0; i<lm; i++ )
fputc( ' ', output );
}
/*
LISTING 4
*/
#include <malloc.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXFNCTS 4000 /* maximum number of functions */
#define MAXMODULES 500 /* number of different files */
struct Func_list /* function statistics */
{
char *name; /* function name */
int used; /* times used in function */
};
struct Pages /* linked list of pages */
{
int pg; /* page number */
struct Pages *next; /* pointer to next page */
};
struct Module /* module statistics */
{
char *name; /* pointer to the module name */
char *cmt; /* module comment/description */
unsigned int length; /* lines in the module */
long size; /* bytes in the module */
};
struct Mod_list /* module control stucture */
{
struct Module *name; /* pointer to module file name */
char *function; /* name of function in file */
struct Func_list *ptr; /* pointer to the first function */
int qty; /* different functions called */
struct Pages *pg; /* point to the page list */
int used; /* times the function is used */
};
#if MAINMODULE != 0
struct Module Mnames[MAXMODULES], *pMnames;
struct Mod_list Mlist[MAXMODULES], *pMlist, *pm[MAXMODULES];
struct Func_list Flist[MAXFNCTS], *pFlist;
char *rlist[50]; /* recursion function list */
int Mqty = 0, Fqty = 0, Mcnt = 0;
int page=1, line=0, depth=0;
int fline;
int firstcmt;
char bfr[300];
char tline[] = {"+-------------------------+"};
char dbl[] = {" "};
char vbar[] = {"| "};
char hbar[] = {"+-"};
FILE *output;
char pc[1000] = {0,0,0,0,0,0,0,0,0,0};
char *pp;
char filecmt[300];
int pw = 80; /* page width */
int pl = 66; /* page length */
int lm = 8; /* left margin */
int rm = 8; /* right margin */
int width; /* the printable page width */
char target[40] = "main"; /* target function */
int stats = 0;
#else
extern struct Module Mnames[MAXMODULES], *pMnames;
extern struct Mod_list Mlist[MAXMODULES], *pMlist;
extern struct Mod_list *pm[MAXMODULES];
extern struct Func_list Flist[MAXFNCTS], *pFlist;
extern char *rlist[]; /* recursion function list */
extern int Mqty, Fqty, Mcnt;
extern int page, line, depth;
extern int fline;
extern int firstcmt;
extern char bfr[];
extern char tline[];
extern char dbl[];
extern char vbar[];
extern char hbar[];
extern FILE *output;
extern char pc[];
extern char *pp;
extern char filecmt[];
extern int pw; /* page width */
extern int pl; /* page length */
extern int lm; /* left margin */
extern int rm; /* right margin */
extern int width; /* the printable page width */
extern char target[]; /* target function */
extern int stats;
[76703,4265]
PARADI.LST 01-Aug-88 1358
Keywords: AUG88 PARADIGM SWAINE
Source from Michael Swaines Programming Paradigms column.
_PROGRAMMING PARADIGMS_
by
Michael Swaine
EXAMPLE 1
function parallel-sort L
if length(L)>1
then
split L into L1 and L2
par
parallel-sort L1
parallel-sort L2
merge L1 and L2 into L
end if
return L
end function
EXAMPLE 2
for pass=1 to ceiling(lgN) do
k:=2pass-1
par
merge length-k sublists Li and Li+1
merge length-k sublists Li+2 and Li+3
{etc., merging adjacent sublists pairwise}
end for
EXAMPLE 3
repeat forever
carry out private activities until hungry
repeat until sated
toss coin
if heads
then
firstSide:=left
secondSide:=right
else
firstSide:=right
secondSide:=left
wait until chopstick on firstSide is available
lift chopstick on firstSide
if chopstick on secondSide is not available
then
put down chopstick on firstSide
else
lift chopstick on firstSide
eat until sated
put down chopstick on firstSide
put down chopstick on secondSide
end if
end repeat
end repeat
EXAMPLE 4
push input formula F
repeat until stack is empty or satisfiability is reported
pop formula F
if F=0
then
report "satisfiable"
else
choose "appropriate" variable X
split F into FX and FX'
for e in {X,X'} do
if the empty clause is not in Fe
then
push Fe
end if
end do
end if
end repeat
[76703,4265]
PARADI.LST 01-Aug-88 1358 Accesses: 7
Disposition !
[76703,4265]
PORTER.LST 01-Aug-88 7781
Keywords: AUG88
Kent Porters Structered Progamming column for August 1988
Disposition !d
Capture Buffer Transfer
No error detection/correction
Opening capture buffer...
_STRUCTURED PROGRAMMING_
by
Kent Porter
LISTING 1
PROGRAM sub;
{ Enhanced version of DIR command }
{ Turbo Pascal 4.0 }
{ K. Porter, DDJ, August 88 }
USES dos, crt;
TYPE maskType = STRING [12];
pathType = STRING [80];
VAR oldDir, searchPath : pathType;
fileMask : maskType;
BlockSize, Nfiles : INTEGER;
TotalBytes, TotalK : LONGINT;
Thru : BOOLEAN;
{ ------------------------------------------------------------- }
PROCEDURE WriteFileInfo (VAR files : SearchRec);
{ List filename, date, time, etc. }
VAR KBytes : LONGINT;
FUNCTION TimeStamp : STRING;
{ Return file date/time by unpacking time field }
VAR stamp : DateTime;
StampStr, WorkStr : STRING [20];
ap : CHAR;
BEGIN
UnpackTime (files.time, stamp);
Str (stamp.month, StampStr); { Format year as string }
IF stamp.month < 10 THEN StampStr := '0' + StampStr;
Str (stamp.day, WorkStr);
IF stamp.day < 10 THEN
StampStr := StampStr + '-0' + WorkStr
ELSE
StampStr := StampStr + '-' + WorkStr;
Str (stamp.year - 1900, WorkStr);
StampStr := StampStr + '-' + WorkStr + ' ';
IF stamp.hour > 11 THEN
ap := 'p'
ELSE
ap := 'a';
IF stamp.hour > 12 THEN
stamp.hour := stamp.hour - 12;
Str (stamp.hour, WorkStr); { Format time string }
IF stamp.hour < 10 THEN
StampStr := StampStr + '0' + WorkStr
ELSE
StampStr := StampStr + WorkStr;
Str (stamp.min, WorkStr);
IF stamp.min < 10 THEN
StampStr := StampStr + ':0'
ELSE
StampStr := StampStr + ':';
TimeStamp := StampStr + WorkStr + ap;
END;
FUNCTION Attribs : STRING;
{ Return file attributes as a string of indicators }
VAR attrib : STRING [6];
BEGIN
attrib := '......';
WITH files DO BEGIN
IF attr AND ReadOnly <> 0 THEN attrib [6] := 'R';
IF attr AND Hidden <> 0 THEN attrib [5] := 'H';
IF attr AND Sysfile <> 0 THEN attrib [4] := 'S';
IF attr AND VolumeID <> 0 THEN attrib [3] := 'V';
IF attr AND Directory <> 0 THEN attrib [2] := 'D';
IF attr AND Archive <> 0 THEN attrib [1] := 'A';
END;
Attribs := attrib;
END;
FUNCTION SizeInK : INTEGER;
{ Return allocated size of file in K }
VAR size : LONGINT;
BEGIN
IF files.size = 0 THEN
SizeInK := 0
ELSE BEGIN
Size := files.size DIV BlockSize;
IF size MOD BlockSize <> 0 THEN
Inc (size);
IF size = 0 THEN size := 1;
SizeInK := (size * BlockSize) DIV 1024;
END;
END;
BEGIN { Body of WriteFileInfo }
Write (files.name); Gotoxy (21, whereY);
Write (TimeStamp); Gotoxy (42, whereY);
Write (Attribs); Gotoxy (53, whereY);
Write (files.size : 6); Gotoxy (64, whereY);
KBytes := SizeInK;
Writeln (KBytes : 3, 'K');
TotalK := TotalK + KBytes; { Accumulate totals }
TotalBytes := TotalBytes + files.size;
Inc (NFiles);
END;
{ ------------------------------------------------------------- }
PROCEDURE ListFiles (path : pathType; mask : maskType);
{ List files in currently selected directory using mask }
VAR files : SearchRec;
heading : STRING [160];
lineCount : INTEGER;
PROCEDURE StartPage; { Begin a new page }
BEGIN
ClrScr;
Writeln (heading);
Write ('Name Date Time Attrib');
Writeln (' Bytes Size');
LineCount := 3;
END;
PROCEDURE CountLines; { Count lines, start new page if full }
VAR ch : CHAR;
BEGIN
Inc (LineCount);
IF LineCount = 24 THEN BEGIN
Gotoxy (1, 25);
Write ('-- MORE --');
ch := ReadKey;
StartPage;
END
END;
PROCEDURE ShowTotals; { Show total bytes, K, files, etc. }
VAR free, size : REAL;
BEGIN
size := DiskSize(0); { Size of default disk in bytes }
free := DiskFree(0);
Write (NFiles, ' files, ', TotalBytes, ' bytes, ');
Writeln (TotalK, 'K space');
Write (free:1:0, ' bytes free out of ', size:1:0, '
total (');
Write ((((size-free) / size) * 100.0) : 5 : 2);
Writeln ('% utilization)');
END;
BEGIN { Body of ListFiles }
Heading := 'Directory for ' + mask + ' in ' +
path + ':';
StartPage;
FindFirst (mask, AnyFile, files);
IF DosError = 0 THEN
REPEAT
WriteFileInfo (files);
CountLines;
FindNext (files);
UNTIL DosError <> 0;
ShowTotals;
END;
{ --------------------------- }
PROCEDURE Separate (VAR path : pathType; VAR mask : maskType);
{ Break out path and mask from command-line argument }
VAR p, c : INTEGER;
BEGIN
path := ParamStr(1);
mask := '';
p := Length (path);
WHILE (path [p] <> '\') AND (p > 0) DO { Find last \ in arg }
Dec (p);
IF p > 0 THEN BEGIN
FOR c := (p + 1) TO Length (path) DO
mask := mask + path [c]; { copy file mask }
IF p = 1 THEN
path [0] := chr (1) { backslash only }
ELSE
path [0] := chr (p - 1); { truncate path before \ }
END;
END;
{ --------------------------- }
FUNCTION AllocInfo : INTEGER;
{ Returns the size of a disk allocation unit in bytes }
VAR reg : registers;
BEGIN
reg.ah := $1B;
Intr ($21, reg); { DOS Int 21h, Fcn 1B }
AllocInfo := reg.al * reg.cx; { sec/cluster * sec size }
END;
{ --------------------------- }
PROCEDURE Check (VAR mask : maskType);
{ Check file mask, complete if necessary }
BEGIN
IF mask [1] = '.' THEN { if form is '.EXT'... }
mask := '*' + mask;
IF pos ('.', mask) = 0 THEN { if mask has no period... }
mask := mask + '.*';
END;
{ --------------------------- }
BEGIN { Main program }
GetDir (0, oldDir); { Save the current directory }
BlockSize := AllocInfo; { Initialize globals }
TotalBytes := 0;
TotalK := 0;
NFiles := 0;
Thru := FALSE;
fileMask := '*.*'; { Initialize mask and path }
searchPath := oldDir;
IF ParamCount < 1 THEN { No command-line arg, so }
BEGIN { show all files in curr dir }
ListFiles (searchPath, fileMask);
Thru := TRUE;
END;
{$I-} { Disable auto error checking }
IF not thru THEN BEGIN { Is command SUB <dir> or SUB \<dir>? }
searchPath := ParamStr(1);
ChDir (searchPath); { Try to set directory }
IF IOResult = 0 THEN BEGIN { List if successful }
{$I+} { Re-enable error checking }
ListFiles (searchPath, fileMask);
Thru := TRUE;
END;
END;
{$I-}
IF not thru THEN BEGIN { Is command SUB <dir\*.*>? }
Separate (searchPath, fileMask);
ChDir (searchPath); { Try to set directory }
IF IOResult = 0 THEN
IF Length (FileMask) > 0 THEN BEGIN
Check (fileMask);
ListFiles (searchPath, fileMask);
Thru := TRUE;
END;
END;
IF not thru THEN BEGIN { Is command SUB *.*? }
fileMask := ParamStr(1);
Check (fileMask);
ListFiles (oldDir, fileMask);
Thru := TRUE;
END;
IF not thru THEN
Writeln ('PATH NOT FOUND');
ChDir (oldDir); { Restore former directory }
END.