Mercurial > hg > octave-nkf
diff liboctave/file-ops.cc @ 3040:443851377f3f
[project @ 1997-06-06 09:29:28 by jwe]
author | jwe |
---|---|
date | Fri, 06 Jun 1997 09:34:14 +0000 |
parents | cf676ff8b702 |
children | 42975c59d2a0 |
line wrap: on
line diff
--- a/liboctave/file-ops.cc +++ b/liboctave/file-ops.cc @@ -29,6 +29,8 @@ #include <cstdlib> #include <cstring> +#include <iostream.h> + #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif @@ -192,74 +194,250 @@ return retval; } -// If NAME has a leading ~ or ~user, Unix-style, expand it to the -// user's home directory. If no ~, or no <pwd.h>, just return NAME. - -// Mostly stolen from kpathsea. Readline also has a more complicated -// tilde-expand function, but we can probalby get by with something a -// bit simpler. +// The following tilde-expansion code was stolen and adapted from +// readline. // XXX FIXME XXX #define DIR_SEP_CHAR '/' +// The default value of tilde_additional_prefixes. This is set to +// whitespace preceding a tilde so that simple programs which do not +// perform any word separation get desired behaviour. +static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 }; + +// The default value of tilde_additional_suffixes. This is set to +// whitespace or newline so that simple programs which do not perform +// any word separation get desired behaviour. +static const char *default_suffixes[] = { " ", "\n", ":", 0 }; + +// If non-null, this contains the address of a function that the +// application wants called before trying the standard tilde +// expansions. The function is called with the text sans tilde, and +// returns a malloc()'ed string which is the expansion, or a NULL +// pointer if the expansion fails. +file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0; + +// If non-null, this contains the address of a function to call if the +// standard meaning for expanding a tilde fails. The function is +// called with the text (sans tilde, as in "foo"), and returns a +// malloc()'ed string which is the expansion, or a NULL pointer if +// there is no expansion. +file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0; + +// When non-null, this is a NULL terminated array of strings which are +// duplicates for a tilde prefix. Bash uses this to expand `=~' and +// `:~'. +string_vector file_ops::tilde_additional_prefixes = default_prefixes; + +// When non-null, this is a NULL terminated array of strings which +// match the end of a username, instead of just "/". Bash sets this +// to `:' and `=~'. +string_vector file_ops::tilde_additional_suffixes = default_suffixes; + +// Find the start of a tilde expansion in S, and return the index +// of the tilde which starts the expansion. Place the length of the +// text which identified this tilde starter in LEN, excluding the +// tilde itself. + +static size_t +tilde_find_prefix (const string& s, size_t& len) +{ + len = 0; + + size_t s_len = s.length (); + + if (s_len == 0 || s[0] == '~') + return 0; + + string_vector prefixes = file_ops::tilde_additional_prefixes; + + if (! prefixes.empty ()) + { + for (size_t i = 0; i < s_len; i++) + { + for (int j = 0; j < prefixes.length (); j++) + { + size_t pfx_len = prefixes[j].length (); + + if (prefixes[j].compare (s.substr (i, pfx_len)) == 0) + { + len = pfx_len - 1; + return i + len; + } + } + } + } + + return s_len; +} + +// Find the end of a tilde expansion in S, and return the index +// of the character which ends the tilde definition. + +static size_t +tilde_find_suffix (const string& s) +{ + size_t s_len = s.length (); + + string_vector suffixes = file_ops::tilde_additional_suffixes; + + size_t i = 0; + + for ( ; i < s_len; i++) + { + if (s[i] == DIR_SEP_CHAR) + break; + + if (! suffixes.empty ()) + { + for (int j = 0; j < suffixes.length (); j++) + { + size_t sfx_len = suffixes[j].length (); + + if (suffixes[j].compare (s.substr (i, sfx_len)) == 0) + return i; + } + } + } + + return i; +} + +// Take FNAME and return the tilde prefix we want expanded. + +static string +isolate_tilde_prefix (const string& fname) +{ + size_t f_len = fname.length (); + + size_t len = 1; + + while (len < f_len && fname[len] != DIR_SEP_CHAR) + len++; + + return fname.substr (1, len); +} + +// Do the work of tilde expansion on FILENAME. FILENAME starts with a +// tilde. + +static string +tilde_expand_word (const string& filename) +{ + size_t f_len = filename.length (); + + if (f_len == 0 || filename[0] != '~') + return filename; + + // A leading `~/' or a bare `~' is *always* translated to the value + // of $HOME or the home directory of the current user, regardless of + // any preexpansion hook. + + if (f_len == 1 || filename[1] == DIR_SEP_CHAR) + return octave_env::get_home_directory () + filename.substr (1); + + string username = isolate_tilde_prefix (filename); + + size_t user_len = username.length (); + + string dirname; + + if (file_ops::tilde_expansion_preexpansion_hook) + { + string expansion + = file_ops::tilde_expansion_preexpansion_hook (username); + + if (! expansion.empty ()) + { + dirname = expansion + filename.substr (user_len); + return dirname; + } + } + + // No preexpansion hook, or the preexpansion hook failed. Look in the + // password database. + + octave_passwd pw = octave_passwd::getpwnam (username); + + if (! pw) + { + // If the calling program has a special syntax for expanding tildes, + // and we couldn't find a standard expansion, then let them try. + + if (file_ops::tilde_expansion_failure_hook) + { + string expansion + = file_ops::tilde_expansion_failure_hook (username); + + if (! expansion.empty ()) + dirname = expansion + filename.substr (user_len); + } + + // If we don't have a failure hook, or if the failure hook did not + // expand the tilde, return a copy of what we were passed. + + if (dirname.length () == 0) + dirname = filename; + } + else + dirname = pw.dir () + filename.substr (user_len); + + return dirname; +} + +// If NAME has a leading ~ or ~user, Unix-style, expand it to the +// user's home directory. If no ~, or no <pwd.h>, just return NAME. + string file_ops::tilde_expand (const string& name) { - string expansion = name; + string result; - // If no leading tilde, do nothing. + size_t name_len = name.length (); - size_t beg = name.find_first_not_of (" \t"); + // Scan through S expanding tildes as we come to them. - if (beg != NPOS && name[beg] == '~') - { - // If `~' or `~/', use the user's home directory. If that is - // empty, just use ".". + size_t pos = 0; - // If `~user' or `~user/', look up user in the passwd database. - - size_t len = name.length (); + while (1) + { + if (pos > name_len) + break; - if (beg == len-1 || name[beg+1] == DIR_SEP_CHAR) - { - string home = octave_env::get_home_directory (); + size_t len; + + // Make START point to the tilde which starts the expansion. - if (home.empty ()) - home = "."; - - expansion = name.substr (0, beg) + home; + size_t start = tilde_find_prefix (name.substr (pos), len); + + result.append (name.substr (pos, start)); - if (beg < len) - expansion.append (name.substr (beg+1)); - } - else - { - size_t end = name.find (DIR_SEP_CHAR, beg); + // Advance STRING to the starting tilde. + + pos += start; - size_t len = end; + // Make FINI be the index of one after the last character of the + // username. - if (end != NPOS) - len -= beg + 1; + size_t fini = tilde_find_suffix (name.substr (pos)); - string user = name.substr (beg+1, len); + // If both START and FINI are zero, we are all done. - octave_passwd pw = octave_passwd::getpwnam (user); + if (! (start || fini)) + break; - // If no such user, just return the original string. + // Expand the entire tilde word, and copy it into RESULT. - if (pw) - { - expansion = string (" ", beg) + pw.dir (); + string tilde_word = name.substr (pos, fini); + + pos += fini; - if (end != NPOS) - expansion.append (name.substr (end)); - } - else - expansion = name; - } + string expansion = tilde_expand_word (tilde_word); + + result.append (expansion); } - return expansion; + return result; } // A vector version of the above.