zoukankan      html  css  js  c++  java
  • 像linux ls命令一样优雅地打印

      1 #define _GNU_SOURCE
      2 
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <stdlib.h>
      6 #include <errno.h>
      7 #include <unistd.h>
      8 
      9 #define TEST_THIS_FILE (1)
     10 
     11 #if TEST_THIS_FILE
     12 #include <unistd.h>
     13 #define MY_MAX(a, b) ((a > b) ? (a) : (b))
     14 #define MY_CEIL(a, b) ((0 == (a % b)) ? (a / b) : ((a / b) + 1))
     15 #define my_free(a) do{if(a) {free(a); (a) = NULL;}} while(0)
     16 #define STR_SAFE(str) ((NULL == (str)) ? "" : (str))
     17 // #define my_print_ln(fmt, arg...) do { printf("(%s|%d)"fmt"
    ", __func__, __LINE__, ##arg); } while(0)
     18 #define my_print_ln(fmt, arg...) do { ; } while(0)
     19 #else
     20 #include "my_platform_common.h"
     21 #endif
     22 
     23 
     24 
     25 
     26 #define SPAN_LEN  (2)   // 列间空格个数
     27 
     28 typedef struct _last_max_len_of_line_t {
     29     unsigned int len;
     30     unsigned int col_total;
     31 }last_max_len_of_line_t;
     32 
     33 /****************************************
     34     计算第几列宽度
     35 
     36     参数 :
     37         names : 待打印的字符串数组
     38         names_count : 待打印的字符串数组长度
     39         col_total : 打印列数
     40         index_col : 第几列
     41 
     42     return : 非NULL 成功
     43                NULL 失败
     44 
     45 ****************************************/
     46 static unsigned int col_len_max(char **names, unsigned int names_count, unsigned int col_total, int index_col)
     47 {
     48     unsigned int curr_col_len_max = 0;
     49     unsigned int index_name = 0;
     50     int row_count = 0;
     51 
     52     if (NULL == names || 0 >= names_count || 0 >= col_total || 0 > index_col) {
     53         return -1;
     54     }
     55     
     56     row_count = MY_CEIL(names_count, col_total);
     57 
     58     // 输出每一行
     59     for (index_name = 0; index_name < MY_CEIL(names_count, col_total); index_name++)
     60     {
     61         if (names_count - 1 < index_name + index_col * row_count) {
     62             break;
     63         }
     64 
     65         curr_col_len_max = MY_MAX(curr_col_len_max, strlen(names[index_name + index_col * row_count]));
     66     }
     67 
     68     if (0 < curr_col_len_max) {
     69         curr_col_len_max += SPAN_LEN;
     70     }
     71 
     72     //my_print_ln("ret=%d", curr_col_len_max);
     73 
     74     return curr_col_len_max;
     75 }
     76 
     77 /****************************************
     78     获取第几行字符串
     79 
     80     参数 :
     81         names : 待打印的字符串数组
     82         names_count : 待打印的字符串数组长度
     83         col_total : 打印列数
     84         index_row : 第几行
     85         width_each : 每列宽度数组
     86 
     87     return : 非NULL 成功
     88                NULL 失败
     89 
     90 ****************************************/
     91 static char *make_buf_of_row(char **names, unsigned int names_count, unsigned int col_total, int index_row, int *width_each)
     92 {
     93     char *buf_row = NULL;
     94     char *buf_row_tmp = NULL;
     95     char *format = NULL;
     96     int row_count = 0;
     97     unsigned int i = 0;
     98 
     99     if (NULL == names || 0 >= names_count || 0 >= col_total || 0 > index_row || NULL == width_each ) {
    100         return NULL;
    101     }
    102     
    103     row_count = MY_CEIL(names_count, col_total);
    104 
    105     for (i = 0; i < col_total; i++, buf_row_tmp = buf_row) {
    106         if (names_count - 1 < index_row + i * row_count) {
    107             break;
    108         }
    109 
    110         asprintf(&format, "%%s%%-%ds", width_each[i]);
    111         if (NULL == format) {
    112             my_free(buf_row);
    113             my_free(buf_row_tmp);
    114             return NULL;
    115         }
    116         asprintf(&buf_row, format, STR_SAFE(buf_row_tmp), names[index_row + i * row_count]);
    117         if (NULL == buf_row) {
    118             my_free(format);
    119             my_free(buf_row_tmp);
    120             return NULL;
    121         }
    122 
    123         my_free(format);
    124         my_free(buf_row_tmp);
    125     }
    126 
    127     // my_print_ln("ret=%s", buf_row);
    128     return buf_row;
    129 }
    130 
    131 static ssize_t _write(int fd, const void *buf, size_t count) {
    132   size_t written = 0;
    133   ssize_t thisTime = 0;
    134   while (count != written) {
    135     thisTime = write(fd, (char *)buf + written, count - written);
    136     if (thisTime == -1) {
    137       if (errno == EINTR)
    138         continue;
    139       else
    140         return -1;
    141     }
    142     written += thisTime;
    143   }
    144   return written;
    145 }
    146 
    147 /****************************************
    148     按n列打印字符串数组
    149 
    150     参数 :
    151         sockfd : 打印输出到文件描述符
    152         names : 待打印的字符串数组
    153         names_count : 待打印的字符串数组长度
    154         col_total : 打印列数
    155 
    156     return :  0 成功
    157              -1 失败
    158 
    159 ****************************************/
    160 static int print_list(int sockfd, char **names, unsigned int names_count, unsigned int col_total)
    161 {
    162     unsigned int index_col = 0;
    163     unsigned int index_row = 0;
    164     int *width_each_col = NULL;
    165 
    166     if (NULL == names || 0 >= names_count || 0 >= col_total) {
    167         return -1;
    168     }
    169     
    170     width_each_col = calloc(col_total, sizeof(int));
    171     if (NULL == width_each_col) {
    172         return -1;
    173     }
    174 
    175     // 计算每列的宽度
    176     for (index_col = 0; index_col < col_total; index_col++)
    177     {
    178         width_each_col[index_col] = col_len_max(names, names_count, col_total, index_col);
    179     }
    180     
    181     // 输出每一行
    182     for (index_row = 0; index_row < MY_CEIL(names_count, col_total); index_row++)
    183     {
    184         char *buf_each_line = NULL;
    185         
    186         buf_each_line = make_buf_of_row(names, names_count, col_total, index_row, width_each_col);
    187         if (NULL == buf_each_line) {
    188             continue;
    189         }
    190 
    191         _write(sockfd, buf_each_line, strlen(buf_each_line));
    192         _write(sockfd, "
    ", 2);
    193 
    194         my_free(buf_each_line);
    195     }
    196 
    197     my_free(width_each_col);
    198 
    199     return 0;
    200 }
    201 
    202 /****************************************
    203     指定假设打印n列, 计算单行会输出的长度
    204 
    205     参数 :
    206         names : 待打印的字符串数组
    207         names_count : 待打印的字符串数组长度
    208         col_total : 打印列数
    209 
    210     return : >=0 单行输出的长度
    211 
    212 ****************************************/
    213 static unsigned int cols_count_sum(char **names, unsigned int names_count, unsigned int col_total)
    214 {
    215     unsigned int chars_count_per_line = 0;
    216     unsigned int index_col = 0;
    217     unsigned int width_each_col = 0;
    218 
    219     if (NULL == names || 0 >= names_count || 0 >= col_total) {
    220         return 0;
    221     }
    222     
    223     // 计算每列的宽度
    224     for (index_col = 0; index_col < col_total; index_col++)
    225     {
    226         width_each_col = col_len_max(names, names_count, col_total, index_col);
    227         chars_count_per_line += width_each_col;
    228         // my_print_ln("[col_total=%d]sum=%d,[%d]=%d", col_total, chars_count_per_line, index_col, width_each_col);
    229         if (0 >= width_each_col) {
    230             break;
    231         }
    232     }
    233 
    234     return chars_count_per_line;
    235 }
    236 
    237 /****************************************
    238     像ls命令那样优雅打印
    239 
    240     参数 :
    241         sockfd : 打印输出到文件描述符
    242         names : 待打印的字符串数组
    243         names_count : 待打印的字符串数组长度
    244 
    245     return : 成功返回0
    246              失败返回-1
    247 
    248 ****************************************/
    249 int print_better(int sockfd, char **names, unsigned int names_count)
    250 {
    251     last_max_len_of_line_t last = {0, 0};
    252     unsigned int chars_count_per_line = 0;
    253     int perfect_col_total = 0;  // 10 11 NOt-OK
    254     unsigned int col_total = 0;
    255     unsigned int width = 0;
    256     
    257     if (NULL == names || 0 >= names_count) {
    258         return -1;
    259     }
    260 
    261     // 0. 获取命令行宽度
    262 
    263     width = 205;
    264     // 1. 计算出最合适的列数
    265     for (col_total = 1; col_total < width; col_total++) 
    266     {
    267         chars_count_per_line = cols_count_sum(names, names_count, col_total);
    268         if (width < chars_count_per_line) {
    269             break;
    270         }
    271 
    272         if (chars_count_per_line > last.len) {
    273             last.len = chars_count_per_line;
    274             last.col_total = col_total;
    275         }
    276 
    277         // my_print_ln("==========");
    278     }
    279 
    280     perfect_col_total = (0 >= last.col_total ) ? 1 : last.col_total;
    281 
    282     // my_print_ln("perfect_col_total=%d", perfect_col_total);
    283 
    284     // 2. 打印
    285     print_list(sockfd, names, names_count, perfect_col_total);
    286 
    287     return 0;
    288 }
    289 
    290 #if TEST_THIS_FILE
    291 char *names[] = {
    292 ".",
    293 "..",
    294 "AUTHORS",
    295 "autom4te.cache",
    296 "bootstrap",
    297 "bootstrap.conf",
    298 "build-aux",
    299 "cfg.mk",
    300 "configure.ac",
    301 "COPYING",
    302 "dist-check.mk",
    303 "doc",
    304 ".git",
    305 ".gitattributes",
    306 ".github",
    307 ".gitignore",
    308 ".gitmodules",
    309 "gl",
    310 "gnulib",
    311 "gnulib-tests",
    312 "HACKING",
    313 "init.cfg",
    314 "lib",
    315 "m4",
    316 
    317 /*
    318 ".mailmap",
    319 "Makefile.am",
    320 "man",
    321 "NEWS",
    322 "po",
    323 ".prev-version",
    324 "README",
    325 "README-hacking",
    326 "README-package-renamed-to-coreutils",
    327 "README-prereq",
    328 "README-release",
    329 "README-valgrind",
    330 "scripts",
    331 "src",
    332 "tests",
    333 "thanks-gen",
    334 "THANKS.in",
    335 "THANKStt.in",
    336 "TODO",
    337 ".vg-suppressions",
    338 ".x-update-copyright",
    339 */
    340 
    341 };
    342 
    343 int main(int argc, char const *argv[])
    344 {
    345     print_better(STDIN_FILENO, names, sizeof(names) / sizeof(char *));
    346 
    347     return 0;
    348 }
    349 #endif
    rm ./a.out -f ; gcc print_better.c ; ./a.out

  • 相关阅读:
    保利尼奥离中超如肖申克救赎 没人再说人傻钱多
    Apache -- XAMPP Apache 无法启动原因及解决方法
    Android -- 工程目录解释
    正向代理和反向代理
    PHP -- 页面传值的6种获取方法
    实用小工具 -- 在线查看别人网站流量
    web前端 -- onkeydown、onkeypress、onkeyup、onblur、onchange、oninput、onpropertychange的区别
    WampServer -- “You don't have permission to access /phpmyadmin/ on this server.”
    PHP -- 字符串
    PHP -- 类和对象基础入门
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/14901218.html
Copyright © 2011-2022 走看看