今天睡了大半天,下午找出来上午下回来的coreutils,开始看他的源码,coreutils是unix上比较基础的工具集,去年做lfs的时候还记得有他,包括了cat、tail、ls、head、hostname等等基本的命令,很有必要作为一个开始对他各个命令的源码进行解析,这些软件中最大的ls也才不到千行,可以阅读之,以其作为学习c语法的方式,前几天抱了nettools的源码在看,结果那个东东又是socekt编程,又是网路编程,实在搞不定,还是coreutils比较实际,^_^,今天是第一篇,sleep.c --上来就sleep呵呵。
/* sleep - delay for a specified amount of time.
Copyright (C) 84, 1991-1997, 1999-2005 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
//引入必要的头文件 ""中是自写的,<>中是c库中既有的。
#include
#include
#include
#include
#include "system.h"
#include "c-strtod.h"
#include "error.h"
#include "long-options.h"
#include "quote.h"
#include "xnanosleep.h"
#include "xstrtod.h"
//定义两个宏,在coreutils每个工具中好像都有这两个定义,没错,记住作者吧,饮水思源。
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "sleep"
#define AUTHORS "Jim Meyering", "Paul Eggert"
/* The name by which this program was run. */
//定义指向字符类型的指针变量program_name
char *program_name;
/*把函数的类型与函数名分写两行纯属风格问题。这种写法可以使我们在使用视觉或
某些工具程序追踪源代码时更容易查找函数名
-- 《C和指针》page 117 */
void
usage (int status)
{
if (status != EXIT_SUCCESS)
/* fprintf 是stdio.h库中的一个函数,它的功能是根据第二个参数format字符串来转换并格
式化数据,然后将结果输出到第一个参数指定的标准错误,成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中 */
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
// status == EXIT_SUCCESS的话,用printf直接向便准输出打印如下的东东
printf (_("\
Usage: %s NUMBER[SUFFIX]...\n\
or: %s OPTION\n\
Pause for NUMBER seconds. SUFFIX may be `s' for seconds (the default),\n\
`m' for minutes, `h' for hours or `d' for days. Unlike most implementations\n\
that require NUMBER be an integer, here NUMBER may be an arbitrary floating\n\
point number. Given two or more arguments, pause for the amount of time\n\
specified by the sum of their values.\n\
\n\
"),
program_name, program_name);
//同时如下的内容,不外一些帮助、版本号之类,注意一下fputs标准库函数:
//fputs()用来将第一个参数(如HELP_OPTION_DESCRIPTION)所指的字符串写入到第二个参数(stdout)所指的文件内,此处是标准输出
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
//exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。
exit (status);
}
/* Given a floating point value *X, and a suffix character, SUFFIX_CHAR,
scale *X by the multiplier implied by SUFFIX_CHAR. SUFFIX_CHAR may
be the NUL byte or `s' to denote seconds, `m' for minutes, `h' for
hours, or `d' for days. If SUFFIX_CHAR is invalid, don't modify *X
and return false. Otherwise return true. */
static bool
apply_suffix (double *x, char suffix_char)
{
//函数功能是根据传入的形参做判断,但是最后x的值的确被改正了,因为传递的是指针
int multiplier;
switch (suffix_char)
{
case 0:
case 's':
multiplier = 1;
break;
case 'm':
multiplier = 60;
break;
case 'h':
multiplier = 60 * 60;
break;
case 'd':
multiplier = 60 * 60 * 24;
break;
default:
return false;
}
*x *= multiplier;
return true;
}
// 主体。
int
main (int argc, char **argv)
{
// 整型变量i
int i;
// 双精度变量seconds,初始化为0.0
double seconds = 0.0;
// 布尔型变量 ok 初始化之。
bool ok = true;
initialize_main (&argc, &argv);
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
// atexit()用来设置一个程序正常结束前调用的函数
atexit (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)
usage (EXIT_FAILURE);
if (argc == 1)
{
error (0, 0, _("missing operand"));
usage (EXIT_FAILURE);
}
for (i = optind; i < argc; i++)
{
double s;
const char *p;
if (! xstrtod (argv[i], &p, &s, c_strtod)
/* Nonnegative interval. */
|| ! (0 <= s)
/* No extra chars after the number and an optional s,m,h,d char. */
|| (*p && *(p+1))
/* Check any suffix char and update S based on the suffix. */
|| ! apply_suffix (&s, *p))
{
error (0, 0, _("invalid time interval %s"), quote (argv[i]));
ok = false;
}
seconds += s;
}
if (!ok)
usage (EXIT_FAILURE);
//精华在此了xnanosleep 函数声明在lib/xnanosleep.h中,函数原型在xnanosleep.c 中,整个c源文件都是在做sleep的,晕倒,下次再看看他的具体实现吧,还有更重要的事情-postmark。
if (xnanosleep (seconds))
error (EXIT_FAILURE, errno, _("cannot read realtime clock"));
exit (EXIT_SUCCESS);
}