9.3.3 sic_builtin.c

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 != ' 
 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; } 
'; pbeg = pend) { pbeg += strspn (pbeg, ":"); len = strcspn (pbeg, ":"); pend = pbeg + len; path = XREALLOC (char, path, 2 + len + strlen(command)); *path = '
 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; } 
'; strncat (path, pbeg, len); if (path[len -1] != '/') strcat (path, "/"); strcat (path, command); if (access (path, X_OK) == 0) break; } if (*pbeg == '
 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; } 
') 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 incase 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 <sic/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 May, 24 2001 using texi2html


GNU Autoconf, Automake and Libtool
GNU Autoconf, Automake, and Libtool
ISBN: 1578701902
EAN: 2147483647
Year: 2002
Pages: 290

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net