/* case - this file provides lcase, ucase, icase, ncase and cap

ucase: ucase [-p var] string
    The string is converted to upper case and either:
        stored in the variable supplied with -p
      or
        printed to stdout if no variable is given

lcase: lcase [-p VAR] STRING
    The STRING is converted to lower case and either:
        stored in the variable supplied with -p
      or
        printed to stdout if no variable is given

icase: icase [-p var] string
        Upper case characters in string are converted to lower case and
        lower case characters in are converted to upper case and
        stored in the variable supplied with -p
      or
        printed to stdout if no variable is given


ncase: ncase [-p var][-e][-E CHARS] string
        Letters in string are converted to both upper and lower case,
        enclosed in square brackets, non-alpha characters are retained as is

     OPTIONS
        -e            The special characters (?*|\[] ) are escaped
        -E  CHARLIST  The characters in CHARLIST are escaped
        -p  VAR       The result is stored in the variable VAR


cap: cap [-p var][-n N] string

        The first letter of each word is capitalized and the rest
        are converted to lowercase
        All non-alpha characters are considered word separators

     OPTIONS
        -n  N         Process only the first N words
        -p  VAR       The result is stored in the variable VAR


   Copyright 2006, Chris F.A. Johnson
   Released under the terms of the GNU General Public License, Version 2

*/

/*
   Add the following lines to Makefile:

case: case.o
	$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ case.o $(SHOBJ_LIBS)

case.o: case.c

*/

#include "config.h"

#if defined (HAVE_UNISTD_H)
#  include <unistd.h>
#endif

#include <stdio.h>
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"


lcase_builtin (list)
     WORD_LIST *list;
{
  int n = 0;
  int ch;
  char *string;
  char *var = NULL;

  reset_internal_getopt ();
  while ((ch = internal_getopt (list, "p:")) != -1)
    switch(ch) {
      case 'p':
        var = list_optarg;
        break;
      default:
        builtin_usage();
        return (EX_USAGE);
    }
  list = loptend;

  if (list == 0 || list->next)
    {
      builtin_usage ();
      return (EX_USAGE);
    }

  if (no_options (list))
    return (EX_USAGE);

  string = list->word->word;

  while ( string[n] )
    {
      string[n] = tolower(string[n]);
      ++n;
    }

  if ( var )
    bind_variable (var, string);
  else
    printf ("%s\n", string);

  return (EXECUTION_SUCCESS);
}

char *lcase_doc[] = {
	"The STRING is converted to lower case and either:",
        "    stored in the variable supplied with -p",
        "  or",
        "    printed to stdout if no variable is given",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin lcase_struct = {
	"lcase",		/* builtin name */
	lcase_builtin,	/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	lcase_doc,		/* array of long documentation strings. */
	"lcase [-p VAR] STRING",	/* usage synopsis */
	0			/* reserved for internal use */
};

/* *************************************************************************** */

ucase_builtin (list)
     WORD_LIST *list;
{
  int n = 0;
  int ch;
  char *string;
  char *var = NULL;

  reset_internal_getopt ();
  while ((ch = internal_getopt (list, "p:")) != -1)
    switch(ch) {
      case 'p':
        var = list_optarg;
        break;
      default:
        builtin_usage();
        return (EX_USAGE);
    }
  list = loptend;

  if (list == 0 || list->next)
    {
      builtin_usage ();
      return (EX_USAGE);
    }

  string = list->word->word;

  while ( string[n] )
    {
      string[n] = toupper(string[n]);
      ++n;
    }

  if ( var )
    bind_variable (var, string);
  else
    printf ("%s\n", string);

  return (EXECUTION_SUCCESS);
}

char *ucase_doc[] = {
	"The string is converted to upper case and either:",
        "    stored in the variable supplied with -p",
        "  or",
        "    printed to stdout if no variable is given",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin ucase_struct = {
	"ucase",		/* builtin name */
	ucase_builtin,	/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	ucase_doc,		/* array of long documentation strings. */
	"ucase [-p var] string",	/* usage synopsis */
	0			/* reserved for internal use */
};

/* *************************************************************************** */

icase_builtin (list)
     WORD_LIST *list;
{
  int n = 0;
  int ch;
  char *string;
  char *var = NULL;

  reset_internal_getopt ();
  while ((ch = internal_getopt (list, "p:")) != -1)
    switch(ch) {
      case 'p':
        var = list_optarg;
        break;
      default:
        builtin_usage();
        return (EX_USAGE);
    }
  list = loptend;

  if (list == 0 || list->next)
    {
      builtin_usage ();
      return (EX_USAGE);
    }

  string = list->word->word;

  while ( string[n] )
    {
      if ( islower(string[n]) ) string[n] = toupper(string[n]);
      else if ( isupper(string[n]) ) string[n] = tolower(string[n]);
      ++n;
    }

  if ( var )
    bind_variable (var, string);
  else
    printf ("%s\n", string);

  return (EXECUTION_SUCCESS);
}

char *icase_doc[] = {
	"    Upper case characters in string are converted to lower case and",
	"    lower case characters in are converted to upper case and",
        "    stored in the variable supplied with -p",
        "  or",
        "    printed to stdout if no variable is given",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin icase_struct = {
	"icase",		/* builtin name */
	icase_builtin,	/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	icase_doc,		/* array of long documentation strings. */
	"icase [-p var] string",	/* usage synopsis */
	0			/* reserved for internal use */
};

/* *************************************************************************** */

ncase_builtin (list)
     WORD_LIST *list;
{
  int n = 0;
  int nn = 0;
  int ch;
  int escape = 0;
  char *string;
  char *newstring;
  char *escchars = NULL ;
  char *var = NULL;

  reset_internal_getopt ();
  while ((ch = internal_getopt (list, "p:eE:")) != -1)
    switch(ch) {
      case 'e':
        escape = 1;
        break;
      case 'E':
        escchars = list_optarg;
        break;
      case 'p':
        var = list_optarg;
        break;
      default:
        builtin_usage();
        return (EX_USAGE);
    }
  list = loptend;

  if (list == 0 || list->next)
    {
      builtin_usage ();
      return (EX_USAGE);
    }

  string = list->word->word;
  newstring = malloc( strlen(string) * 4 + 1);
  if ( newstring == NULL )
    {
      return 5;
    }
  newstring[0] = '\0';

  while ( string[n] )
    {
      if ( islower(string[n]) || isupper(string[n]) )
        {
          newstring[nn++] = '[';
          newstring[nn++] = toupper(string[n]);
          newstring[nn++] = tolower(string[n]);
          newstring[nn++] = ']';
        }
      else if ( escape == 1 )
        {
          switch (string[n])
            {
              case ' ':
              case '*':
              case '[':
              case ']':
              case '?':
              case '\\':
              case '&':
              case '|':
                newstring[nn++] = '\\';
                newstring[nn++] = string[n];
                break;

              default:
                newstring[nn++] = string[n];
                break;
            }
        }
      else if ( escchars != NULL )
        {
          if ( strchr(escchars,string[n]) != NULL )
            {
              newstring[nn++] = '\\';
            }
          newstring[nn++] = string[n];
        }
      else
        {
          newstring[nn++] = string[n];
        }
      ++n;
      newstring[nn] = '\0';
    }

  if ( var != NULL )
    bind_variable (var, newstring);
  else
    printf ("%s\n", newstring);

  return (EXECUTION_SUCCESS);
}

char *ncase_doc[] = {
	"    Letters in string are converted to both upper and lower case,",
	"    enclosed in square brackets, non-alpha characters are retained as is",
        "",
        " OPTIONS",
        "    -e            The special characters (?*|\\[] ) are escaped",
        "    -E  CHARLIST  The characters in CHARLIST are escaped",
        "    -p  VAR       The result is stored in the variable VAR",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin ncase_struct = {
	"ncase",		/* builtin name */
	ncase_builtin,	/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	ncase_doc,		/* array of long documentation strings. */
	"ncase [-p var][-e][-E CHARS] string",	/* usage synopsis */
	0			/* reserved for internal use */
};

/* *************************************************************************** */

cap_builtin (list)
     WORD_LIST *list;
{
  int n = 0;
  int nn = 0;
  int ch;
  int escape = 0;
  int firstletter = 1;
  int num = 0;
  int max = 666;
  char *string;
  char *escchars = NULL ;
  char *var = NULL;

  reset_internal_getopt ();
  while ((ch = internal_getopt (list, "p:n:")) != -1)
    switch(ch) {
      case 'E':
        escchars = list_optarg;
        break;

      case 'n':
        max = atoi(list_optarg);
        break;

      case 'p':
        var = list_optarg;
        break;

      default:
        builtin_usage();
        return (EX_USAGE);
    }
  list = loptend;

  if (list == 0 || list->next)
    {
      builtin_usage ();
      return (EX_USAGE);
    }

  string = list->word->word;

  while ( string[n] )
    {
      if ( isalpha(string[n]) && firstletter == 1 )
        {
          firstletter = 0;
          if ( num < max )
            {
              string[n] = toupper(string[n]);
            }
          ++num;
        }
      else if ( isupper(string[n]) )
        {
          string[n] = tolower(string[n]);
        }
      else if ( ! isalpha(string[n]) )
        {
          firstletter = 1;
        }
      ++n;
    }

  if ( var != NULL )
    bind_variable (var, string);
  else
    printf ("%s\n", string);

  return (EXECUTION_SUCCESS);
}

char *cap_doc[] = {
        "",
	"    The first letter of each word is capitalized and the rest",
	"    are converted to lowercase",
        "    All non-alpha characters are considered word separators",
        "",
        " OPTIONS",
        "    -n  N         Process only the first N words",
        "    -p  VAR       The result is stored in the variable VAR",
	(char *)NULL
};

/* The standard structure describing a builtin command.  bash keeps an array
   of these structures. */
struct builtin cap_struct = {
	"cap",		/* builtin name */
	cap_builtin,	/* function implementing the builtin */
	BUILTIN_ENABLED,	/* initial flags for builtin */
	cap_doc,		/* array of long documentation strings. */
	"cap [-p var][-n N] string",	/* usage synopsis */
	0			/* reserved for internal use */
};

