/******************************************************************** * Android development tools line_endings hacking * 说明: * 本文主要是对android源代码中的line_endings开发工具进行了解读, * 目的是为了知道传说中的dos,unix文件之间转换的工作机制。 * * 2016-5-3 深圳 南山平山村 曾剑锋 *******************************************************************/ #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/stat.h> #define BUFSIZE (1024*8) static void to_unix(char* buf); static void unix_to_dos(char* buf2, const char* buf); // 使用方法 int usage() { fprintf(stderr, "usage: line_endings unix|dos FILES\n" "\n" "Convert FILES to either unix or dos line endings.\n"); return 1; } // 定义Node数据结构 typedef struct Node { struct Node *next; char buf[BUFSIZE*2+3]; } Node; int main(int argc, char** argv) { // 枚举UNIX,DOS两种数据 enum { UNIX, DOS } ending; int i; // 参数个数判断 if (argc < 2) { return usage(); } // 参数比较 if (0 == strcmp("unix", argv[1])) { ending = UNIX; } else if (0 == strcmp("dos", argv[1])) { ending = DOS; } else { return usage(); } // 命令行传入的参数可能有多个,利用for循环进行轮流转换。 for (i=2; i<argc; i++) { int fd; int len; // force implied chmod(argv[i], S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); // 打开文件 fd = open(argv[i], O_RDWR); if (fd < 0) { fprintf(stderr, "unable to open file for read/write: %s\n", argv[i]); return 1; } // 获取文件大小 len = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); // 文件长度正常才有必要进行转换 if (len > 0) { // 创建根节点 Node* root = malloc(sizeof(Node)); Node* node = root; node->buf[0] = 0; // root节点的buf数据位0 while (len > 0) { // 创建节点,并出示节点 node->next = malloc(sizeof(Node)); node = node->next; node->next = NULL; // 这里还是没搞太懂为什么要+2,后面有'\0',那只需要+1就行了,为什么 // 还要+2,没搞懂。 char buf[BUFSIZE+2]; ssize_t amt; ssize_t amt2 = len < BUFSIZE ? len : BUFSIZE; amt = read(fd, buf, amt2); if (amt != amt2) { fprintf(stderr, "unable to read file: %s\n", argv[i]); return 1; } buf[amt2] = '\0'; // 字符串结尾 // 先转成unix文档 to_unix(buf); if (ending == UNIX) { strcpy(node->buf, buf); } else { // 这里BUFSIZE*2的主要原因应该是怕所有的都是换行符,这样转换出来 // 就是*2了,但是没搞懂为什么要+3,个人感觉最多有个+1就行了。 char buf2[(BUFSIZE*2)+3]; unix_to_dos(buf2, buf); strcpy(node->buf, buf2); } len -= amt2; } // 将文件长度修改为0,并重新从文件头开始 ftruncate(fd, 0); lseek(fd, 0, SEEK_SET); // 循环将链表中的内容写入文件,并释放链表中的内容 while (root) { ssize_t amt2 = strlen(root->buf); if (amt2 > 0) { ssize_t amt = write(fd, root->buf, amt2); if (amt != amt2) { fprintf(stderr, "unable to write file: %s\n", argv[i]); return 1; } } node = root; root = root->next; free(node); } } close(fd); } return 0; } // 这里相当于是字符的的不断的拷贝 void to_unix(char* buf) { char* p = buf; char* q = buf; while (*p) { if (p[0] == '\r' && p[1] == '\n') { // dos *q = '\n'; p += 2; q += 1; } else if (p[0] == '\r') { // old mac *q = '\n'; p += 1; q += 1; } else { *q = *p; p += 1; q += 1; } } *q = '\0'; } // 这里和to_unix的动作正好相反 void unix_to_dos(char* buf2, const char* buf) { const char* p = buf; char* q = buf2; while (*p) { if (*p == '\n') { q[0] = '\r'; q[1] = '\n'; q += 2; p += 1; } else { *q = *p; p += 1; q += 1; } } *q = '\0'; }