+ long count = 1;
+
+ if (list)
+ {
+ register char *arg;
+
+ arg = list->word->word;
+ if (!arg || (legal_number (arg, &count) == 0))
+ {
+ builtin_error ("bad non-numeric arg `%s'", list->word->word);
+ throw_to_top_level ();
+ }
+ no_args (list->next);
+ }
+ return (count);
+}
+
+/* Return the octal number parsed from STRING, or -1 to indicate
+ that the string contained a bad number. */
+int
+read_octal (string)
+ char *string;
+{
+ int result, digits;
+
+ result = digits = 0;
+ while (*string && *string >= '0' && *string < '8')
+ {
+ digits++;
+ result = (result * 8) + *string++ - '0';
+ }
+
+ if (!digits || result > 0777 || *string)
+ result = -1;
+
+ return (result);
+}
+
+/* **************************************************************** */
+/* */
+/* Command name hashing */
+/* */
+/* **************************************************************** */
+
+/* Return the full pathname that FILENAME hashes to. If FILENAME
+ is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check
+ ./FILENAME and return that if it is executable. */
+char *
+find_hashed_filename (filename)
+ char *filename;
+{
+ register BUCKET_CONTENTS *item;
+ char *path, *dotted_filename, *tail;
+ int same;
+
+ if (hashing_enabled == 0)
+ return ((char *)NULL);
+
+ item = find_hash_item (filename, hashed_filenames);
+
+ if (item == NULL)
+ return ((char *)NULL);
+
+ /* If this filename is hashed, but `.' comes before it in the path,
+ see if ./filename is executable. If the hashed value is not an
+ absolute pathname, see if ./`hashed-value' exists. */
+ path = pathdata(item)->path;
+ if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH))
+ {
+ tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename;
+ dotted_filename = xmalloc (3 + strlen (tail));
+ dotted_filename[0] = '.'; dotted_filename[1] = '/';
+ strcpy (dotted_filename + 2, tail);
+
+ if (executable_file (dotted_filename))
+ return (dotted_filename);
+
+ free (dotted_filename);
+
+#if 0
+ if (pathdata(item)->flags & HASH_RELPATH)
+ return ((char *)NULL);
+#endif
+
+ /* Watch out. If this file was hashed to "./filename", and
+ "./filename" is not executable, then return NULL. */
+
+ /* Since we already know "./filename" is not executable, what
+ we're really interested in is whether or not the `path'
+ portion of the hashed filename is equivalent to the current
+ directory, but only if it starts with a `.'. (This catches
+ ./. and so on.) same_file () tests general Unix file
+ equivalence -- same device and inode. */
+ if (*path == '.')
+ {
+ same = 0;
+ tail = (char *)strrchr (path, '/');
+
+ if (tail)
+ {
+ *tail = '\0';
+ same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL);
+ *tail = '/';
+ }
+
+ return same ? (char *)NULL : path;
+ }
+ }
+
+ return (path);