Chinaunix首页 | 论坛 | 博客
  • 博客访问: 929022
  • 博文数量: 177
  • 博客积分: 8613
  • 博客等级: 中将
  • 技术积分: 2835
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-12 04:16
文章分类
文章存档

2012年(12)

2011年(24)

2010年(24)

2009年(75)

2008年(42)

我的朋友

分类: C/C++

2009-12-02 18:06:17

/* basename -- strip directory and suffix from file names
程序的作用是,去掉文件名的目录部分和后缀部分,suffix是后缀的意思
 */

/* Usage: basename name [suffix] 这是个使用举例,这个例子相当不错了,很明了的说
   NAME is a file name; SUFFIX is a suffix to strip from it.

   basename /usr/foo/lossage/functions.l
   => functions.l
   basename /usr/foo/lossage/functions.l .l
   => functions
   basename functions.lisp p
   => functions.lis */
//包含一些系统里的库头
#include
#include
#include
#include
//包含本地的一些头文件
#include "system.h"
#include "long-options.h"
#include "error.h"
#include "quote.h"

/* The official name of this program (e.g., no `g' prefix).  */
#define PROGRAM_NAME "basename" //定义宏PROGRAM_NAME,其值是一个字符串,是程序名称

#define AUTHORS "FIXME unknown"//定义宏AUTHORS

/* The name this program was run with. */
char *program_name; //声明全局字符指针

void
usage (int status)//帮助函数
{
  if (status != EXIT_SUCCESS)
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
         program_name);
  else
    {
      printf (_("\
Usage: %s NAME [SUFFIX]\n\
  or:  %s OPTION\n\
"),
          program_name, program_name);
      fputs (_("\
Print NAME with any leading directory components removed.\n\
If specified, also remove a trailing SUFFIX.\n\
\n\
"), stdout);//这句话说明了程序的主要用途,是打印去掉了目录和尾部的后缀以后的文件名
      fputs (HELP_OPTION_DESCRIPTION, stdout);
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
      printf (_("\
\n\
Examples:\n\
  %s /usr/bin/sort       Output \"sort\".\n\
  %s include/stdio.h .h  Output \"stdio\".\n\
"),
          program_name, program_name);
      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    }
  exit (status);
}

/* Remove SUFFIX from the end of NAME if it is there, unless NAME
   consists entirely of SUFFIX.
去掉文件名最后的后缀,如果文件名和后缀相同,则不去除
   */

static void
remove_suffix (char *name, const char *suffix)//此函数接受两个形参,形参都是指向字符类型的指针
{
  char *np;//声明局部变量np,是一个指向字符类型的指针
  const char *sp;//声明指针变量,指向的是一个字符串常量,再说一下,指针可以被改变,指针指向的字符串不能被改变

  np = name + strlen (name);//np的值是第一个形参name的首地址加上name的长度,也就是指向了name的最后一个空字符
  sp = suffix + strlen (suffix);//和上面一样,sp得到了一个位置

  while (np > name && sp > suffix)//循环继续的条件是np到达name的第一个字符之前,并且sp到达suffix的第一个字符之前
    if (*--np != *--sp)//如果np的最后一个字符不等于sp指向的那个字符,则直接return,如果相等,则继续进行循环
      return;
  if (np > name)//循环执行完毕后,应该是suffix遍历完毕了,而且匹配了所有的np指向的name的最后那些字符,这时候将目前的np指向的字符置为\0,这样就达到去除后缀的目的了
    *np = '\0';
}//想想,如果name和suffix是一致的话,最后的那个(np > name)就不执行了,所以name的值并没有被改变,否则的话,肯定把后缀给去掉了。

int
main (int argc, char **argv)//main函数体
{
  char *name;//声明main函数里的字符指针变量name
//下面这5行是标准做法
  initialize_main (&argc, &argv);
  program_name = argv[0];
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  atexit (close_stdout);//登记出口函数,这里面,特别是close_stdout函数,引用的比较多,很常用,在每个小程序里基本都使用了,不错。

  parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
              usage, AUTHORS, (char const *) NULL);//解析命令行选项,主要是看看是否在控制台上打印帮助信息
  if (getopt_long (argc, argv, "+", NULL, NULL) != -1)//此程序不需要命令行选项,所以调用一次getopt_long函数后,如果返回值不是-1,说明命令行有选项了,则打印帮助,并退出程序
    usage (EXIT_FAILURE);

  if (argc < optind + 1)//optind的值,应该是1,这里的语义是,如果argc小于2的话,就打印帮助信息,并退出程序,if的条件语句里不写小于2,是为了更好的兼容吧
    {
      error (0, 0, _("missing operand"));
      usage (EXIT_FAILURE);
    }

  if (optind + 2 < argc)//同理,如果argc大于3,也打印帮助并退出程序,这说明该程序只接受一个或者两个命令行参数
    {
      error (0, 0, _("extra operand %s"), quote (argv[optind + 2]));
      usage (EXIT_FAILURE);
    }

//base_name是在lib/Basename.c里面实现的,这里向它传递了一个形参,就是命令行参数里的第一个字符串,经过base_name处理后,将那个字符串赋值给name
  name = base_name (argv[optind]);
  strip_trailing_slashes (name);//这个函数是在lib/Stripslash.c里面实现的,将name传递过去处理一下

  /* Per POSIX, `basename // /' must return `//' on platforms with
     distinct //.  On platforms with drive letters, this generalizes
     to making `basename c: :' return `c:'.  This rule is captured by
     skipping suffix stripping if base_name returned an absolute path
     or a drive letter (only possible if name is a file-system
     root).  */
     //下面的这个if条件比较多,引用的两个函数都是在dirname.h里面定义的宏
  if (argc == optind + 2 && IS_RELATIVE_FILE_NAME (name)
      && ! FILE_SYSTEM_PREFIX_LEN (name))
    remove_suffix (name, argv[optind + 1]);//满足上面if的条件的情况下,调用本文件里的函数remove_suffix

  puts (name);//打印出来name这个字符串
  free (name);//释放name指向的内存空间

  exit (EXIT_SUCCESS);//函数最终的退出状态是成功。
}

阅读(1518) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~