是详细研究源代码的时候了。此刻,如果您还没有 selpg.c,则可能需要下载它(请参阅 参考资料 )。我将向您介绍代码,一次介绍一段。
以注释“==== includes =====”开始的行
这些行指定所需的头文件。stdio.h 是 C 标准输入输出库的头文件。文件的打开、关闭、读和写函数( fopen()
、 fclose()
、 fgets()
、 getc()
等等)、 printf()
函数系列和 setvbuf()
函数都需要它。
stdlib.h 是 atoi()
函数(将 ASCII 码转换为整数)所需要的,该函数将字符串转换为整数。
string.h 是 strcpy()
和 strcmp()
这样的字符串函数所需要的。
unistd.h 是 access access()
函数所需要的。
limits.h 是定义 INT_MAX 所需要的,INT_MAX 指定您的编译器/操作系统/硬件平台上 int 的最大可取值。使用它而不是硬编码的值可以提高代码的可移植性。
assert.h 用于 assert()
调试宏。
errno.h 是声明 errno 所需要的,errno 是全局系统调用错误号变量(下面会有更多介绍)。
以注释“==== types =====”开始的行
这里只定义了一个类型,即: selpg_args
结构。指向该类型变量的指针被传递到 process_args()
函数,返回该指针时,它包含从参数处理过程获得的值。 typedef
用来给类型一个短名 sp_args。
我们还定义了宏 INBUFSIZ,它是在读取输入时用作缓冲区的字符数组的大小。这是为了有更好的性能。
以注释“==== globals ======”开始的行
Progname
是保存名称(命令就是通过该名称被调用)的全局 char* 变量,作为在错误消息中显示之用。用这种方法,即使您将 selpg 命令重命名为别的名称,新的名称也将在消息中显示;您不必修改该代码。
以注释“==== prototypes ===”开始的行 按照 ANSI C 约定,这些行声明了代码中所有函数的函数原型。这是现在的常规作法,它可以帮助编译器检测函数定义/声明和函数使用之间的类型不匹配。
main() 函数
这很简单:它声明所需变量,然后用变量 ac
、 av
和 &sa
调用函数 process_args()
。 ac
代表“参数计数”,它包含命令行参数的数目, 包括 命令名本身; av
代表“参数向量”,它是字符指针的指针;它以字符串数组的形式包含所有的命令行参数。 &sa
是指向类型为 sp_args
的结构的指针。 process_args()
返回后,已解析的参数值在 sa
结构中;我们将该变量传递至函数 process_input()
,该函数选择所需的页并将其写至指定的目的地。
如果代码中任何一处出现了使处理不能继续进行之类的错误,那么我们会检索系统错误消息(如果有的话),然后将它与我们自己的消息一起显示。随后我们用错误码调用 exit()
函数;对于本实用程序,我们已经选择了对每个不同错误条件返回不同数字。不过这不是必须的;有些实用程序对任何错误条件都简单地返回 1,若成功则返回 0,而其它实用程序则将错误分类,并根据类别返回较小范围代码(比如 1、2 或 3)中的一个。规定的唯一约定是返回 0 应该表示成功而返回非零值表示失败。有关系统调用中出现错误的更多信息,请参阅 系统调用错误 一节。
既然所有错误都会导致退出,那么如果我们从 process_input()
函数返回,则意味着没有错误,因此我们从 main()
返回 0。