Back: sic_syntax.c
Forward: sic.c & sic.h (again)
 
FastBack: sic.c & sic.h (again)
Up: A Sample Shell Application
FastForward: Introducing GNU Libtool
Top: Autoconf, Automake, and Libtool
Contents: Table of Contents
Index: Index
About: About this document

9.3.3 `sic_builtin.c'

In addition to the syntax handlers I have just added to the Sic shell, the language of this shell is also defined by the builtin commands it provides. The infrastructure for this file is built from a table of functions which is fed into various C preprocessor macros, just as I did for the syntax handlers.

One builtin handler function has special status, builtin_unknown. This is the builtin that is called, if the Sic library cannot find a suitable builtin function to handle the current input command. At first this doesn't sound especially important -- but it is the key to any shell implementation. When there is no builtin handler for the command, the shell will search the users command path, `$PATH', to find a suitable executable. And this is the job of builtin_unknown:

 
int
builtin_unknown (Sic *sic, int argc, char *const argv[])
{
  char *path = path_find (argv[0]);
  int status = SIC_ERROR;

  if (!path)
    {
      sic_result_append (sic, "command \"");
      sic_result_append (sic, argv[0]);
      sic_result_append (sic, "\" not found");
    }
  else if (path_execute (sic, path, argv) != SIC_OKAY)
    {
      sic_result_append (sic, "command \"");
      sic_result_append (sic, argv[0]);
      sic_result_append (sic, "\" failed: ");
      sic_result_append (sic, strerror (errno));
    }
  else
    status = SIC_OKAY;

  return status;
}

static char *
path_find (const char *command)
{
  char *path = xstrdup (command);
  
  if (*command == '/')
    {
      if (access (command, X_OK) < 0)
        goto notfound;
    }
  else
    {
      char *PATH = getenv ("PATH");
      char *pbeg, *pend;
      size_t len;

      for (pbeg = PATH; *pbeg != '\0'; pbeg = pend)
        {
          pbeg += strspn (pbeg, ":");
          len = strcspn (pbeg, ":");
          pend = pbeg + len;
          path = XREALLOC (char, path, 2 + len + strlen(command));
          *path = '\0';
          strncat (path, pbeg, len);
          if (path[len -1] != '/') strcat (path, "/");
          strcat (path, command);
          
          if (access (path, X_OK) == 0)
              break;
        }

      if (*pbeg == '\0')
          goto notfound;
    }

  return path;

 notfound:
  XFREE (path);
  return NULL;
}  


Running `autoscan' again at this point adds AC_CHECK_FUNCS(strcspn strspn) to `configure.scan'. This tells me that these functions are not truly portable. As before I provide fallback implementations for these functions in case they are missing from the target host -- and as it turns out, they are easy to write:

 
/* strcspn.c -- implement strcspn() for architectures without it */

#if HAVE_CONFIG_H
#  include <config.h>
#endif

#include <sys/types.h>

#if STDC_HEADERS
#  include <string.h>
#elif HAVE_STRINGS_H
#  include <strings.h>
#endif

#if !HAVE_STRCHR
#  ifndef strchr
#    define strchr index
#  endif
#endif

size_t
strcspn (const char *string, const char *reject)
{
  size_t count = 0;
  while (strchr (reject, *string) == 0)
    ++count, ++string;

  return count;
}

There is no need to add any code to `Makefile.am', because the configure script will automatically add the names of the missing function sources to `@LIBOBJS@'.

This implementation uses the autoconf generated `config.h' to get information about the availability of headers and type definitions. It is interesting that autoscan reports that strchr and strrchr, which are used in the fallback implementations of strcspn and strspn respectively, are themselves not portable! Luckily, the Autoconf manual tells me exactly how to deal with this: by adding some code to my `common.h' (paraphrased from the literal code in the manual):

 
#if !STDC_HEADERS
#  if !HAVE_STRCHR
#    define strchr index
#    define strrchr rindex
#  endif
#endif

And another macro in `configure.in':

 
AC_CHECK_FUNCS(strchr strrchr)


This document was generated by Gary V. Vaughan on February, 8 2006 using texi2html