base/config/kconfig/mconf.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
00003  * Released under the terms of the GNU GPL v2.0.
00004  *
00005  * Introduced single menu mode (show all sub-menus in one large tree).
00006  * 2002-11-06 Petr Baudis <pasky@ucw.cz>
00007  */
00008 
00009 #include <sys/ioctl.h>
00010 #include <sys/wait.h>
00011 #include <ctype.h>
00012 #include <errno.h>
00013 #include <fcntl.h>
00014 #include <limits.h>
00015 #include <signal.h>
00016 #include <stdarg.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <termios.h>
00020 #include <unistd.h>
00021 
00022 #define LKC_DIRECT_LINK
00023 #include "lkc.h"
00024 
00025 static char menu_backtitle[128];
00026 static const char menu_instructions[] =
00027     "Arrow keys navigate the menu.  "
00028     "<Enter> selects submenus --->.  "
00029     "Highlighted letters are hotkeys.  "
00030     "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
00031     "Press <Esc><Esc> to exit, <?> for Help.  "
00032     "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
00033 radiolist_instructions[] =
00034     "Use the arrow keys to navigate this window or "
00035     "press the hotkey of the item you wish to select "
00036     "followed by the <SPACE BAR>. "
00037     "Press <?> for additional information about this option.",
00038 inputbox_instructions_int[] =
00039     "Please enter a decimal value. "
00040     "Fractions will not be accepted.  "
00041     "Use the <TAB> key to move from the input field to the buttons below it.",
00042 inputbox_instructions_hex[] =
00043     "Please enter a hexadecimal value. "
00044     "Use the <TAB> key to move from the input field to the buttons below it.",
00045 inputbox_instructions_string[] =
00046     "Please enter a string value. "
00047     "Use the <TAB> key to move from the input field to the buttons below it.",
00048 setmod_text[] =
00049     "This feature depends on another which has been configured as a module.\n"
00050     "As a result, this feature will be built as a module.",
00051 nohelp_text[] =
00052     "There is no help available for this RTAI option.\n",
00053 load_config_text[] =
00054     "Enter the name of the configuration file you wish to load.  "
00055     "Accept the name shown to restore the configuration you "
00056     "last retrieved.  Leave blank to abort.",
00057 load_config_help[] =
00058     "\n"
00059     "For various reasons, one may wish to keep several different RTAI\n"
00060     "configurations available on a single machine.\n"
00061     "\n"
00062     "If you have saved a previous configuration in a file other than\n"
00063     "RTAI's default, entering the name of the file here will allow you\n"
00064     "to modify that configuration.\n"
00065     "\n"
00066     "If you are uncertain, then you have probably never used alternate\n"
00067     "configuration files.  You should therefor leave this blank to abort.\n",
00068 save_config_text[] =
00069     "Enter a filename to which this configuration should be saved "
00070     "as an alternate.  Leave blank to abort.",
00071 save_config_help[] =
00072     "\n"
00073     "For various reasons, one may wish to keep different RTAI\n"
00074     "configurations available on a single machine.\n"
00075     "\n"
00076     "Entering a file name here will allow you to later retrieve, modify\n"
00077     "and use the current configuration as an alternate to whatever\n"
00078     "configuration options you have selected at that time.\n"
00079     "\n"
00080     "If you are uncertain what all this means then you should probably\n"
00081     "leave this blank.\n"
00082 ;
00083 
00084 static char buf[4096], *bufptr = buf;
00085 static char input_buf[4096];
00086 static char filename[PATH_MAX+1] = ".config";
00087 static char *args[1024], **argptr = args;
00088 static int indent = 0;
00089 static struct termios ios_org;
00090 static int rows, cols;
00091 static struct menu *curr_menu;
00092 static int child_count;
00093 static int do_resize;
00094 static int single_menu_mode;
00095 
00096 static void conf(struct menu *menu);
00097 static void conf_choice(struct menu *menu);
00098 static void conf_string(struct menu *menu);
00099 static void conf_load(void);
00100 static void conf_save(void);
00101 static void show_textbox(const char *title, const char *text, int r, int c);
00102 static void show_helptext(const char *title, const char *text);
00103 static void show_help(struct menu *menu);
00104 static void show_readme(void);
00105 
00106 static void cprint_init(void);
00107 static int cprint1(const char *fmt, ...);
00108 static void cprint_done(void);
00109 static int cprint(const char *fmt, ...);
00110 
00111 static void init_wsize(void)
00112 {
00113     struct winsize ws;
00114     char *env;
00115 
00116     if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
00117         rows = 24;
00118         cols = 80;
00119     } else {
00120         rows = ws.ws_row;
00121         cols = ws.ws_col;
00122         if (!rows) {
00123             env = getenv("LINES");
00124             if (env)
00125                 rows = atoi(env);
00126             if (!rows)
00127                 rows = 24;
00128         }
00129         if (!cols) {
00130             env = getenv("COLUMNS");
00131             if (env)
00132                 cols = atoi(env);
00133             if (!cols)
00134                 cols = 80;
00135         }
00136     }
00137 
00138     if (rows < 19 || cols < 80) {
00139         fprintf(stderr, "Your display is too small to run Menuconfig!\n");
00140         fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
00141         exit(1);
00142     }
00143 
00144     rows -= 4;
00145     cols -= 5;
00146 }
00147 
00148 static void cprint_init(void)
00149 {
00150     bufptr = buf;
00151     argptr = args;
00152     memset(args, 0, sizeof(args));
00153     indent = 0;
00154     child_count = 0;
00155     cprint("./lxdialog/lxdialog");
00156     cprint("--backtitle");
00157     cprint(menu_backtitle);
00158 }
00159 
00160 static int cprint1(const char *fmt, ...)
00161 {
00162     va_list ap;
00163     int res;
00164 
00165     if (!*argptr)
00166         *argptr = bufptr;
00167     va_start(ap, fmt);
00168     res = vsprintf(bufptr, fmt, ap);
00169     va_end(ap);
00170     bufptr += res;
00171 
00172     return res;
00173 }
00174 
00175 static void cprint_done(void)
00176 {
00177     *bufptr++ = 0;
00178     argptr++;
00179 }
00180 
00181 static int cprint(const char *fmt, ...)
00182 {
00183     va_list ap;
00184     int res;
00185 
00186     *argptr++ = bufptr;
00187     va_start(ap, fmt);
00188     res = vsprintf(bufptr, fmt, ap);
00189     va_end(ap);
00190     bufptr += res;
00191     *bufptr++ = 0;
00192 
00193     return res;
00194 }
00195 
00196 pid_t pid;
00197 
00198 static void winch_handler(int sig)
00199 {
00200     if (!do_resize) {
00201         kill(pid, SIGINT);
00202         do_resize = 1;
00203     }
00204 }
00205 
00206 static int exec_conf(void)
00207 {
00208     int pipefd[2], stat, size;
00209     struct sigaction sa;
00210     sigset_t sset, osset;
00211 
00212     sigemptyset(&sset);
00213     sigaddset(&sset, SIGINT);
00214     sigprocmask(SIG_BLOCK, &sset, &osset);
00215 
00216     signal(SIGINT, SIG_DFL);
00217 
00218     sa.sa_handler = winch_handler;
00219     sigemptyset(&sa.sa_mask);
00220     sa.sa_flags = SA_RESTART;
00221     sigaction(SIGWINCH, &sa, NULL);
00222 
00223     *argptr++ = NULL;
00224 
00225     pipe(pipefd);
00226     pid = fork();
00227     if (pid == 0) {
00228         sigprocmask(SIG_SETMASK, &osset, NULL);
00229         dup2(pipefd[1], 2);
00230         close(pipefd[0]);
00231         close(pipefd[1]);
00232         execv(args[0], args);
00233         _exit(EXIT_FAILURE);
00234     }
00235 
00236     close(pipefd[1]);
00237     bufptr = input_buf;
00238     while (1) {
00239         size = input_buf + sizeof(input_buf) - bufptr;
00240         size = read(pipefd[0], bufptr, size);
00241         if (size <= 0) {
00242             if (size < 0) {
00243                 if (errno == EINTR || errno == EAGAIN)
00244                     continue;
00245                 perror("read");
00246             }
00247             break;
00248         }
00249         bufptr += size;
00250     }
00251     *bufptr++ = 0;
00252     close(pipefd[0]);
00253     waitpid(pid, &stat, 0);
00254 
00255     if (do_resize) {
00256         init_wsize();
00257         do_resize = 0;
00258         sigprocmask(SIG_SETMASK, &osset, NULL);
00259         return -1;
00260     }
00261     if (WIFSIGNALED(stat)) {
00262         printf("\finterrupted(%d)\n", WTERMSIG(stat));
00263         exit(1);
00264     }
00265 #if 0
00266     printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
00267     sleep(1);
00268 #endif
00269     sigpending(&sset);
00270     if (sigismember(&sset, SIGINT)) {
00271         printf("\finterrupted\n");
00272         exit(1);
00273     }
00274     sigprocmask(SIG_SETMASK, &osset, NULL);
00275 
00276     return WEXITSTATUS(stat);
00277 }
00278 
00279 static void build_conf(struct menu *menu)
00280 {
00281     struct symbol *sym;
00282     struct property *prop;
00283     struct menu *child;
00284     int type, tmp, doint = 2;
00285     tristate val;
00286     char ch;
00287 
00288     if (!menu_is_visible(menu))
00289         return;
00290 
00291     sym = menu->sym;
00292     prop = menu->prompt;
00293     if (!sym) {
00294         if (prop && menu != curr_menu) {
00295             const char *prompt = menu_get_prompt(menu);
00296             switch (prop->type) {
00297             case P_MENU:
00298                 child_count++;
00299                 cprint("m%p", menu);
00300 
00301                 if (single_menu_mode) {
00302                     cprint1("%s%*c%s",
00303                         menu->data ? "-->" : "++>",
00304                         indent + 1, ' ', prompt);
00305                 } else
00306                     cprint1("   %*c%s  --->", indent + 1, ' ', prompt);
00307 
00308                 cprint_done();
00309                 if (single_menu_mode && menu->data)
00310                     goto conf_childs;
00311                 return;
00312             default:
00313                 if (prompt) {
00314                     child_count++;
00315                     cprint(":%p", menu);
00316                     cprint("---%*c%s", indent + 1, ' ', prompt);
00317                 }
00318             }
00319         } else
00320             doint = 0;
00321         goto conf_childs;
00322     }
00323 
00324     type = sym_get_type(sym);
00325     if (sym_is_choice(sym)) {
00326         struct symbol *def_sym = sym_get_choice_value(sym);
00327         struct menu *def_menu = NULL;
00328 
00329         child_count++;
00330         for (child = menu->list; child; child = child->next) {
00331             if (menu_is_visible(child) && child->sym == def_sym)
00332                 def_menu = child;
00333         }
00334 
00335         val = sym_get_tristate_value(sym);
00336         if (sym_is_changable(sym)) {
00337             cprint("t%p", menu);
00338             switch (type) {
00339             case S_BOOLEAN:
00340                 cprint1("[%c]", val == no ? ' ' : '*');
00341                 break;
00342             case S_TRISTATE:
00343                 switch (val) {
00344                 case yes: ch = '*'; break;
00345                 case mod: ch = 'M'; break;
00346                 default:  ch = ' '; break;
00347                 }
00348                 cprint1("<%c>", ch);
00349                 break;
00350             }
00351         } else {
00352             cprint("%c%p", def_menu ? 't' : ':', menu);
00353             cprint1("   ");
00354         }
00355 
00356         cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
00357         if (val == yes) {
00358             if (def_menu) {
00359                 cprint1(" (%s)", menu_get_prompt(def_menu));
00360                 cprint1("  --->");
00361                 cprint_done();
00362                 if (def_menu->list) {
00363                     indent += 2;
00364                     build_conf(def_menu);
00365                     indent -= 2;
00366                 }
00367             } else
00368                 cprint_done();
00369             return;
00370         }
00371         cprint_done();
00372     } else {
00373         if (menu == curr_menu) {
00374             cprint(":%p", menu);
00375             cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
00376             goto conf_childs;
00377         }
00378         child_count++;
00379         val = sym_get_tristate_value(sym);
00380         if (sym_is_choice_value(sym) && val == yes) {
00381             cprint(":%p", menu);
00382             cprint1("   ");
00383         } else {
00384             switch (type) {
00385             case S_BOOLEAN:
00386                 cprint("t%p", menu);
00387                 if (sym_is_changable(sym))
00388                     cprint1("[%c]", val == no ? ' ' : '*');
00389                 else
00390                     cprint1("---");
00391                 break;
00392             case S_TRISTATE:
00393                 cprint("t%p", menu);
00394                 switch (val) {
00395                 case yes: ch = '*'; break;
00396                 case mod: ch = 'M'; break;
00397                 default:  ch = ' '; break;
00398                 }
00399                 if (sym_is_changable(sym))
00400                     cprint1("<%c>", ch);
00401                 else
00402                     cprint1("---");
00403                 break;
00404             default:
00405                 cprint("s%p", menu);
00406                 tmp = cprint1("(%s)", sym_get_string_value(sym));
00407                 tmp = indent - tmp + 4;
00408                 if (tmp < 0)
00409                     tmp = 0;
00410                 cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
00411                     (sym_has_value(sym) || !sym_is_changable(sym)) ?
00412                     "" : " (NEW)");
00413                 cprint_done();
00414                 goto conf_childs;
00415             }
00416         }
00417         cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
00418             (sym_has_value(sym) || !sym_is_changable(sym)) ?
00419             "" : " (NEW)");
00420         if (menu->prompt->type == P_MENU) {
00421             cprint1("  --->");
00422             cprint_done();
00423             return;
00424         }
00425         cprint_done();
00426     }
00427 
00428 conf_childs:
00429     indent += doint;
00430     for (child = menu->list; child; child = child->next)
00431         build_conf(child);
00432     indent -= doint;
00433 }
00434 
00435 static void conf(struct menu *menu)
00436 {
00437     struct menu *submenu;
00438     const char *prompt = menu_get_prompt(menu);
00439     struct symbol *sym;
00440     char active_entry[40];
00441     int stat, type, i;
00442 
00443     unlink("lxdialog.scrltmp");
00444     active_entry[0] = 0;
00445     while (1) {
00446         cprint_init();
00447         cprint("--title");
00448         cprint("%s", prompt ? prompt : "Main Menu");
00449         cprint("--menu");
00450         cprint(menu_instructions);
00451         cprint("%d", rows);
00452         cprint("%d", cols);
00453         cprint("%d", rows - 10);
00454         cprint("%s", active_entry);
00455         curr_menu = menu;
00456         build_conf(menu);
00457         if (!child_count)
00458             break;
00459         if (menu == &rootmenu) {
00460             cprint(":");
00461             cprint("--- ");
00462             cprint("L");
00463             cprint("    Load an Alternate Configuration File");
00464             cprint("S");
00465             cprint("    Save Configuration to an Alternate File");
00466         }
00467         stat = exec_conf();
00468         if (stat < 0)
00469             continue;
00470 
00471         if (stat == 1 || stat == 255)
00472             break;
00473 
00474         type = input_buf[0];
00475         if (!type)
00476             continue;
00477 
00478         for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
00479             ;
00480         if (i >= sizeof(active_entry))
00481             i = sizeof(active_entry) - 1;
00482         input_buf[i] = 0;
00483         strcpy(active_entry, input_buf);
00484 
00485         sym = NULL;
00486         submenu = NULL;
00487         if (sscanf(input_buf + 1, "%p", &submenu) == 1)
00488             sym = submenu->sym;
00489 
00490         switch (stat) {
00491         case 0:
00492             switch (type) {
00493             case 'm':
00494                 if (single_menu_mode)
00495                     submenu->data = (void *) (long) !submenu->data;
00496                 else
00497                     conf(submenu);
00498                 break;
00499             case 't':
00500                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
00501                     conf_choice(submenu);
00502                 else if (submenu->prompt->type == P_MENU)
00503                     conf(submenu);
00504                 break;
00505             case 's':
00506                 conf_string(submenu);
00507                 break;
00508             case 'L':
00509                 conf_load();
00510                 break;
00511             case 'S':
00512                 conf_save();
00513                 break;
00514             }
00515             break;
00516         case 2:
00517             if (sym)
00518                 show_help(submenu);
00519             else
00520                 show_readme();
00521             break;
00522         case 3:
00523             if (type == 't') {
00524                 if (sym_set_tristate_value(sym, yes))
00525                     break;
00526                 if (sym_set_tristate_value(sym, mod))
00527                     show_textbox(NULL, setmod_text, 6, 74);
00528             }
00529             break;
00530         case 4:
00531             if (type == 't')
00532                 sym_set_tristate_value(sym, no);
00533             break;
00534         case 5:
00535             if (type == 't')
00536                 sym_set_tristate_value(sym, mod);
00537             break;
00538         case 6:
00539             if (type == 't')
00540                 sym_toggle_tristate_value(sym);
00541             else if (type == 'm')
00542                 conf(submenu);
00543             break;
00544         }
00545     }
00546 }
00547 
00548 static void show_textbox(const char *title, const char *text, int r, int c)
00549 {
00550     int fd;
00551 
00552     fd = creat(".help.tmp", 0777);
00553     write(fd, text, strlen(text));
00554     close(fd);
00555     do {
00556         cprint_init();
00557         if (title) {
00558             cprint("--title");
00559             cprint("%s", title);
00560         }
00561         cprint("--textbox");
00562         cprint(".help.tmp");
00563         cprint("%d", r);
00564         cprint("%d", c);
00565     } while (exec_conf() < 0);
00566     unlink(".help.tmp");
00567 }
00568 
00569 static void show_helptext(const char *title, const char *text)
00570 {
00571     show_textbox(title, text, rows, cols);
00572 }
00573 
00574 static void show_help(struct menu *menu)
00575 {
00576     const char *help;
00577     char *helptext;
00578     struct symbol *sym = menu->sym;
00579 
00580     help = sym->help;
00581     if (!help)
00582         help = nohelp_text;
00583     if (sym->name) {
00584         helptext = malloc(strlen(sym->name) + strlen(help) + 16);
00585         sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help);
00586         show_helptext(menu_get_prompt(menu), helptext);
00587         free(helptext);
00588     } else
00589         show_helptext(menu_get_prompt(menu), help);
00590 }
00591 
00592 static void show_readme(void)
00593 {
00594     do {
00595         cprint_init();
00596         cprint("--textbox");
00597         cprint("scripts/README.Menuconfig");
00598         cprint("%d", rows);
00599         cprint("%d", cols);
00600     } while (exec_conf() == -1);
00601 }
00602 
00603 static void conf_choice(struct menu *menu)
00604 {
00605     const char *prompt = menu_get_prompt(menu);
00606     struct menu *child;
00607     struct symbol *active;
00608     int stat;
00609 
00610     while (1) {
00611         cprint_init();
00612         cprint("--title");
00613         cprint("%s", prompt ? prompt : "Main Menu");
00614         cprint("--radiolist");
00615         cprint(radiolist_instructions);
00616         cprint("15");
00617         cprint("70");
00618         cprint("6");
00619 
00620         curr_menu = menu;
00621         active = sym_get_choice_value(menu->sym);
00622         for (child = menu->list; child; child = child->next) {
00623             if (!menu_is_visible(child))
00624                 continue;
00625             cprint("%p", child);
00626             cprint("%s", menu_get_prompt(child));
00627             cprint(child->sym == active ? "ON" : "OFF");
00628         }
00629 
00630         stat = exec_conf();
00631         switch (stat) {
00632         case 0:
00633             if (sscanf(input_buf, "%p", &menu) != 1)
00634                 break;
00635             sym_set_tristate_value(menu->sym, yes);
00636             return;
00637         case 1:
00638             show_help(menu);
00639             break;
00640         case 255:
00641             return;
00642         }
00643     }
00644 }
00645 
00646 static void conf_string(struct menu *menu)
00647 {
00648     const char *prompt = menu_get_prompt(menu);
00649     int stat;
00650 
00651     while (1) {
00652         cprint_init();
00653         cprint("--title");
00654         cprint("%s", prompt ? prompt : "Main Menu");
00655         cprint("--inputbox");
00656         switch (sym_get_type(menu->sym)) {
00657         case S_INT:
00658             cprint(inputbox_instructions_int);
00659             break;
00660         case S_HEX:
00661             cprint(inputbox_instructions_hex);
00662             break;
00663         case S_STRING:
00664             cprint(inputbox_instructions_string);
00665             break;
00666         default:
00667             /* panic? */;
00668         }
00669         cprint("10");
00670         cprint("75");
00671         cprint("%s", sym_get_string_value(menu->sym));
00672         stat = exec_conf();
00673         switch (stat) {
00674         case 0:
00675             if (sym_set_string_value(menu->sym, input_buf))
00676                 return;
00677             show_textbox(NULL, "You have made an invalid entry.", 5, 43);
00678             break;
00679         case 1:
00680             show_help(menu);
00681             break;
00682         case 255:
00683             return;
00684         }
00685     }
00686 }
00687 
00688 static void conf_load(void)
00689 {
00690     int stat;
00691 
00692     while (1) {
00693         cprint_init();
00694         cprint("--inputbox");
00695         cprint(load_config_text);
00696         cprint("11");
00697         cprint("55");
00698         cprint("%s", filename);
00699         stat = exec_conf();
00700         switch(stat) {
00701         case 0:
00702             if (!input_buf[0])
00703                 return;
00704             if (!conf_read(input_buf))
00705                 return;
00706             show_textbox(NULL, "File does not exist!", 5, 38);
00707             break;
00708         case 1:
00709             show_helptext("Load Alternate Configuration", load_config_help);
00710             break;
00711         case 255:
00712             return;
00713         }
00714     }
00715 }
00716 
00717 static void conf_save(void)
00718 {
00719     int stat;
00720 
00721     while (1) {
00722         cprint_init();
00723         cprint("--inputbox");
00724         cprint(save_config_text);
00725         cprint("11");
00726         cprint("55");
00727         cprint("%s", filename);
00728         stat = exec_conf();
00729         switch(stat) {
00730         case 0:
00731             if (!input_buf[0])
00732                 return;
00733             if (!conf_write(input_buf))
00734                 return;
00735             show_textbox(NULL, "Can't create file!  Probably a nonexistent directory.", 5, 60);
00736             break;
00737         case 1:
00738             show_helptext("Save Alternate Configuration", save_config_help);
00739             break;
00740         case 255:
00741             return;
00742         }
00743     }
00744 }
00745 
00746 static void conf_cleanup(void)
00747 {
00748     tcsetattr(1, TCSAFLUSH, &ios_org);
00749     unlink(".help.tmp");
00750     unlink("lxdialog.scrltmp");
00751 }
00752 
00753 int main(int ac, char **av)
00754 {
00755     struct symbol *sym;
00756     char *mode;
00757     int stat;
00758 
00759     conf_parse(av[1]);
00760     conf_read(NULL);
00761 
00762     sym = sym_lookup("RTAI_VERSION", 0);
00763     sym_calc_value(sym);
00764     sprintf(menu_backtitle, "RTAI %s Configuration",
00765         sym_get_string_value(sym));
00766 
00767     mode = getenv("MENUCONFIG_MODE");
00768     if (mode) {
00769         if (!strcasecmp(mode, "single_menu"))
00770             single_menu_mode = 1;
00771     }
00772 
00773     tcgetattr(1, &ios_org);
00774     atexit(conf_cleanup);
00775     init_wsize();
00776     conf(&rootmenu);
00777 
00778     do {
00779         cprint_init();
00780         cprint("--yesno");
00781         cprint("Do you wish to save your new configuration?");
00782         cprint("5");
00783         cprint("60");
00784         stat = exec_conf();
00785     } while (stat < 0);
00786 
00787     if (stat == 0) {
00788         conf_write(NULL);
00789     } else
00790         printf("\n\nYour RTAI configuration changes were NOT saved.\n\n");
00791 
00792     return 0;
00793 }

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7