linux命令源码剖析,Linux cat 命令源码剖析

5. safe_rw, full_rw 函数

read 和write函数在读写第一个字符之前有可能被signal中断, safe_rw可以恢复被中断的read和write过程. 这个函数非常tricky, 它的名字safe_rw和rw其实都是宏定义, 条件编译可以将此函数编译成safe_read, safe_write两个函数.

size_t /* 原始的read()函数返回值是 ssize_t */

safe_rw (int fd, void const *buf, size_t count)

{

/* Work around a bug in Tru64 5.1.  Attempting to read more than

INT_MAX bytes fails with errno == EINVAL.  See

.

When decreasing COUNT, keep it block-aligned.  */

enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };

for (;;)

{

ssize_t result = rw (fd, buf, count);

if (0 <= result)

return result;

    else if (IS_EINTR (errno)) /* signal 中断 */

continue;

else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)

count = BUGGY_READ_MAXIMUM;

else  /* 返回 (size_t) -1 */

return result;

}

}

read, write 读写过程中有可能被 signal 中断, full_rw 可以恢复读写过程, 直到读写到了指定数目的字节或到达文件结尾(EOF), 或者是读写出错. 返回当前已经读写了的字节数目. full_rw() 函数名也是宏定义的, 实际上实现了full_read() full_write().

/* Write(read) COUNT bytes at BUF to(from) descriptor FD, retrying if

interrupted or if a partial write(read) occurs.  Return the number

of bytes transferred.

When writing, set errno if fewer than COUNT bytes are written.

When reading, if fewer than COUNT bytes are read, you must examine

errno to distinguish failure from EOF (errno == 0).  */

size_t

full_rw (int fd, const void *buf, size_t count)

{

size_t total = 0;

const char *ptr = (const char *) buf;

while (count > 0)

{

size_t n_rw = safe_rw (fd, ptr, count);

if (n_rw == (size_t) -1) /* error */

break;

if (n_rw == 0) /* reach EOF */

{

errno = ZERO_BYTE_TRANSFER_ERRNO;

break;

}

total += n_rw;

ptr += n_rw;

count -= n_rw;

}

return total;

}

Tips : 查看lib目录下safe_read.c 和 safe_write.c文件可以看到这个函数怎样被展开成两个不同的函数的.

6. cat 函数, 处理格式化输出

simple_cat只是将输入原封不动的输出, 没有作任何处理, 所有与格式化输出有关的内容都放在了 cat 函数里面.

cat 函数的实现包含很多技巧. 例如使用一个哨兵'\n'来标记输入缓冲区的结尾. 另外使用了一个字符数组来统计行数, 使得不支持64位整型的系统也可以使用很大范围的数.

下面是这个行计数器的代码.

/* Position in 'line_buf' where printing starts.  This will not change

unless the number of lines is larger than 999999.  */

static char *line_num_print = line_buf + LINE_COUNTER_BUF_LEN - 8;

/* Position of the first digit in 'line_buf'.  */

static char *line_num_start = line_buf + LINE_COUNTER_BUF_LEN - 3;

/* Position of the last digit in 'line_buf'.  */

static char *line_num_end = line_buf + LINE_COUNTER_BUF_LEN - 3;

static void

next_line_num (void)

{

char *endp = line_num_end;

do

{

if ((*endp)++ < '9')

return;

*endp-- = '0';

}

while (endp >= line_num_start);

if (line_num_start > line_buf)

*--line_num_start = '1';

else

*line_buf = '>';

if (line_num_start < line_num_print)

line_num_print--;

}

理解这个函数的关键是搞懂newlines这个变量作用, cat格式化输出主要的操作判断换行和连续空行, newlines这个变量标记的是空行的数目, 值为0表示此时的inbuf的读取位置在一行的开头, 1表示有一个空行, -1 表示刚刚解析完一行, 准备进入下一行, 可以看到cat 函数最后的那个 while(true) 的两个break语句都将 newlines 置为 -1.

cat格式化输出的过程实际上就是逐一扫描输入缓冲数组的过程, 并在扫描的过程中将转化后的字符存入输出缓冲数组中.

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值