aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-01-31 05:15:38 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-01-31 05:15:38 +0100
commitd8528b8e56bab7643722e4453121882d23c23c07 (patch)
treec742df066326cd571327b10d4cca3341c798d129 /coreutils
parented910c750d7908a31262488e04d38b7bf3d75322 (diff)
downloadbusybox-w32-d8528b8e56bab7643722e4453121882d23c23c07.tar.gz
busybox-w32-d8528b8e56bab7643722e4453121882d23c23c07.tar.bz2
busybox-w32-d8528b8e56bab7643722e4453121882d23c23c07.zip
ls: unicode fixes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'coreutils')
-rw-r--r--coreutils/ls.c412
1 files changed, 217 insertions, 195 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 6c898b793..d004ce8b1 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -241,9 +241,6 @@ struct dnode {
241 IF_SELINUX(security_context_t sid;) 241 IF_SELINUX(security_context_t sid;)
242}; 242};
243 243
244static struct dnode **list_dir(const char *, unsigned *);
245static unsigned list_single(const struct dnode *);
246
247struct globals { 244struct globals {
248#if ENABLE_FEATURE_LS_COLOR 245#if ENABLE_FEATURE_LS_COLOR
249 smallint show_color; 246 smallint show_color;
@@ -528,31 +525,236 @@ static void dnsort(struct dnode **dn, int size)
528#endif 525#endif
529 526
530 527
531static void showfiles(struct dnode **dn, unsigned nfiles) 528static unsigned calc_name_len(const char *name)
529{
530 unsigned len;
531 uni_stat_t uni_stat;
532
533 // TODO: quote tab as \t, etc, if -Q
534 name = printable_string(&uni_stat, name);
535
536 if (!(option_mask32 & OPT_Q)) {
537 return uni_stat.unicode_width;
538 }
539
540 len = 2 + uni_stat.unicode_width;
541 while (*name) {
542 if (*name == '"' || *name == '\\') {
543 len++;
544 }
545 name++;
546 }
547 return len;
548}
549
550
551/* Return the number of used columns.
552 * Note that only STYLE_COLUMNS uses return value.
553 * STYLE_SINGLE and STYLE_LONG don't care.
554 * coreutils 7.2 also supports:
555 * ls -b (--escape) = octal escapes (although it doesn't look like working)
556 * ls -N (--literal) = not escape at all
557 */
558static unsigned print_name(const char *name)
559{
560 unsigned len;
561 uni_stat_t uni_stat;
562
563 // TODO: quote tab as \t, etc, if -Q
564 name = printable_string(&uni_stat, name);
565
566 if (!(option_mask32 & OPT_Q)) {
567 fputs(name, stdout);
568 return uni_stat.unicode_width;
569 }
570
571 len = 2 + uni_stat.unicode_width;
572 putchar('"');
573 while (*name) {
574 if (*name == '"' || *name == '\\') {
575 putchar('\\');
576 len++;
577 }
578 putchar(*name++);
579 }
580 putchar('"');
581 return len;
582}
583
584/* Return the number of used columns.
585 * Note that only STYLE_COLUMNS uses return value,
586 * STYLE_SINGLE and STYLE_LONG don't care.
587 */
588static NOINLINE unsigned list_single(const struct dnode *dn)
532{ 589{
533 unsigned i, ncols, nrows, row, nc;
534 unsigned column = 0; 590 unsigned column = 0;
535 unsigned nexttab = 0; 591 char *lpath = lpath; /* for compiler */
536 unsigned column_width = 0; /* for STYLE_LONG and STYLE_SINGLE not used */ 592#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
593 struct stat info;
594 char append;
595#endif
537 596
538 /* Never happens: 597 /* Never happens:
539 if (dn == NULL || nfiles < 1) 598 if (dn->fullname == NULL)
540 return; 599 return 0;
541 */ 600 */
542 601
543 if (all_fmt & STYLE_LONG) { 602#if ENABLE_FEATURE_LS_FILETYPES
603 append = append_char(dn->dstat.st_mode);
604#endif
605
606 /* Do readlink early, so that if it fails, error message
607 * does not appear *inside* the "ls -l" line */
608 if (all_fmt & LIST_SYMLINK)
609 if (S_ISLNK(dn->dstat.st_mode))
610 lpath = xmalloc_readlink_or_warn(dn->fullname);
611
612 if (all_fmt & LIST_INO)
613 column += printf("%7llu ", (long long) dn->dstat.st_ino);
614 if (all_fmt & LIST_BLOCKS)
615 column += printf("%4"OFF_FMT"u ", (off_t) (dn->dstat.st_blocks >> 1));
616 if (all_fmt & LIST_MODEBITS)
617 column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
618 if (all_fmt & LIST_NLINKS)
619 column += printf("%4lu ", (long) dn->dstat.st_nlink);
620#if ENABLE_FEATURE_LS_USERNAME
621 if (all_fmt & LIST_ID_NAME) {
622 if (option_mask32 & OPT_g) {
623 column += printf("%-8.8s ",
624 get_cached_username(dn->dstat.st_uid));
625 } else {
626 column += printf("%-8.8s %-8.8s ",
627 get_cached_username(dn->dstat.st_uid),
628 get_cached_groupname(dn->dstat.st_gid));
629 }
630 }
631#endif
632 if (all_fmt & LIST_ID_NUMERIC) {
633 if (option_mask32 & OPT_g)
634 column += printf("%-8u ", (int) dn->dstat.st_uid);
635 else
636 column += printf("%-8u %-8u ",
637 (int) dn->dstat.st_uid,
638 (int) dn->dstat.st_gid);
639 }
640 if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) {
641 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
642 column += printf("%4u, %3u ",
643 (int) major(dn->dstat.st_rdev),
644 (int) minor(dn->dstat.st_rdev));
645 } else {
646 if (all_fmt & LS_DISP_HR) {
647 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ",
648 /* print st_size, show one fractional, use suffixes */
649 make_human_readable_str(dn->dstat.st_size, 1, 0)
650 );
651 } else {
652 column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size);
653 }
654 }
655 }
656#if ENABLE_FEATURE_LS_TIMESTAMPS
657 if (all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) {
658 char *filetime;
659 time_t ttime = dn->dstat.st_mtime;
660 if (all_fmt & TIME_ACCESS)
661 ttime = dn->dstat.st_atime;
662 if (all_fmt & TIME_CHANGE)
663 ttime = dn->dstat.st_ctime;
664 filetime = ctime(&ttime);
665 /* filetime's format: "Wed Jun 30 21:49:08 1993\n" */
666 if (all_fmt & LIST_FULLTIME)
667 column += printf("%.24s ", filetime);
668 else { /* LIST_DATE_TIME */
669 /* current_time_t ~== time(NULL) */
670 time_t age = current_time_t - ttime;
671 printf("%.6s ", filetime + 4); /* "Jun 30" */
672 if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
673 /* hh:mm if less than 6 months old */
674 printf("%.5s ", filetime + 11);
675 } else { /* year. buggy if year > 9999 ;) */
676 printf(" %.4s ", filetime + 20);
677 }
678 column += 13;
679 }
680 }
681#endif
682#if ENABLE_SELINUX
683 if (all_fmt & LIST_CONTEXT) {
684 column += printf("%-32s ", dn->sid ? dn->sid : "unknown");
685 freecon(dn->sid);
686 }
687#endif
688 if (all_fmt & LIST_FILENAME) {
689#if ENABLE_FEATURE_LS_COLOR
690 if (show_color) {
691 info.st_mode = 0; /* for fgcolor() */
692 lstat(dn->fullname, &info);
693 printf("\033[%u;%um", bold(info.st_mode),
694 fgcolor(info.st_mode));
695 }
696#endif
697 column += print_name(dn->name);
698 if (show_color) {
699 printf("\033[0m");
700 }
701 }
702 if (all_fmt & LIST_SYMLINK) {
703 if (S_ISLNK(dn->dstat.st_mode) && lpath) {
704 printf(" -> ");
705#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
706#if ENABLE_FEATURE_LS_COLOR
707 info.st_mode = 0; /* for fgcolor() */
708#endif
709 if (stat(dn->fullname, &info) == 0) {
710 append = append_char(info.st_mode);
711 }
712#endif
713#if ENABLE_FEATURE_LS_COLOR
714 if (show_color) {
715 printf("\033[%u;%um", bold(info.st_mode),
716 fgcolor(info.st_mode));
717 }
718#endif
719 column += print_name(lpath) + 4;
720 if (show_color) {
721 printf("\033[0m");
722 }
723 free(lpath);
724 }
725 }
726#if ENABLE_FEATURE_LS_FILETYPES
727 if (all_fmt & LIST_FILETYPE) {
728 if (append) {
729 putchar(append);
730 column++;
731 }
732 }
733#endif
734
735 return column;
736}
737
738static void showfiles(struct dnode **dn, unsigned nfiles)
739{
740 unsigned i, ncols, nrows, row, nc;
741 unsigned column = 0;
742 unsigned nexttab = 0;
743 unsigned column_width = 0; /* used only by STYLE_COLUMNS */
744
745 if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */
544 ncols = 1; 746 ncols = 1;
545 } else { 747 } else {
546 /* find the longest file name, use that as the column width */ 748 /* find the longest file name, use that as the column width */
547 for (i = 0; dn[i]; i++) { 749 for (i = 0; dn[i]; i++) {
548 int len = unicode_strlen(dn[i]->name); 750 int len = calc_name_len(dn[i]->name);
549 if (column_width < len) 751 if (column_width < len)
550 column_width = len; 752 column_width = len;
551 } 753 }
552 column_width += tabstops + 754 column_width += tabstops +
553 IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) 755 IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
554 ((all_fmt & LIST_INO) ? 8 : 0) + 756 ((all_fmt & LIST_INO) ? 8 : 0) +
555 ((all_fmt & LIST_BLOCKS) ? 5 : 0); 757 ((all_fmt & LIST_BLOCKS) ? 5 : 0);
556 ncols = (int) (terminal_width / column_width); 758 ncols = (int) (terminal_width / column_width);
557 } 759 }
558 760
@@ -618,6 +820,8 @@ static off_t calculate_blocks(struct dnode **dn)
618#endif 820#endif
619 821
620 822
823static struct dnode **list_dir(const char *, unsigned *);
824
621static void showdirs(struct dnode **dn, int first) 825static void showdirs(struct dnode **dn, int first)
622{ 826{
623 unsigned nfiles; 827 unsigned nfiles;
@@ -733,188 +937,6 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p)
733} 937}
734 938
735 939
736static int print_name(const char *name)
737{
738 if (option_mask32 & OPT_Q) {
739#if ENABLE_FEATURE_ASSUME_UNICODE
740 unsigned len = 2 + unicode_strlen(name);
741#else
742 unsigned len = 2;
743#endif
744 putchar('"');
745 while (*name) {
746 if (*name == '"') {
747 putchar('\\');
748 len++;
749 }
750 putchar(*name++);
751 if (!ENABLE_FEATURE_ASSUME_UNICODE)
752 len++;
753 }
754 putchar('"');
755 return len;
756 }
757 /* No -Q: */
758#if ENABLE_FEATURE_ASSUME_UNICODE
759 fputs(name, stdout);
760 return unicode_strlen(name);
761#else
762 return printf("%s", name);
763#endif
764}
765
766
767static NOINLINE unsigned list_single(const struct dnode *dn)
768{
769 unsigned column = 0;
770 char *lpath = lpath; /* for compiler */
771#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
772 struct stat info;
773 char append;
774#endif
775
776 /* Never happens:
777 if (dn->fullname == NULL)
778 return 0;
779 */
780
781#if ENABLE_FEATURE_LS_FILETYPES
782 append = append_char(dn->dstat.st_mode);
783#endif
784
785 /* Do readlink early, so that if it fails, error message
786 * does not appear *inside* the "ls -l" line */
787 if (all_fmt & LIST_SYMLINK)
788 if (S_ISLNK(dn->dstat.st_mode))
789 lpath = xmalloc_readlink_or_warn(dn->fullname);
790
791 if (all_fmt & LIST_INO)
792 column += printf("%7llu ", (long long) dn->dstat.st_ino);
793 if (all_fmt & LIST_BLOCKS)
794 column += printf("%4"OFF_FMT"u ", (off_t) (dn->dstat.st_blocks >> 1));
795 if (all_fmt & LIST_MODEBITS)
796 column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
797 if (all_fmt & LIST_NLINKS)
798 column += printf("%4lu ", (long) dn->dstat.st_nlink);
799#if ENABLE_FEATURE_LS_USERNAME
800 if (all_fmt & LIST_ID_NAME) {
801 if (option_mask32 & OPT_g) {
802 column += printf("%-8.8s ",
803 get_cached_username(dn->dstat.st_uid));
804 } else {
805 column += printf("%-8.8s %-8.8s ",
806 get_cached_username(dn->dstat.st_uid),
807 get_cached_groupname(dn->dstat.st_gid));
808 }
809 }
810#endif
811 if (all_fmt & LIST_ID_NUMERIC) {
812 if (option_mask32 & OPT_g)
813 column += printf("%-8u ", (int) dn->dstat.st_uid);
814 else
815 column += printf("%-8u %-8u ",
816 (int) dn->dstat.st_uid,
817 (int) dn->dstat.st_gid);
818 }
819 if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) {
820 if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
821 column += printf("%4u, %3u ",
822 (int) major(dn->dstat.st_rdev),
823 (int) minor(dn->dstat.st_rdev));
824 } else {
825 if (all_fmt & LS_DISP_HR) {
826 column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ",
827 /* print st_size, show one fractional, use suffixes */
828 make_human_readable_str(dn->dstat.st_size, 1, 0)
829 );
830 } else {
831 column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size);
832 }
833 }
834 }
835#if ENABLE_FEATURE_LS_TIMESTAMPS
836 if (all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) {
837 char *filetime;
838 time_t ttime = dn->dstat.st_mtime;
839 if (all_fmt & TIME_ACCESS)
840 ttime = dn->dstat.st_atime;
841 if (all_fmt & TIME_CHANGE)
842 ttime = dn->dstat.st_ctime;
843 filetime = ctime(&ttime);
844 /* filetime's format: "Wed Jun 30 21:49:08 1993\n" */
845 if (all_fmt & LIST_FULLTIME)
846 column += printf("%.24s ", filetime);
847 else { /* LIST_DATE_TIME */
848 /* current_time_t ~== time(NULL) */
849 time_t age = current_time_t - ttime;
850 printf("%.6s ", filetime + 4); /* "Jun 30" */
851 if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
852 /* hh:mm if less than 6 months old */
853 printf("%.5s ", filetime + 11);
854 } else { /* year. buggy if year > 9999 ;) */
855 printf(" %.4s ", filetime + 20);
856 }
857 column += 13;
858 }
859 }
860#endif
861#if ENABLE_SELINUX
862 if (all_fmt & LIST_CONTEXT) {
863 column += printf("%-32s ", dn->sid ? dn->sid : "unknown");
864 freecon(dn->sid);
865 }
866#endif
867 if (all_fmt & LIST_FILENAME) {
868#if ENABLE_FEATURE_LS_COLOR
869 if (show_color) {
870 info.st_mode = 0; /* for fgcolor() */
871 lstat(dn->fullname, &info);
872 printf("\033[%u;%um", bold(info.st_mode),
873 fgcolor(info.st_mode));
874 }
875#endif
876 column += print_name(dn->name);
877 if (show_color) {
878 printf("\033[0m");
879 }
880 }
881 if (all_fmt & LIST_SYMLINK) {
882 if (S_ISLNK(dn->dstat.st_mode) && lpath) {
883 printf(" -> ");
884#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
885#if ENABLE_FEATURE_LS_COLOR
886 info.st_mode = 0; /* for fgcolor() */
887#endif
888 if (stat(dn->fullname, &info) == 0) {
889 append = append_char(info.st_mode);
890 }
891#endif
892#if ENABLE_FEATURE_LS_COLOR
893 if (show_color) {
894 printf("\033[%u;%um", bold(info.st_mode),
895 fgcolor(info.st_mode));
896 }
897#endif
898 column += print_name(lpath) + 4;
899 if (show_color) {
900 printf("\033[0m");
901 }
902 free(lpath);
903 }
904 }
905#if ENABLE_FEATURE_LS_FILETYPES
906 if (all_fmt & LIST_FILETYPE) {
907 if (append) {
908 putchar(append);
909 column++;
910 }
911 }
912#endif
913
914 return column;
915}
916
917
918int ls_main(int argc UNUSED_PARAM, char **argv) 940int ls_main(int argc UNUSED_PARAM, char **argv)
919{ 941{
920 struct dnode **dnd; 942 struct dnode **dnd;