6
char *XCursesProgramName="syb";
10
#define MAXHISTORY 1000
13
* This structure is used for keeping command history.
18
char *command[MAXHISTORY];
22
* Define some global variables.
24
char *GPUsage = "[-p Command Prompt] [-U User] [-P Password] [-S Server] [-h help]";
25
char *GPCurrentDatabase = 0;
26
extern char *dberrstr;
29
* Because the error/message callback do not allow you to pass in
30
* data of your own, we have to make the screen pointer global. :(
32
CDKSCREEN *GPCdkScreen = 0;
35
* Define function prototypes.
37
DBPROCESS *loginToSybase (CDKSCREEN *screen, char *login, char *password);
38
DBPROCESS *sybaseLogin (CDKSCREEN *screen, char *login, char *password, int attempts);
39
char *assembleTitle (DBPROCESS *dbProcess);
40
char *assembleRow (DBPROCESS *dbProcess);
41
char *uc (char *word);
42
int getColWidth (DBPROCESS *dbProcess, int col);
43
void runIsqlCommand (CDKSCREEN *cdkscreen, CDKSWINDOW *swindow, DBPROCESS *process);
44
void useDatabase (CDKSWINDOW *swindow, DBPROCESS *dbProc, char *command);
45
void intro (CDKSCREEN *screen);
46
void help (CDKENTRY *entry);
47
void loadHistory (struct history_st *history);
48
void saveHistory (struct history_st *history, int count);
51
* Define callback prototypes.
53
void viewHistoryCB (EObjectType cdktype, void *object, void *clientData, chtype key);
54
void swindowHelpCB (EObjectType cdktype, void *object, void *clientData, chtype key);
55
void historyUpCB (EObjectType cdktype, void *object, void *clientData, chtype key);
56
void historyDownCB (EObjectType cdktype, void *object, void *clientData, chtype key);
57
void listHistoryCB (EObjectType cdktype, void *object, void *clientData, chtype key);
60
* Define Sybase error/message callbacks. This is required by DBLib.
62
int err_handler (DBPROCESS *dbProcess, DBINT mesgNumber, int mesgState,
63
int severity, char *mesgText);
64
int msg_handler (DBPROCESS *dbProcess, DBINT mesgNumber, int mesgState,
65
int severity, char *mesgText);
68
* Written by: Mike Glover
70
* This creates a very simple interface to Sybase.
72
int main (int argc, char **argv)
74
/* Declare variables. */
75
CDKSWINDOW *commandOutput = 0;
76
CDKENTRY *commandEntry = 0;
77
DBPROCESS *dbProcess = 0;
78
WINDOW *cursesWin = 0;
89
struct history_st history;
90
char *mesg[5], temp[1000];
92
/* Set up the history. */
93
GPCurrentDatabase = strdup ("master");
97
/* Check the command line for options. */
100
/* Are there any more command line options to parse. */
101
if ((ret = getopt (argc, argv, "p:U:P:S:h")) == -1)
109
prompt = copyChar (optarg);
113
login = copyChar (optarg);
117
password = copyChar (optarg);
121
server = copyChar (optarg);
125
printf ("Usage: %s %s\n", argv[0], GPUsage);
131
/* Set up the command prompt. */
136
if ((dsquery = getenv ("DSQUERY")) != 0)
138
sprintf (temp, "</B/24>[%s] Command >", dsquery);
139
prompt = copyChar (temp);
143
prompt = copyChar ("</B/24>Command >");
148
sprintf (temp, "</B/24>[%s] Command >", server);
149
prompt = copyChar (temp);
154
cursesWin = initscr();
155
GPCdkScreen = initCDKScreen (cursesWin);
160
/* Initialize DB-Library. */
161
if (dbinit() == FAIL)
163
mesg[0] = "<C></U>Fatal Error";
164
mesg[1] = "<C>Could not connect to the Sybase database.";
165
popupLabel (GPCdkScreen, mesg, 2);
169
/* Load the history. */
170
loadHistory (&history);
172
/* Create the scrolling window. */
173
commandOutput = newCDKSwindow (GPCdkScreen, CENTER, TOP, -8, -2,
174
"<C></B/5>Command Output Window",
175
MAXWIDTH, TRUE, FALSE);
177
/* Create the entry field. */
178
width = COLS - strlen (prompt) - 1;
179
commandEntry = newCDKEntry (GPCdkScreen, CENTER, BOTTOM,
180
0, prompt, A_BOLD|COLOR_PAIR(8),
181
COLOR_PAIR(24)|'_', vMIXED,
182
width, 1, 512, FALSE, FALSE);
184
/* Create the key bindings. */
185
bindCDKObject (vENTRY, commandEntry, KEY_UP, &historyUpCB, &history);
186
bindCDKObject (vENTRY, commandEntry, KEY_DOWN, &historyDownCB, &history);
187
bindCDKObject (vENTRY, commandEntry, CONTROL('^'), &listHistoryCB, &history);
188
bindCDKObject (vENTRY, commandEntry, TAB, &viewHistoryCB, commandOutput);
189
bindCDKObject (vSWINDOW, commandOutput, '?', swindowHelpCB, commandEntry);
191
/* Draw the screen. */
192
refreshCDKScreen (GPCdkScreen);
194
/* Display the introduction window. */
197
/* Make them login first. */
198
dbProcess = sybaseLogin (GPCdkScreen, login, password, 3);
201
destroyCDKScreen (GPCdkScreen);
206
/* Do this forever. */
209
/* Get the command. */
210
command = activateCDKEntry (commandEntry, 0);
212
/* Strip off leading and trailing white space. */
213
stripWhiteSpace (vBOTH, command);
215
/* Upper case the command. */
216
upper = uc (command);
218
/* Check the output of the command. */
219
if (strcmp (upper, "QUIT") == 0 ||
220
strcmp (upper, "EXIT") == 0 ||
221
strcmp (upper, "Q") == 0 ||
222
strcmp (upper, "E") == 0 ||
223
commandEntry->exitType == vESCAPE_HIT)
225
/* Save the history. */
226
saveHistory (&history, 100);
233
destroyCDKEntry (commandEntry);
234
destroyCDKSwindow (commandOutput);
240
else if (strcmp (command, "login") == 0)
242
DBPROCESS *newLogin = sybaseLogin (GPCdkScreen, 0, 0, 3);
245
addCDKSwindow (commandOutput, "Login Error: Could not switch to new user.", BOTTOM);
249
/* Close the old connection. */
251
dbProcess = newLogin;
253
/* Add a message to the scrolling window. */
254
addCDKSwindow (commandOutput,
255
"Logged into database as new user.",
260
else if (strcmp (command, "logout") == 0)
262
/* Close the old connection. */
266
/* Add a message to the scrolling window. */
267
addCDKSwindow (commandOutput, "Logged out.", BOTTOM);
270
else if (strcmp (command, "clear") == 0)
272
/* Clear the scrolling window. */
273
cleanCDKSwindow (commandOutput);
275
else if (strcmp (command, "history") == 0)
277
listHistoryCB (vENTRY, (void *)commandEntry, (void *)&history, 0);
279
else if (strcmp (command, "tables") == 0)
281
/* Check if we are logged in. */
284
addCDKSwindow (commandOutput, "You must login first.", BOTTOM);
288
sprintf (command, "select * from sysobjects where type = 'U'");
290
/* Put the command into the ISQL buffer. */
291
dbcmd (dbProcess, command);
293
/* Put the command into the scrolling window. */
294
sprintf (temp, "</R>%d><!R> %s", count+1, command);
295
addCDKSwindow (commandOutput, temp, BOTTOM);
297
/* Increment the counter. */
301
else if (strcmp (command, "help") == 0)
303
/* Display the help. */
306
else if (command[0] == 'u' && command[1] == 's' &&
307
command[2] == 'e' && command[3] == ' ')
309
/* They want to use a database. */
310
useDatabase (commandOutput, dbProcess, command);
313
else if (strcmp (command, "go") == 0)
315
/* Check if we are logged in. */
318
addCDKSwindow (commandOutput, "You must login first.", BOTTOM);
322
/* Put the command into the scrolling window. */
323
sprintf (temp, "</R>%d><!R> %s", count+1, command);
324
addCDKSwindow (commandOutput, temp, BOTTOM);
327
/* Run the command. */
328
runIsqlCommand (GPCdkScreen, commandOutput, dbProcess);
333
/* Check if we are logged in. */
336
addCDKSwindow (commandOutput, "You must login first.", BOTTOM);
340
/* Put the command into the ISQL buffer. */
341
dbcmd (dbProcess, command);
343
/* Put the command into the scrolling window. */
344
sprintf (temp, "</R>%d><!R> %s", count+1, command);
345
addCDKSwindow (commandOutput, temp, BOTTOM);
347
/* Increment the counter. */
352
/* Keep the history. */
353
history.command[history.count] = copyChar (command);
355
history.current = history.count;
357
/* Clear the entry field. */
358
cleanCDKEntry (commandEntry);
360
/* Free up the memory used by the upper pointer. */
366
* This lets a person 'use' a database.
368
void useDatabase (CDKSWINDOW *swindow, DBPROCESS *dbProc, char *command)
375
/* Split the command line up and get the database name. */
376
words = CDKsplitString (command, ' ');
377
wordCount = CDKcountStrings (words);
379
/* Look for the name. */
380
for (x=1; x < wordCount; x++)
382
if (strlen (words[x]) != 0)
384
database = copyChar (words[x]);
387
CDKfreeStrings(words);
389
/* Try to actually use the database. */
390
if (dbuse(dbProc, database) == FAIL)
392
/* We aren't allowed to use that database. */
393
sprintf (temp, "Command: %s", command);
394
addCDKSwindow (swindow, temp, BOTTOM);
395
addCDKSwindow (swindow, "</B/16>Error<!B!16> You are not allowed to use that database.", BOTTOM);
399
/* Set the global database name. */
402
/* Put a syntax error in the scrolling window. */
403
sprintf (temp, "Command: %s", command);
404
addCDKSwindow (swindow, temp, BOTTOM);
405
addCDKSwindow (swindow, "</B/16>Error<!B!16> Syntax Error", BOTTOM);
409
/* Clear out the old database name and set the new one. */
410
freeChar (GPCurrentDatabase);
411
GPCurrentDatabase = database;
413
/* Add a message into the scrolling window. */
414
sprintf (temp, "Command: %s", command);
415
addCDKSwindow (swindow, temp, BOTTOM);
416
sprintf (temp, "Default Database set to %s", GPCurrentDatabase);
417
addCDKSwindow (swindow, temp, BOTTOM);
421
* This does the requisite checking for failed login attempts.
423
DBPROCESS *sybaseLogin (CDKSCREEN *screen, char *accountName, char *accountPassword, int attemptCount)
425
DBPROCESS *dbProcess = 0;
426
char *login = accountName;
427
char *password = accountPassword;
432
/* Give them X attempts, then kick them out. */
433
while (count < attemptCount)
436
dbProcess = loginToSybase (GPCdkScreen, login, password);
439
* If the dbprocess is null the account/password
440
* pair does not exist.
445
* If the login and account names were provided,
446
* set them to null and allow the user to enter
447
* the name and password by hand.
452
/* Spit out the login error message. */
454
mesg[lines++] = "<C></B/5>Login Error";
456
mesg[lines++] = "<C>The login/password pair does not exist.";
458
mesg[lines++] = "<C>Please try again.";
460
popupLabel (GPCdkScreen, mesg, lines);
462
eraseCDKScreen (GPCdkScreen);
463
refreshCDKScreen (GPCdkScreen);
472
/* Did we expire the login attempts? */
473
if (count > attemptCount-1)
476
mesg[lines++] = "<C>Login Error";
478
mesg[lines++] = "<C>Too many attempyts to login.";
479
mesg[lines++] = "<C>Exiting.";
481
popupLabel (GPCdkScreen, mesg, lines);
489
* Let the user login.
491
DBPROCESS *loginToSybase (CDKSCREEN *screen, char *accountName, char *accountPassword)
493
CDKENTRY *loginEntry = 0;
494
CDKENTRY *passwordEntry = 0;
495
LOGINREC *dbLogin = 0;
496
char *hostAccount = 0;
497
char *login = accountName;
498
char *password = accountPassword;
499
char *mesg[10], temp[256];
501
/* Draw the screen. */
502
refreshCDKScreen (screen);
504
/* Define the login entry field. */
507
loginEntry = newCDKEntry (screen, CENTER, CENTER,
508
"\n<C></B/5>Sybase Login\n",
510
A_BOLD|COLOR_PAIR(8),
511
COLOR_PAIR(24)|'_', vMIXED,
512
20, 1, 20, TRUE, FALSE);
514
/* Use the current account name as the default answer. */
515
hostAccount = getlogin();
516
setCDKEntryValue (loginEntry, hostAccount);
521
/* Redraw the screen. */
522
eraseCDKScreen (loginEntry->screen);
523
refreshCDKScreen (loginEntry->screen);
525
/* Get the login to the sybase account. */
526
login = copyChar (activateCDKEntry (loginEntry, 0));
528
/* Check if they hit escape. */
529
if (loginEntry->exitType == vESCAPE_HIT)
531
mesg[0] = "<C></U>Error";
532
mesg[1] = "A user name must be provided.";
533
popupLabel (screen, mesg, 2);
541
/* Destroy the widget. */
542
destroyCDKEntry (loginEntry);
545
/* Get the password if we need too. */
548
sprintf (temp, "\n<C></B/5>%s's Password\n", login);
549
passwordEntry = newCDKEntry (screen, CENTER, CENTER,
550
temp, "Account Password: ",
551
A_BOLD|COLOR_PAIR(8),
552
COLOR_PAIR(24)|'_', vHMIXED,
553
20, 0, 20, TRUE, FALSE);
554
setCDKEntryHiddenChar (passwordEntry, '*');
556
/* Get the password. (the account may not have a password.) */
557
password = copyChar (activateCDKEntry (passwordEntry, 0));
558
if ((passwordEntry->exitType == vESCAPE_HIT) ||
559
((int)strlen(password) == 0))
564
/* Destroy the widget. */
565
destroyCDKEntry (passwordEntry);
569
* Try to connect to the database and get a LOGINREC structre.
571
if ((dbLogin = dblogin()) == 0)
573
mesg[0] = "<C></U>Fatal Error";
574
mesg[1] = "<C>Could not connect to the Sybase database.";
575
popupLabel (screen, mesg, 2);
576
refreshCDKScreen (screen);
581
* Set the login and password and try to login to the database.
583
DBSETLUSER (dbLogin, login);
584
DBSETLPWD (dbLogin, password);
585
DBSETLAPP (dbLogin, "cdk_syb");
587
/* Create a dbprocess structure to communicate with the database. */
588
return dbopen (dbLogin, 0);
592
* This actually runs the command.
594
void runIsqlCommand (CDKSCREEN *screen, CDKSWINDOW *swindow, DBPROCESS *dbProcess)
596
/* Declare local variables. */
600
/* Add in a output seperation line. */
601
addCDKSwindow (swindow, "<C><#HL(5)> Start of Output <#HL(5)>", BOTTOM);
603
/* Run the command. */
604
dbsqlexec (dbProcess);
606
/* Check the return code of the commands. */
607
while ((returnCode = dbresults (dbProcess)) != NO_MORE_RESULTS)
609
if (returnCode == FAIL)
611
/* Oops, the command bombed. */
612
addCDKSwindow (swindow, "</5/16>Command failed.", BOTTOM);
616
if (!(DBCMDROW (dbProcess)))
618
/* The command could not return any rows. */
619
addCDKSwindow (swindow, "</5/16>Command could not return rows.", BOTTOM);
624
* The command returned some rows, print out the title.
626
char *row = assembleTitle (dbProcess);
627
addCDKSwindow (swindow, row, BOTTOM);
630
/* For each row returned, assemble the info. */
632
while (dbnextrow (dbProcess) != NO_MORE_ROWS)
634
row = assembleRow (dbProcess);
635
addCDKSwindow (swindow, row, BOTTOM);
642
/* Add in a output seperation line. */
643
addCDKSwindow (swindow, "<C><#HL(5)> End of Output <#HL(5)>", BOTTOM);
644
addCDKSwindow (swindow, "", BOTTOM);
646
/* Can the query... */
647
dbcanquery (dbProcess);
651
* This creates a single line from the column widths and values.
653
char *assembleTitle (DBPROCESS *dbProc)
658
int colCount = dbnumcols (dbProc);
663
/* Clean the row out. */
664
memset (row, '\0', MAXWIDTH);
666
/* Start assembling the row. */
667
for (x=1; x <= colCount; x++)
669
colName = dbcolname (dbProc, x);
670
colWidth = getColWidth (dbProc, x);
671
colNameLen = (int)strlen (colName);
673
/* If we need to pad, then pad. */
674
if (colNameLen < colWidth)
676
/* Create a string the same length as the col width. */
677
memset (temp, '\0', MAXWIDTH);
678
memset (temp, ' ', (colWidth-colNameLen));
681
sprintf (row, "%s %s%s", row, colName, temp);
686
sprintf (row, "%s %s", row, colName);
689
return (char *)strdup (row);
693
* This assembles a single row.
695
char *assembleRow (DBPROCESS *dbProcess)
698
int colCount = dbnumcols (dbProcess);
702
char value[MAXWIDTH];
708
/* Clean out the row. */
709
memset (row, '\0', MAXWIDTH);
711
/* Start assembling the row. */
712
for (x=1; x <= colCount; x++)
714
columnType = (int)dbcoltype (dbProcess, x);
715
colWidth = (int)getColWidth (dbProcess, x);
716
valueLen = (int)dbdatlen (dbProcess, x);
718
/* Check the column type. */
719
if (columnType == SYBINT1)
721
DBINT object_id = *((DBINT *)dbdata(dbProcess, x));
722
sprintf (format, "%%-%dd", colWidth);
723
sprintf (value, format, (int)object_id);
725
else if (columnType == SYBINT2)
727
DBINT object_id = *((DBINT *)dbdata(dbProcess, x));
728
sprintf (format, "%%-%dd", colWidth);
729
sprintf (value, format, (int)object_id);
731
else if (columnType == SYBINT4)
733
DBINT object_id = *((DBINT *)dbdata(dbProcess, x));
734
sprintf (format, "%%-%dd", colWidth);
735
sprintf (value, format, (int)object_id);
737
else if (columnType == SYBREAL)
739
DBREAL object_id = *((DBREAL *)dbdata(dbProcess, x));
740
sprintf (format, "%%-%d.2f", colWidth);
741
sprintf (value, format, object_id);
743
else if (columnType == SYBFLT8)
745
DBFLT8 object_id = *((DBFLT8 *)dbdata(dbProcess, x));
746
sprintf (format, "%%-%d.2f", colWidth);
747
sprintf (value, format, object_id);
757
memset (value, '\0', MAXWIDTH);
758
dataValue = (DBCHAR *)dbdata (dbProcess, x);
759
strncpy (value, dataValue, valueLen);
763
/* If we need to pad, then pad. */
764
if (valueLen < colWidth)
766
/* Copy the value into the string. */
767
memset (temp, '\0', MAXWIDTH);
768
memset (temp, ' ', (colWidth-valueLen));
769
sprintf (row, "%s %s%s", row, value, temp);
773
sprintf (row, "%s %s", row, value);
776
return copyChar (row);
780
* This function returns the correct width of a column, taking
781
* into account the width of the title, the width of the data
784
int getColWidth (DBPROCESS *dbProcess, int col)
786
char *colName = dbcolname (dbProcess, col);
787
int colNameLen = (int)strlen(colName);
788
int colWidth = dbcollen (dbProcess, col);
789
int columnType = (int)dbcoltype (dbProcess, col);
791
/* If the colType is int/real/float adjust accordingly. */
792
if (columnType == SYBINT1 || columnType == SYBINT2 ||
793
columnType == SYBINT4)
797
else if (columnType == SYBREAL || columnType == SYBFLT8)
802
/* Is the name of the column wider than the col width? */
803
if (colNameLen >= colWidth)
805
return (colNameLen+1);
811
* This callback allows the user to play with the scrolling window.
813
void viewHistoryCB (EObjectType cdktype, void *object, void *clientData, chtype key)
815
CDKSWINDOW *swindow = (CDKSWINDOW *)clientData;
816
CDKENTRY *entry = (CDKENTRY *)object;
818
/* Let them play... */
819
activateCDKSwindow (swindow, 0);
821
/* Redraw the entry field. */
822
drawCDKEntry (entry, ObjOf(entry)->box);
826
* This displays a little introduction screen.
828
void intro (CDKSCREEN *screen)
833
/* Create the message. */
835
mesg[lines++] = "<C></B/16>Sybase Command Interface";
836
mesg[lines++] = "<C>Written by Mike Glover";
838
mesg[lines++] = "<C>Type </B>help<!B> to get help.";
840
/* Display the message. */
841
popupLabel (screen, mesg, lines);
845
* This function displays help.
847
void help (CDKENTRY *entry)
852
/* Create the help message. */
853
mesg[lines++] = "<C></B/29>Help";
855
mesg[lines++] = "</B/24>When in the command line.";
856
mesg[lines++] = "<B=Up Arrow > Scrolls back one command.";
857
mesg[lines++] = "<B=Down Arrow> Scrolls forward one command.";
858
mesg[lines++] = "<B=Tab > Activates the scrolling window.";
859
mesg[lines++] = "<B=help > Displays this help window.";
861
mesg[lines++] = "</B/24>When in the scrolling window.";
862
mesg[lines++] = "<B=l or L > Loads a file into the window.";
863
mesg[lines++] = "<B=s or S > Saves the contents of the window to a file.";
864
mesg[lines++] = "<B=Up Arrow > Scrolls up one line.";
865
mesg[lines++] = "<B=Down Arrow> Scrolls down one line.";
866
mesg[lines++] = "<B=Page Up > Scrolls back one page.";
867
mesg[lines++] = "<B=Page Down > Scrolls forward one page.";
868
mesg[lines++] = "<B=Tab or Esc> Returns to the command line.";
869
mesg[lines++] = "<B=? > Displays this help window.";
871
mesg[lines++] = "<C> (</B/24>Refer to the scrolling window online manual for more help<!B!24>.)";
873
/* Pop up the help message. */
874
popupLabel (entry->screen, mesg, lines);
878
* This converts a word to upper case.
880
char *uc (char *word)
882
int length = strlen (word);
883
char *upper = (char *)malloc (sizeof (char *) * (length+2));
886
/* Start converting the case. */
887
for (x=0; x < length; x++)
889
if (isalpha ((int)word[x]))
891
upper[x] = toupper(word[x]);
898
upper[length] = '\0';
903
* The following two functions are the error and message handler callbacks.
904
* which will be called by Sybase when and error occurs.
906
int err_handler (DBPROCESS *dbProcess, DBINT mesgNumber, int mesgState, int severity, char *mesgText)
908
/* Declare local variables. */
909
char *mesg[10], temp[256];
912
/* Check if the process is dead. */
913
if ((dbProcess == 0) || (DBDEAD(dbProcess)))
915
mesg[0] = "</B/32>Database Process Error";
916
mesg[1] = "<C>The database process seems to have died.";
917
mesg[2] = "<C>Try logging in again with the </R>login<!R> command";
918
popupLabel (GPCdkScreen, mesg, 3);
923
mesg[0] = "</B/32>DB-Library Error";
924
sprintf (temp, "<C>%s", dberrstr);
925
mesg[1] = copyChar (temp);
929
/* Display the message if we have an error. */
932
popupLabel (GPCdkScreen, mesg, --errorCount);
942
int mesg_handler (DBPROCESS *dbProcess, DBINT mesgNumber, int mesgState, int severity, char *mesgText)
944
/* Declare local variables. */
945
char *mesg[10], temp[256];
947
/* Create the message. */
948
mesg[0] = "<C></B/16>SQL Server Message";
949
sprintf (temp, "</R>Message Number<!R> %ld", mesgNumber);
950
mesg[1] = copyChar (temp);
951
sprintf (temp, "</R>State <!R> %d", mesgState);
952
mesg[2] = copyChar (temp);
953
sprintf (temp, "</R>Severity <!R> %d", severity);
954
mesg[3] = copyChar (temp);
955
sprintf (temp, "</R>Message <!R> %s", mesgText);
956
mesg[4] = copyChar (temp);
957
popupLabel (GPCdkScreen, mesg, 5);
960
freeChar (mesg[1]); freeChar (mesg[2]);
961
freeChar (mesg[3]); freeChar (mesg[4]);
966
* This is for the scrolling window help callback.
968
void swindowHelpCB (EObjectType cdktype, void *object, void *clientData, chtype key)
970
CDKENTRY *entry = (CDKENTRY *)clientData;
975
* This is the callback for the down arrow.
977
void historyUpCB (EObjectType cdktype, void *object, void *clientData, chtype key)
979
CDKENTRY *entry = (CDKENTRY *)object;
980
struct history_st *history = (struct history_st *) clientData;
982
/* Make sure we don't go out of bounds. */
983
if (history->current == 0)
989
/* Decrement the counter. */
992
/* Display the command. */
993
setCDKEntryValue (entry, history->command[history->current]);
994
drawCDKEntry (entry, ObjOf(entry)->box);
998
* This is the callback for the down arrow.
1000
void historyDownCB (EObjectType cdktype, void *object, void *clientData, chtype key)
1002
CDKENTRY *entry = (CDKENTRY *)object;
1003
struct history_st *history = (struct history_st *) clientData;
1005
/* Make sure we don't go out of bounds. */
1006
if (history->current == history->count)
1012
/* Increment the counter... */
1015
/* If we are at the end, clear the entry field. */
1016
if (history->current == history->count)
1018
cleanCDKEntry (entry);
1019
drawCDKEntry (entry, ObjOf(entry)->box);
1023
/* Display the command. */
1024
setCDKEntryValue (entry, history->command[history->current]);
1025
drawCDKEntry (entry, ObjOf(entry)->box);
1029
* This callback allows the user to pick from the history list from a
1032
void listHistoryCB (EObjectType cdktype, void *object, void *clientData, chtype key)
1034
CDKSCROLL *scrollList = 0;
1035
CDKENTRY *entry = (CDKENTRY *)object;
1036
struct history_st *history = (struct history_st *) clientData;
1037
int height = (history->count < 10 ? history->count+3 : 13);
1040
/* No history, no list. */
1041
if (history->count == 0)
1043
/* Popup a little window telling the user there are no commands. */
1044
char *mesg[] = {"<C></B/16>No Commands Entered", "<C>No History"};
1045
popupLabel (entry->screen, mesg, 2);
1047
/* Redraw the screen. */
1048
eraseCDKEntry (ObjOf(entry));
1049
drawCDKScreen (entry->screen);
1055
/* Create the scrolling list of previous commands. */
1056
scrollList = newCDKScroll (entry->screen, CENTER, CENTER, RIGHT,
1057
height, -10, "<C></B/29>Command History",
1058
history->command, history->count,
1059
NUMBERS, A_REVERSE, TRUE, FALSE);
1061
/* Get the command to execute. */
1062
selection = activateCDKScroll (scrollList, 0);
1063
destroyCDKScroll (scrollList);
1065
/* Check the results of the selection. */
1068
/* Get the command and stick it back in the entry field. */
1069
setCDKEntryValue (entry, history->command[selection]);
1072
/* Redraw the screen. */
1073
eraseCDKEntry (ObjOf(entry));
1074
drawCDKScreen (ScreenOf(entry));
1078
* This loads the history into the editor from the RC file.
1080
void loadHistory (struct history_st *history)
1083
char filename[1000];
1085
/* Create the RC filename. */
1086
if ((home = getenv ("HOME")) == 0)
1090
sprintf (filename, "%s/.sybrc", home);
1092
/* Set some variables. */
1093
history->current = 0;
1096
/* Read the file. */
1097
if ((history->count = readFile (filename, history->command, MAXHISTORY)) != -1)
1099
history->current = history->count;
1105
* This saves the history into RC file.
1107
void saveHistory (struct history_st *history, int count)
1111
char filename[1000];
1114
/* Create the RC filename. */
1115
if ((home = getenv ("HOME")) == 0)
1119
sprintf (filename, "%s/.sybrc", home);
1121
/* Open the file for writing. */
1122
if ((fd = fopen (filename, "w")) == 0)
1127
/* Start saving the history. */
1128
for (x=0; x < history->count; x++)
1130
fprintf (fd, "%s\n", history->command[x]);