Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

ireadln.cpp

Go to the documentation of this file.
00001 // +-------------------------------------------------------------------------+
00002 // |               I__n__t__e__L__i__b           0.6.10 development          |
00003 // | Copyright (c) Andrey Vikt. Stolyarov <crocodil_AT_croco.net> 2000-2007. |
00004 // |                                                                         |
00005 // | This is free software. The library part is available under              |
00006 // |                               GNU LESSER GENERAL PUBLIC LICENSE v.2.1.  |
00007 // | GNU LGPL v2.1 is found in docs/gnu_gpl2.txt,  or at  http://www.gnu.org |
00008 // |     Please see also docs/readme.txt and visit http://www.intelib.org    |
00009 // |                                                                         |
00010 // | !!! THERE IS NO WARRANTY OF ANY KIND, NEITHER EXPRESSED NOR IMPLIED !!! |
00011 // +-------------------------------------------------------------------------+
00012 
00013 
00014 
00015 
00016 #include <stdlib.h> // for free()
00017 #include "../sexpress/sexpress.hpp"
00018 #include "../tools/sreader.hpp"
00019 #include "../tools/sstream.hpp"
00020 
00021 #ifndef INTELIB_USE_READLINE 
00022 #define INTELIB_USE_READLINE 1
00023 #endif
00024 
00025 #if INTELIB_USE_READLINE == 1
00026 #include <readline/readline.h>
00027 #include <readline/history.h>
00028 #include <string.h>
00029 #include <signal.h>
00030 #include <setjmp.h>
00031 
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <unistd.h>
00035 
00036 #include "../sexpress/shashtbl.hpp"
00037 #endif
00038 
00039 static SReference plain_read(const SStreamRef &in,
00040                              const SStreamRef &out,
00041                              const SStreamRef &err,
00042                              IntelibGenericReader &reader,
00043                              const SString &prompt)
00044 {
00045     char buf[512];
00046     out->Puts("> ");
00047     do {
00048         buf[sizeof(buf)-2] = 0;
00049         if(0 == in->Gets(buf, sizeof(buf))) {
00050             reader.FeedEof();
00051         } else {
00052             if(buf[sizeof(buf)-2]!=0 && buf[sizeof(buf)-2]!='\n') {
00053                 err->Puts("#* input line too long\n");
00054                 int c;
00055                 do {
00056                     c = in->Getc();
00057                 } while (c!=EOF && c!='\n');
00058                 continue;
00059             }
00060             reader.FeedString(buf);
00061         }
00062     } while(!reader.IsReady());
00063     return reader.Get();
00064 }
00065 
00066 #if INTELIB_USE_READLINE == 1
00067 
00068 static sigjmp_buf backtoloop;
00069 static void (*savesig)(int);
00070  
00071 static void inth(int a) {
00072     signal(SIGINT, savesig);
00073     rl_cleanup_after_signal();
00074     rl_free_line_state();
00075     siglongjmp(backtoloop, 1);
00076 }
00077 
00078 static bool emptyline(const char *line)
00079 {
00080     while(*line) {
00081         if(!isspace(*line)) return false;
00082         line++;
00083     }
00084     return true;
00085 }
00086 
00087 
00088 static SExpressionHashTable *epack = 0;
00089 
00090 static bool is_dirname(const char *fname)
00091 {
00092     struct stat s;
00093     if(-1 == stat(fname, &s)) return false;
00094     return S_ISDIR(s.st_mode);
00095 }
00096 
00097 static char *macro_char_generator(const char *text, int seq)
00098 {
00099     if(text[1] == '\0') {
00100         static int st;
00101         if(seq==0) st = 0;
00102         switch(st++) {
00103             case 0: return strdup("#\\");
00104             case 1: return strdup("#'");
00105             default: return 0;
00106         }
00107     }
00108     if(text[1] != '\\') return 0;
00109 
00110     static int state, len; 
00111     if(seq == 0) {
00112         state = 0;
00113         len = strlen(text);
00114     }
00115 
00116     static const char *names[] = { 
00117         "#\\Newline", "#\\Space", "#\\Tab", "#\\Backspace", "#\\Linefeed",
00118         "#\\Page", "#\\Return", "#\\Rubout", 0 
00119     };
00120 
00121     if(state>=0) {
00122         while(names[state]) {
00123             if(strncasecmp(names[state], text, len) == 0)
00124                 return strdup(names[state++]);
00125             state++;
00126         }
00127         // no more names, try chars...
00128         state = -1;
00129     }
00130 
00131     if(text[2] != '\0' && text[3] != '\0') return 0;
00132 
00133     while(state > -256) {
00134         if(isgraph(-state) && (text[2]==(char)(-state) || text[2]=='\0')) {
00135             char *res = (char*) malloc(4);
00136             res[0] = '#'; res[1] = '\\'; res[2] = -state; res[3] = '\0';
00137             state--;
00138             return res;
00139         }
00140         state--;
00141     }
00142     return 0;
00143 }
00144 
00145 static char *generator(const char *text, int seq)
00146 {
00147     if(text[0] == '"') {
00148         rl_filename_completion_desired = 1;
00149         char *fname = rl_filename_completion_function(text+1, seq);
00150         if(!fname) return 0;
00151         char *res = (char*) malloc(strlen(fname) + 3); 
00152             /* 3 is for leading dquote, trailing slash and term. zero */
00153         res[0] = '"';
00154         strcpy(res+1, fname);
00155         if(is_dirname(fname)) {
00156             strcat(res+1, "/");
00157         } else {
00158             strcat(res+1, "\"");
00159         }
00160         rl_completion_suppress_append = 1;
00161         free(fname);
00162         rl_filename_completion_desired = 1;
00163         return res;
00164     }
00165 
00166     if(text[0] == '#') {
00167         return macro_char_generator(text, seq);
00168     }
00169 
00170     static int state, len; 
00171     static SReference list;
00172     if(seq == 0) {
00173         state = 0;
00174         len = strlen(text);
00175 
00176         list = *PTheEmptyList;
00177         if(epack) {
00178             SExpressionHashTable::Iterator iter(*epack);
00179             SReference r = iter.GetNext();
00180             while(r.GetPtr()) {
00181                 const char *s = r.Car().GetString();
00182                 if(strncasecmp(s, text, len) == 0) 
00183                     list,s; 
00184                 r = iter.GetNext();
00185             }
00186         }
00187     }
00188 
00189     if(list.IsEmptyList()) 
00190         return 0;
00191     else {
00192         char *res = strdup(list.Car().GetString());
00193         list = list.Cdr();
00194         strncpy(res, text, len);
00195         bool to_lower = false;
00196         for(int i=0; i<len; i++)
00197             if(isalpha(text[i])) to_lower = islower(text[i]);
00198         if(to_lower)
00199             for(int i=len; res[i]; i++) res[i] = tolower(res[i]);
00200         return res;
00201     }
00202 }
00203 
00204 static SReference do_readline(IntelibGenericReader &reader,
00205                               const SReference& pkg,
00206                               const SString &prompt)
00207 {
00208     static bool init = false;
00209     if(!init) {
00210         init = true;
00211         rl_readline_name = "NILL";
00212         rl_completion_entry_function = generator;
00213         rl_basic_word_break_characters = " \n\t()';";
00214         rl_basic_quote_characters = "";
00215         //rl_special_prefixes = "\"";
00216     }
00217     epack = pkg.DynamicCastGetPtr<SExpressionHashTable>();
00218 
00219     char *line;
00220 
00221     for(;;) { /* to allow cancelling by pressing Ctrl-C and empty strings */
00222         if(0 == sigsetjmp(backtoloop, 1)) {
00223             savesig = signal(SIGINT, inth);
00224             line = readline(prompt.c_str());
00225             signal(SIGINT, savesig);
00226             SString hist_line("");
00227             if(line && emptyline(line)) {
00228                 free(line);
00229                 continue;
00230             }
00231             for(;;) {
00232                 if(!line) {
00233                     reader.FeedEof();
00234                 } else {
00235                     if(hist_line!="") hist_line += " ";
00236                     hist_line += line;
00237                     reader.FeedString(line);
00238                     reader.FeedChar('\n');
00239                     free(line);
00240                 }
00241                 if(reader.IsReady()) {
00242                     add_history(hist_line.c_str());
00243                     return reader.Get();
00244                 }
00245                 savesig = signal(SIGINT, inth);
00246                 line = readline("> ");
00247                 signal(SIGINT, savesig);
00248             }
00249         } else {
00250             reader.Drop();
00251             printf("\n");
00252         }
00253     }
00254 } 
00255 #endif
00256 
00257 
00258 SReference intelib_read_line(const SStreamRef &in,
00259                              const SStreamRef &out,
00260                              const SStreamRef &err,
00261                              IntelibGenericReader &reader,
00262                              const SReference &package,
00263                              const SString &prompt)
00264 {
00265 #if INTELIB_USE_READLINE == 1
00266     if(in->Fileno() == 0 && out->Fileno() == 1) {
00267         return do_readline(reader, package, prompt);
00268     } else {
00269         return plain_read(in, out, err, reader, prompt);
00270     }
00271 #else
00272     return plain_read(in, out, err, reader, prompt);
00273 #endif
00274 }

Generated on Tue Dec 18 00:39:43 2007 for InteLib by  doxygen 1.4.1