Jump to: navigation, search

The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 7.01 on page 153

Write a program that converts upper case to lower or lower case to upper, depending on the name it is invoked with, as found in argv[0].



Solution by Richard Heathfield

/* This program converts its input to upper case
 * (if argv[0] begins with U or u) or lower case.
 * If argc is 0, it prints an error and quits.
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


int main(int argc, char **argv)
{
  int (*convcase[2])(int) = {toupper, tolower};
  int func;
  int result = EXIT_SUCCESS;

  int ch;

  if(argc > 0)
  {
    if(toupper((unsigned char)argv[0][0]) == 'U')
    {
      func = 0;
    }
    else
    {
      func = 1;
    }

    while((ch = getchar()) != EOF)
    {
      ch = (*convcase[func])((unsigned char)ch);
      putchar(ch);
    }
  }
  else
  {
    fprintf(stderr, "Unknown name. Can't decide what to do.\n");
    result = EXIT_FAILURE;
  }

  return result;
}


Solution by Bryan Williams (category 1)

/*

  Exercise 7-1. Write a program that converts upper case to lower case or lower case to upper, 
                depending on the name it is invoked with, as found in argv[0].


  Assumptions: The program should read from stdin, until EOF, converting the output to stdout
               appropriately. 

               The correct outputs should be :
 
               Program Name                Output
               lower                       stdin with all caps converted to lower case
               upper                       stdin with all lowercase characters converted to uppercase
               [anything else]             helpful message explaining how to use this

  Author : Bryan Williams

*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define SUCCESS           0
#define NO_ARGV0          1
#define BAD_NAME          2


int main(int argc, char *argv[])
{
  int ErrorStatus = SUCCESS;
  int (*convert)(int c) = NULL;
  int c = 0;
   
  /* check that there were any arguments */
  if(SUCCESS == ErrorStatus)
  {
    if(0 >= argc)
    {
      printf("Your environment has not provided a single argument for the program name.\n");
      ErrorStatus = NO_ARGV0;
    }
  }

  /* check for valid names in the argv[0] string */
  if(SUCCESS == ErrorStatus)
  {
    if(0 == strcmp(argv[0], "lower"))
    {
      convert = tolower;
    } 
    else if(0 == strcmp(argv[0], "upper"))
    {
      convert = toupper;
    }
    else
    {
      printf("This program performs two functions.\n");
      printf("If the executable is named lower then it converts all the input on stdin to lowercase.\n");
      printf("If the executable is named upper then it converts all the input on stdin to uppercase.\n");
      printf("As you have named it %s it prints this message.\n", argv[0]);
      ErrorStatus = BAD_NAME;
    }
  }

  /* ok so far, keep looping until EOF is encountered */
  if(SUCCESS == ErrorStatus)
  {
    while(EOF != (c = getchar()))
    {
      putchar((*convert)(c));
    }
  }

  /* and return what happened */
  return SUCCESS == ErrorStatus ? EXIT_SUCCESS : EXIT_FAILURE;
}





Solution by Cromagnon (talk) (category 0)

December 26, 2019.

This uses a function getbasename to get the basename of the command. Thus, argv[0] = "/tmp/lower" implies getbasename(argv[0]) = "lower"

#include <stdio.h>
#include <ctype.h>
#include <string.h>

char *getbasename(char *);

/* convert input to lower or upper case depending on argv[0]*/
int main(int argc, char *argv[])
{
	int c, (*convert)(int) = NULL;
	char* bn;

	if (strcmp((bn = getbasename(argv[0])), "lower") == 0)
		convert = tolower;
	else if (strcmp(bn, "upper") == 0)
		convert = toupper;
	else
		return 1;
	while ((c = getchar()) != EOF)
		putchar((*convert)(c));
	return 0;
}

char *getbasename(char *s)
{
	char *p;
	char *base;

	for (base = p = s; *p != '\0'; p++)
		if (*p == '/')
			base = p;
	return base + 1;
}

Solution by DtxdF

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define IS_LOWER 1
#define IS_UPPER 2
#define IS_NONE  -1

int get_size(char *fn);

int main(int argc, char **argv) {
	int c, size;
	char *filename = *argv;
	filename += 2;

	size = get_size(filename);

	if (size == IS_NONE) {
		fputs("Invalid filename!\n", stderr);
		return EXIT_FAILURE;

	}

	while ((c = getchar()) != EOF) {
		if (size == IS_LOWER)
			c = tolower(c);
		else
			c = toupper(c);

		putchar(c);

	}

	return EXIT_SUCCESS;

}

int get_size(char *fn) {
	if (strcmp(fn, "tolower") == 0)
		return IS_LOWER;
	else if (strcmp(fn, "toupper") == 0)
		return IS_UPPER;
	else
		return IS_NONE;

}

Solution by anonymous

My solution takes into account if it is a Unix/Linux executable or a Windows executable and it handles different ways of being called.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/*
    Exercise 7-1. Write a program that converts upper case to lower or lower case to upper, depending on the name it is invoked with, as found in argv[0].
*/

enum type { LOWER, UPPER };

int main(int argc, char *argv[])
{
    int c, mode = -1;
    if (argc > 1)
    {
        printf("usage 1: ./lower\nusage 2: .\\lower.exe\nusage 3: ./upper\nusage 4: .\\upper.exe\n");
        return 1;
    }
    if (stricmp(*argv, "lower") == 0 || stricmp(*argv, "lower.exe") == 0) // handles when argv simply equals the executable name
        mode = LOWER;
    else if (stricmp(*argv, "upper") == 0 || stricmp(*argv, "upper.exe") == 0) // handles when argv simply equals the executable name
        mode = UPPER;
    else  // handles when argv has a relative or absolute path for the executable
    {
        while (*++*argv != '\0') // go to end of string
            ;
        while (*--*argv != '\\' && **argv != '/') // go back until a slash is found
            ;
        (*argv)++; // move right to not include the slash
        if (stricmp(*argv, "lower") == 0 || stricmp(*argv, "lower.exe") == 0)
            mode = LOWER;
        else if (stricmp(*argv, "upper") == 0 || stricmp(*argv, "upper.exe") == 0)
            mode = UPPER;
    }
    if (mode == LOWER)
        while ((c = getchar()) != EOF)
            putchar(tolower(c));
    else if (mode == UPPER)
        while ((c = getchar()) != EOF)
            putchar(toupper(c));
    else
    {
        printf("usage 1: ./lower\nusage 2: .\\lower.exe\nusage 3: ./upper\nusage 4: .\\upper.exe\n");
        return 1;
    }
    return 0;
}
Personal tools