// // aegis - project change supervisor // Copyright (C) 2003-2008 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #include #include #include #include #include #include #include #include struct shell_zsh_ty { shell_ty inherited; string_ty *command; string_ty *prefix; }; static char * copy_of(const char *s, size_t len) { char *result = new char [len + 1]; memcpy(result, s, len); result[len] = 0; return result; } static void destructor(shell_ty *sp) { shell_zsh_ty *this_thing; this_thing = (shell_zsh_ty *)sp; if (this_thing->command) str_free(this_thing->command); if (this_thing->prefix) str_free(this_thing->prefix); } static void usage(void) { const char *prog; prog = progname_get(); fprintf(stderr, "Usage: %s \n", prog); exit(1); } static int test(shell_ty *sp) { shell_zsh_ty *this_thing; char *cp; char *end; unsigned long n; char *comp_line; unsigned long comp_point; size_t ac; size_t ac_max; char **av; int inco_ac; this_thing = (shell_zsh_ty *)sp; // // The PREFIX environment variable must be set and valid. // cp = getenv("PREFIX"); if (!cp) return 0; this_thing->prefix = str_from_c(cp); // // The BUFFER environment variable must be set and valid. // comp_line = getenv("BUFFER"); if (!comp_line || !*comp_line) return 0; // // The CURSOR environment variable must be set and valid. // cp = getenv("CURSOR"); if (!cp) return 0; n = strtoul(cp, &end, 10); if (end == cp || *end) return 0; comp_point = n; if (comp_point > strlen(comp_line)) return 0; // // There should be at least one command line argument, // the name of the command being completed // if (arglex_get_string() != arglex_token_string) usage(); this_thing->command = str_from_c(arglex_value.alv_string); // // Ignore the rest of the command line arguments. // while (arglex_get_string() == arglex_token_string) ; if (arglex_token != arglex_token_eoln) usage(); // // Generate the new command line, by splitting the comp_line string // into words. // ac = 0; ac_max = 0; av = 0; inco_ac = -1; for (cp = comp_line; ; ) { // // If the completion point is in the middle of white space, // or at the start of another word, insert an empty argument to // serve as the imcomplete argument in need of attention. // if ((unsigned long)(cp - comp_line) == comp_point) { // // insert the empty string as the incomplete argument. // if (ac >= ac_max) { ac_max = ac_max * 2 + 8; char **new_av = new char * [ac_max]; for (size_t k = 0; k < ac; ++k) new_av[k] = av[k]; delete [] av; av = new_av; } inco_ac = ac; av[ac++] = copy_of(cp, 0); comp_point = ~0uL; } // // end of the line // if (!*cp) { break; } // // Skip white space around words. // if (isspace((unsigned char)*cp)) { ++cp; continue; } // // Collect one word. // // Note that the completion point also terminates the word, // even if there is no white space present. // end = cp; while ( *end && !isspace((unsigned char)*end) && end != comp_line + comp_point ) { ++end; } // // Insert word into the list. // if (ac >= ac_max) { ac_max = ac_max * 2 + 8; char **new_av = new char * [ac_max]; for (size_t k = 0; k < ac; ++k) new_av[k] = av[k]; delete [] av; av = new_av; } if ((unsigned long)(cp - comp_line) < comp_point && comp_point <= (unsigned long)(end - comp_line)) { inco_ac = ac; comp_point = ~0uL; } av[ac++] = copy_of(cp, end - cp); // // Move past the word. // cp = end; } assert(inco_ac >= 0); // // NULL terminate the list of word pointers. // if (ac >= ac_max) { ac_max = ac_max * 2 + 8; char **new_av = new char * [ac_max]; for (size_t k = 0; k < ac; ++k) new_av[k] = av[k]; delete [] av; av = new_av; } av[ac] = 0; // // Insert our fake command line into the command line processor. // arglex_synthetic(ac, av, inco_ac); // // Report success. // return 1; } static string_ty * command_get(shell_ty *sh) { shell_zsh_ty *this_thing; this_thing = (shell_zsh_ty *)sh; return this_thing->command; } static string_ty * prefix_get(shell_ty *sh) { shell_zsh_ty *this_thing; this_thing = (shell_zsh_ty *)sh; return this_thing->prefix; } static void emit(shell_ty *, string_ty *s) { char *cp; for (cp = s->str_text; *cp; ++cp) { switch (*cp) { case '\\': case '\n': putchar('\\'); // fall through... default: putchar(*cp); } } putchar('\n'); } static shell_vtbl_ty vtbl = { destructor, test, command_get, prefix_get, emit, sizeof(shell_zsh_ty), "zsh", }; shell_ty * shell_zsh(void) { shell_ty *sp; shell_zsh_ty *this_thing; sp = shell_new(&vtbl); this_thing = (shell_zsh_ty *)sp; this_thing->command = 0; this_thing->prefix = 0; return sp; }