Article View: alt.msdos.programmer
Article #1170Re: Two C problems
From: John R Buchan
Date: Mon, 08 Jan 1996 17:16
Date: Mon, 08 Jan 1996 17:16
355 lines
11469 bytes
11469 bytes
In article <4cojnn$rgd@lugb.latrobe.edu.au>, csigjb@luxor.latrobe.edu.au
says...
>
>I have two C problems.
The following is a reformatted (sorry, I prefer my format) version of the
full version of the code that was originally posted (sorry about the rather
large post folks). I have made a few modifications (I think I remembered to
add comments by each. Please excuse those that you have already corrected
in your second post) and it now seems to be functional (though I can't be
certain that it functions the way you expected). BTW, You might want to
consider breaking your main into smaller functions.
As a few people have probably mentioned, it is considered rather poor taste
to post non-ansi code in c.l.c and even worse to post incomplete uncompilable
code. Always try to post a minimum compilable example (as little non-ansi
code as possible) that illustrates your problem. It is sometimes easier to
write a new small program for this rather than trying to edit the original
(just be sure that it probuces the same problem) A consistant format and
well placed comments are also helpful.
#include <stdio.h>
#include <stdlib.h> /* needed for ansi exit() and EXIT_FAILURE */
#include <conio.h>
#include <string.h>
#include <alloc.h>
#include <process.h>
/* it is fairly common practice to use all caps in the names of globals. */
#define maxstring 127 /* this should be a constant expression not a const */
const lineend='\n';
const escape=27;
const null='\0'; /* Using nul for this name will cause less confusion. */
const space=' ';
const up='H';
const down='P';
const pageup='I';
const pagedown='Q';
const left='K';
const right='M';
const home='G';
const end_='O';
typedef char string[maxstring]; /* needs a constant expression, not a const */
typedef struct nodetypetag
{
string line;
int linenum;
struct nodetypetag *next,*previous;
} nodetype;
typedef nodetype *nodetypeptr;
string line,line_,line1,bottomline;
char empty(nodetypeptr posptr)
{
return(posptr==NULL);
}
void initialize(nodetypeptr *listptr)
{
*listptr=NULL;
}
void add(nodetypeptr *listptr,char *fileline,int Linenum)
{
nodetypeptr newptr,tempptr;
newptr=(nodetypeptr)malloc(sizeof(nodetype));
/* need to verify allocation success */
strcpy(newptr->line,fileline);
newptr->linenum=Linenum;
newptr->next=NULL; /* no need to write this twice */
if (*listptr==NULL)
{
(*listptr)=newptr;
/* (*listptr)->next=NULL; not needed */
(*listptr)->previous=NULL;
}
else
{
tempptr=*listptr;
while (tempptr->next!=NULL)
{
tempptr=tempptr->next;
}
tempptr->next=newptr;
/* newptr->next=NULL; not needed */
newptr->previous=tempptr;
}
}
/* void remove(nodetypeptr *listptr) name is in conflict with the ansi */
/* function remove, which is prototyped in stdio.h */
void RemoveNode(nodetypeptr *listptr)
{
nodetypeptr tempptr;
/* NULL tests missing */
if( listptr != NULL && *listptr != NULL) /* at least 1 node exists */
{
tempptr=*listptr;
*listptr=(*listptr)->next;
(*listptr)->previous=NULL;
free(tempptr);
}
}
/* This would probably work better as: *
* *
* nodetypeptr setpos( int linenum) *
* *
* This would reduce the number of indirects and allow you to return *
* NULL, if an invalid number manages to be passed in. */
void setpos(nodetypeptr *posptr,int linenum)
{
while ((*posptr)->linenum!=linenum)
{
if ((*posptr)->linenum>linenum)
{
*posptr=(*posptr)->previous;
}
else
if ((*posptr)->linenum<linenum)
{
*posptr=(*posptr)->next;
}
}
}
void writescreenfull(char width,char height,nodetypeptr posptr,char stringpos)
{
char y;
char *line__; /* this definition was apparently left out */
window(1,1,width,height);
clrscr();
window(1,1,width,height+1);
y=1;
while ((y<=height) && (!empty(posptr->next)))
{
gotoxy(1,y);
strcpy(line_,posptr->line);
line__=&(line_[stringpos]); /* line__ = line_ + stringpos; */
strncpy(line,line__,width-1);
/* strcat(line,null); someone else explained this already */
line[maxstring - 1] = '\0'; /* this provides your safety */
cputs(line);
posptr=posptr->next;
y++;
}
}
/* Since fgets will always append a '\0', there is no need for the *
* maxstrings parameter. Just test for '\0' and '\n' or use the ansi *
* strrchr function. */
void removelineends(char *strings,unsigned int maxstrings)
{
unsigned int i;
i=0;
while ((i<maxstrings) && (strings[i]!=lineend))
{
i++;
}
strings[i]=null;
}
int main(int argc,char *argv[]) /* main must return int */
{
FILE *file;
char x,ch,width,height,back,fore,stringpos;
int numlines,linenum;
struct text_info info; /* forgot the struct */
nodetypeptr listptr,posptr;
if (argc<2)
{
cputs("\nShow what . . .\n");
exit(EXIT_FAILURE); /* exit with failure value, when code fails */
}
else
{
file=fopen(argv[1],"rt");
if (file==NULL)
{
cprintf("\nFile %s not found . . .\n",argv[1]);
exit(EXIT_FAILURE); /* exit with failure value, when code fails */
}
else
{
rewind(file); /* not needed, "r" opens to the beginning anyway */
initialize(&listptr);
linenum=0;
while (fgets(line,maxstring,file)!=NULL)
{
removelineends(line,maxstring);
add(&listptr,line,linenum);
linenum++;
}
numlines=linenum--; /* ?? */
fclose(file);
posptr=listptr;
/* This would make a nice 'InitScreen' function */
gettextinfo(&info);
fore=info.attribute&0x0f;
back=(info.attribute&0x70)/0x10;
height=info.screenheight;
width=info.screenwidth;
strcpy(bottomline," \30 \31 pgup pgdn s <string> "
"(search for string) esc (quit)");
for(x=strlen(bottomline)+1;x<width;x++)
{
strcat(bottomline," ");
}
/* look into sprintf */
_setcursortype(_NOCURSOR);
clrscr();
textcolor(back);
textbackground(fore);
gotoxy(1,height);
cputs(bottomline);
textcolor(fore);
textbackground(back);
/* end 'InitScreen' function */
height--;
linenum=0; /* the first line in your list is 0, not 1 */
stringpos=0; /* this should start at 0, not 1 */
writescreenfull(width,height,posptr,stringpos);
ch=space;
while (ch!=escape)
{
while ((ch!=up) && (ch!=down) && (ch!=pageup) &&
(ch!=pagedown) && (ch!=escape) && (ch!=left) &&
(ch!=right) && (ch!=end_) && (ch!=home))
{
ch=getch();
if (ch==null)
{
ch=getch();
}
}
/* This would be much clearer using a switch statement */
if (ch==up)
{
if ((linenum-1)>=0)
{
linenum--;
}
else
{
linenum=0;
}
setpos(&posptr,linenum);
}
else
if (ch==down)
{
if ((linenum+1+height)<=numlines) /* ?? */
{
linenum++;
}
else
{
linenum=numlines-height+1;
}
setpos(&posptr,linenum);
}
else
if (ch==pageup)
{
if ((linenum-height+1)>=1)
{
linenum=linenum-height+1;
}
else
{
linenum=1;
}
setpos(&posptr,linenum);
}
else
if (ch==pagedown)
{
if (((linenum+height-1)<=numlines) &&
((numlines-(linenum+height-1))>=(height-1)))
{
linenum=linenum+height-1;
}
else
{
linenum=numlines-height+1;
}
setpos(&posptr,linenum);
}
else
if (ch==left)
{
if (stringpos>0) /* s/b 0 */
{
stringpos--;
}
}
else
if (ch==right)
{
if (stringpos<=(maxstring-width))
{
stringpos++;
}
}
else
if (ch==end_)
{
stringpos=maxstring-width+1;
}
else
if (ch==home)
{
stringpos=0; /* s/b 0, not 1 */
}
if (ch!=escape)
{
ch=space;
}
writescreenfull(width,height,posptr,stringpos);
}
height+=1;
window(1,1,width,height);
clrscr();
_setcursortype(_NORMALCURSOR);
while (!empty(listptr))
{
RemoveNode(&listptr);
}
}
}
return 0;
}
--
John R Buchan -:|:- Looking for that elusive FAQ? ftp to:
jatmon@mail.iag.net -:|:- rtfm.mit.edu /pub/usenet-by-group/....
Technical Details
Message-ID:
<4crjh3$d71@news.iag.net>Path:
arc1-ca.pugleaf.net!news.iag.net!newsReferences:
<4cojnn$rgd@lugb.latrobe.edu.au>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!news.iag.net!news From: jatmon@iag.net (John R Buchan) Newsgroups: alt.msdos.programmer,comp.lang.c Subject: Re: Two C problems Date: 8 Jan 1996 17:16:19 GMT Organization: Internet Access Group, Orlando, Florida Distribution: world Message-ID: <4crjh3$d71@news.iag.net> References: <4cojnn$rgd@lugb.latrobe.edu.au> NNTP-Posting-Host: pm3-orl29.iag.net X-Newsreader: WinVN 0.99.7