Code:
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> // for isspace()
int barmenu(const char const **array, int row, int col,
int arraylength, int width, int menulength, int selection);
// Removes whitespace from the end of strings
void chomp(char *str)
{
int len=strlen(str);
if(len>0)
while((len>0) && isspace(str[len-1]))
str[--len]='\0';
}
int main(void)
{
char buf[128];
int selection,row=1,col=10,arraylength=0,width=5, menulength=5;
char **testarray=NULL;
FILE *fp=fopen("filename","r");
while(fgets(buf,128,fp) != NULL)
{
chomp(buf); // Remove \n from end of line
if(strlen(buf) > width) width=strlen(buf);
if(!buf[0]) continue; // Ignore blank lines
arraylength++;
// Room for n+1 elements of char * size.
testarray=realloc(testarray, sizeof(char *)*(arraylength+1));
// strdup is an easy str=malloc(strlen(s)+1); strcpy(str,s);
testarray[arraylength-1]=strdup(buf);
}
// The +1 gives us room for a NULL on the end. Makes it easier to find crashes.
testarray[arraylength]=NULL;
fclose(fp);
// If no elements were loaded, it will still be NULL
if(testarray == NULL)
{
fprintf(stderr, "Unable to load options\n");
exit(1);
}
initscr();
noecho();
keypad(stdscr,TRUE);
selection=barmenu((const char const **)testarray,row,col,arraylength,width,menulength,0);
mvprintw(15,0,"Selection= %d",selection);
refresh();
getch();
endwin();
// Add another option to file
fp=fopen("filename","a");
fputs("whatever\n", fp);
fclose(fp);
// We allocated all this stuff, so free it.
for(col=0; col<arraylength; col++) if(testarray[col]) free(testarray[col]);
free(testarray);
// Cannot return -1 to commandline. 127 is the maximum we should return.
if(selection < 0) return(127);
// 0 has special meaning, return n+1
return selection+1;
}
int barmenu(const char const **array, int row, int col,
int arraylength, int width, int menulength, int selection)
{
int counter,offset=0,ky=0;
char formatstring[7];
curs_set(0);
if (arraylength < menulength)
menulength=arraylength;
if (selection > menulength)
offset=selection-menulength+1;
sprintf(formatstring,"%%-%ds",width); // remove - sign to right-justify the menu items
while(ky != 27)
{
for (counter=0; counter < menulength; counter++)
{
if (counter+offset==selection)
attron(A_REVERSE);
mvprintw(row+counter,col,formatstring,array[counter+offset]);
attroff(A_REVERSE);
}
ky=getch();
switch(ky)
{
case KEY_UP:
if (selection)
{
selection--;
if (selection < offset)
offset--;
}
break;
case KEY_DOWN:
if (selection < arraylength-1)
{
selection++;
if (selection > offset+menulength-1)
offset++;
}
break;
case KEY_HOME:
selection=0;
offset=0;
break;
case KEY_END:
selection=arraylength-1;
offset=arraylength-menulength;
break;
case KEY_PPAGE:
selection-=menulength;
if (selection < 0)
selection=0;
offset-=menulength;
if (offset < 0)
offset=0;
break;
case KEY_NPAGE:
selection+=menulength;
if (selection > arraylength-1)
selection=arraylength-1;
offset+=menulength;
if (offset > arraylength-menulength)
offset=arraylength-menulength;
break;
case 10: //enter
return selection;
break;
case KEY_F(1): // function key 1
return -1;
case 27: //esc
// esc twice to get out, otherwise eat the chars that don't work
//from home or end on the keypad
ky=getch();
if (ky == 27)
{
curs_set(0);
mvaddstr(9,77," ");
return -1;
}
else
if (ky=='[')
{
getch();
getch();
}
else
ungetch(ky);
}
}
return -1;
}