diff --git a/.gitignore b/.gitignore index 46d0f92..de62e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ /coreutils-[0-9.]*.tar.xz -/coreutils-[0-9.]*.tar.xz.sig diff --git a/coreutils-4.5.3-langinfo.patch b/coreutils-4.5.3-langinfo.patch new file mode 100644 index 0000000..a8af3bd --- /dev/null +++ b/coreutils-4.5.3-langinfo.patch @@ -0,0 +1,20 @@ +diff --git a/src/date.c b/src/date.c +index ddb011e..619a72b 100644 +--- a/src/date.c ++++ b/src/date.c +@@ -490,14 +490,7 @@ main (int argc, char **argv) + format = DATE_FMT_LANGINFO (); + if (! *format) + { +- /* Do not wrap the following literal format string with _(...). +- For example, suppose LC_ALL is unset, LC_TIME=POSIX, +- and LANG="ko_KR". In that case, POSIX says that LC_TIME +- determines the format and contents of date and time strings +- written by date, which means "date" must generate output +- using the POSIX locale; but adding _() would cause "date" +- to use a Korean translation of the format. */ +- format = "%a %b %e %H:%M:%S %Z %Y"; ++ format = dcgettext(NULL, N_("%a %b %e %H:%M:%S %Z %Y"), LC_TIME); + } + } + diff --git a/coreutils-6.10-manpages.patch b/coreutils-6.10-manpages.patch new file mode 100644 index 0000000..5f8bdb2 --- /dev/null +++ b/coreutils-6.10-manpages.patch @@ -0,0 +1,14 @@ +diff --git a/src/md5sum.c b/src/md5sum.c +index 8e21609..a857d62 100644 +--- a/src/md5sum.c ++++ b/src/md5sum.c +@@ -266,6 +266,9 @@ Print or check %s (%d-bit) checksums.\n\ + fputs (_("\ + -t, --text read in text mode (default)\n\ + "), stdout); ++ fputs (_("\ ++ Note: There is no difference between binary and text mode option on GNU system.\n\ ++"), stdout); + fputs (_("\ + \n\ + The following five options are useful only when verifying checksums:\n\ diff --git a/coreutils-8.2-uname-processortype.patch b/coreutils-8.2-uname-processortype.patch new file mode 100644 index 0000000..ed01ab8 --- /dev/null +++ b/coreutils-8.2-uname-processortype.patch @@ -0,0 +1,49 @@ +diff --git a/src/uname.c b/src/uname.c +index 6371ca2..1ad8fd7 100644 +--- a/src/uname.c ++++ b/src/uname.c +@@ -300,13 +300,19 @@ main (int argc, char **argv) + + if (toprint & PRINT_PROCESSOR) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_ARCHITECTURE + { + static char processor[257]; + if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor)) + element = processor; + } ++#else ++ { ++ static struct utsname u; ++ uname(&u); ++ element = u.machine; ++ } + #endif + #ifdef UNAME_PROCESSOR + if (element == unknown) +@@ -344,7 +350,7 @@ main (int argc, char **argv) + + if (toprint & PRINT_HARDWARE_PLATFORM) + { +- char const *element = unknown; ++ char *element = unknown; + #if HAVE_SYSINFO && defined SI_PLATFORM + { + static char hardware_platform[257]; +@@ -352,6 +358,14 @@ main (int argc, char **argv) + hardware_platform, sizeof hardware_platform)) + element = hardware_platform; + } ++#else ++ { ++ static struct utsname u; ++ uname(&u); ++ element = u.machine; ++ if(strlen(element)==4 && element[0]=='i' && element[2]=='8' && element[3]=='6') ++ element[1]='3'; ++ } + #endif + #ifdef UNAME_HARDWARE_PLATFORM + if (element == unknown) diff --git a/coreutils-8.25-DIR_COLORS.patch b/coreutils-8.25-DIR_COLORS.patch new file mode 100644 index 0000000..94923b0 --- /dev/null +++ b/coreutils-8.25-DIR_COLORS.patch @@ -0,0 +1,692 @@ +From a13bc34f1eeebdf8b87e4b5a570341bb77a62f76 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 17 Jun 2016 16:58:18 +0200 +Subject: [PATCH] downstream changes to default DIR_COLORS + +--- + DIR_COLORS | 41 ++++--- + DIR_COLORS.256color | 302 ++++++++++++++++++++++++------------------------ + DIR_COLORS.lightbgcolor | 215 +++++++++++++++++----------------- + 3 files changed, 286 insertions(+), 272 deletions(-) + +diff --git a/DIR_COLORS b/DIR_COLORS +index d2ea453..27af9d7 100644 +--- a/DIR_COLORS ++++ b/DIR_COLORS +@@ -1,6 +1,10 @@ + # Configuration file for dircolors, a utility to help you set the + # LS_COLORS environment variable used by GNU ls with the --color option. + ++# This file goes in the /etc directory, and must be world readable. ++# You can copy this file to .dir_colors in your $HOME directory to override ++# the system defaults. ++ + # Copyright (C) 1996-2017 Free Software Foundation, Inc. + # Copying and distribution of this file, with or without modification, + # are permitted provided the copyright notice and this notice are preserved. +@@ -8,6 +12,9 @@ + # The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the + # slackware version of dircolors) are recognized but ignored. + ++# For compatibility, the pattern "^COLOR.*none" is recognized as a way to ++# disable colorization. See https://bugzilla.redhat.com/1349579 for details. ++ + # Below are TERM entries, which can be a glob patterns, to match + # against the TERM environment variable to determine if it is colorizable. + TERM Eterm +@@ -56,7 +63,7 @@ DOOR 01;35 # door + BLK 40;33;01 # block device driver + CHR 40;33;01 # character device driver + ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... +-MISSING 00 # ... and the files they point to ++MISSING 01;05;37;41 # ... and the files they point to + SETUID 37;41 # file that is setuid (u+s) + SETGID 30;43 # file that is setgid (g+s) + CAPABILITY 30;41 # file with capability +@@ -185,21 +192,21 @@ EXEC 01;32 + .ogx 01;35 + + # audio formats +-.aac 00;36 +-.au 00;36 +-.flac 00;36 +-.m4a 00;36 +-.mid 00;36 +-.midi 00;36 +-.mka 00;36 +-.mp3 00;36 +-.mpc 00;36 +-.ogg 00;36 +-.ra 00;36 +-.wav 00;36 ++.aac 01;36 ++.au 01;36 ++.flac 01;36 ++.m4a 01;36 ++.mid 01;36 ++.midi 01;36 ++.mka 01;36 ++.mp3 01;36 ++.mpc 01;36 ++.ogg 01;36 ++.ra 01;36 ++.wav 01;36 + + # https://wiki.xiph.org/MIME_Types_and_File_Extensions +-.oga 00;36 +-.opus 00;36 +-.spx 00;36 +-.xspf 00;36 ++.oga 01;36 ++.opus 01;36 ++.spx 01;36 ++.xspf 01;36 +diff --git a/DIR_COLORS.256color b/DIR_COLORS.256color +index d2ea453..74c34ba 100644 +--- a/DIR_COLORS.256color ++++ b/DIR_COLORS.256color +@@ -1,3 +1,9 @@ ++# Configuration file for the 256color ls utility ++ ++# This file goes in the /etc directory, and must be world readable. ++# You can copy this file to .dir_colors in your $HOME directory to override ++# the system defaults. ++ + # Configuration file for dircolors, a utility to help you set the + # LS_COLORS environment variable used by GNU ls with the --color option. + +@@ -8,32 +14,13 @@ + # The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the + # slackware version of dircolors) are recognized but ignored. + ++# For compatibility, the pattern "^COLOR.*none" is recognized as a way to ++# disable colorization. See https://bugzilla.redhat.com/1349579 for details. ++ + # Below are TERM entries, which can be a glob patterns, to match + # against the TERM environment variable to determine if it is colorizable. +-TERM Eterm +-TERM ansi +-TERM *color* +-TERM con[0-9]*x[0-9]* +-TERM cons25 +-TERM console +-TERM cygwin +-TERM dtterm +-TERM gnome +-TERM hurd +-TERM jfbterm +-TERM konsole +-TERM kterm +-TERM linux +-TERM linux-c +-TERM mlterm +-TERM putty +-TERM rxvt* +-TERM screen* +-TERM st +-TERM terminator +-TERM tmux* +-TERM vt100 +-TERM xterm* ++TERM *256color* ++TERM rxvt-unicode256 + + # Below are the color init strings for the basic file types. A color init + # string consists of one or more of the following numeric codes: +@@ -43,29 +30,40 @@ TERM xterm* + # 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white + # Background color codes: + # 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white ++# Text color(256 colors mode) codes: ++# Valid syntax for text 256color is 38;5; , where color number ++# is number between 0 and 255. ++# You may find following command useful to search the best one for you: ++# for ((x=0; x<=255; x++));do echo -e "${x}:\033[38;5;${x}mcolor\033[000m";done ++# Background color(256 colors mode) codes: ++# Valid syntax for background 256color is 48;5; , where ++# color number is number between 0 and 255. ++# You may find following command useful to search the best one for you: ++# for ((x=0; x<=255; x++));do echo -e "${x}:\033[48;5;${x}mcolor\033[000m";done ++ + #NORMAL 00 # no color code at all + #FILE 00 # regular file: use no color at all + RESET 0 # reset to "normal" color +-DIR 01;34 # directory +-LINK 01;36 # symbolic link. (If you set this to 'target' instead of a ++DIR 38;5;33 # directory ++LINK 38;5;51 # symbolic link. (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) + MULTIHARDLINK 00 # regular file with more than one link +-FIFO 40;33 # pipe +-SOCK 01;35 # socket +-DOOR 01;35 # door +-BLK 40;33;01 # block device driver +-CHR 40;33;01 # character device driver +-ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... +-MISSING 00 # ... and the files they point to +-SETUID 37;41 # file that is setuid (u+s) +-SETGID 30;43 # file that is setgid (g+s) +-CAPABILITY 30;41 # file with capability +-STICKY_OTHER_WRITABLE 30;42 # dir that is sticky and other-writable (+t,o+w) +-OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky +-STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable ++FIFO 40;38;5;11 # pipe ++SOCK 38;5;13 # socket ++DOOR 38;5;5 # door ++BLK 48;5;232;38;5;11 # block device driver ++CHR 48;5;232;38;5;3 # character device driver ++ORPHAN 48;5;232;38;5;9 # symlink to nonexistent file, or non-stat'able file ... ++MISSING 01;05;37;41 # ... and the files they point to ++SETUID 48;5;196;38;5;15 # file that is setuid (u+s) ++SETGID 48;5;11;38;5;16 # file that is setgid (g+s) ++CAPABILITY 48;5;196;38;5;226 # file with capability ++STICKY_OTHER_WRITABLE 48;5;10;38;5;16 # dir that is sticky and other-writable (+t,o+w) ++OTHER_WRITABLE 48;5;10;38;5;21 # dir that is other-writable (o+w) and not sticky ++STICKY 48;5;21;38;5;15 # dir with the sticky bit set (+t) and not other-writable + + # This is for files with execute permission: +-EXEC 01;32 ++EXEC 38;5;40 + + # List any file extensions like '.gz' or '.tar' that you would like ls + # to colorize below. Put the extension, a space, and the color init string. +@@ -83,123 +81,123 @@ EXEC 01;32 + #.csh 01;32 + + # archives or compressed (bright red) +-.tar 01;31 +-.tgz 01;31 +-.arc 01;31 +-.arj 01;31 +-.taz 01;31 +-.lha 01;31 +-.lz4 01;31 +-.lzh 01;31 +-.lzma 01;31 +-.tlz 01;31 +-.txz 01;31 +-.tzo 01;31 +-.t7z 01;31 +-.zip 01;31 +-.z 01;31 +-.Z 01;31 +-.dz 01;31 +-.gz 01;31 +-.lrz 01;31 +-.lz 01;31 +-.lzo 01;31 +-.xz 01;31 +-.zst 01;31 +-.tzst 01;31 +-.bz2 01;31 +-.bz 01;31 +-.tbz 01;31 +-.tbz2 01;31 +-.tz 01;31 +-.deb 01;31 +-.rpm 01;31 +-.jar 01;31 +-.war 01;31 +-.ear 01;31 +-.sar 01;31 +-.rar 01;31 +-.alz 01;31 +-.ace 01;31 +-.zoo 01;31 +-.cpio 01;31 +-.7z 01;31 +-.rz 01;31 +-.cab 01;31 +-.wim 01;31 +-.swm 01;31 +-.dwm 01;31 +-.esd 01;31 ++.tar 38;5;9 ++.tgz 38;5;9 ++.arc 38;5;9 ++.arj 38;5;9 ++.taz 38;5;9 ++.lha 38;5;9 ++.lz4 38;5;9 ++.lzh 38;5;9 ++.lzma 38;5;9 ++.tlz 38;5;9 ++.txz 38;5;9 ++.tzo 38;5;9 ++.t7z 38;5;9 ++.zip 38;5;9 ++.z 38;5;9 ++.Z 38;5;9 ++.dz 38;5;9 ++.gz 38;5;9 ++.lrz 38;5;9 ++.lz 38;5;9 ++.lzo 38;5;9 ++.xz 38;5;9 ++.zst 38;5;9 ++.tzst 38;5;9 ++.bz2 38;5;9 ++.bz 38;5;9 ++.tbz 38;5;9 ++.tbz2 38;5;9 ++.tz 38;5;9 ++.deb 38;5;9 ++.rpm 38;5;9 ++.jar 38;5;9 ++.war 38;5;9 ++.ear 38;5;9 ++.sar 38;5;9 ++.rar 38;5;9 ++.alz 38;5;9 ++.ace 38;5;9 ++.zoo 38;5;9 ++.cpio 38;5;9 ++.7z 38;5;9 ++.rz 38;5;9 ++.cab 38;5;9 ++.wim 38;5;9 ++.swm 38;5;9 ++.dwm 38;5;9 ++.esd 38;5;9 + + # image formats +-.jpg 01;35 +-.jpeg 01;35 +-.mjpg 01;35 +-.mjpeg 01;35 +-.gif 01;35 +-.bmp 01;35 +-.pbm 01;35 +-.pgm 01;35 +-.ppm 01;35 +-.tga 01;35 +-.xbm 01;35 +-.xpm 01;35 +-.tif 01;35 +-.tiff 01;35 +-.png 01;35 +-.svg 01;35 +-.svgz 01;35 +-.mng 01;35 +-.pcx 01;35 +-.mov 01;35 +-.mpg 01;35 +-.mpeg 01;35 +-.m2v 01;35 +-.mkv 01;35 +-.webm 01;35 +-.ogm 01;35 +-.mp4 01;35 +-.m4v 01;35 +-.mp4v 01;35 +-.vob 01;35 +-.qt 01;35 +-.nuv 01;35 +-.wmv 01;35 +-.asf 01;35 +-.rm 01;35 +-.rmvb 01;35 +-.flc 01;35 +-.avi 01;35 +-.fli 01;35 +-.flv 01;35 +-.gl 01;35 +-.dl 01;35 +-.xcf 01;35 +-.xwd 01;35 +-.yuv 01;35 +-.cgm 01;35 +-.emf 01;35 ++.jpg 38;5;13 ++.jpeg 38;5;13 ++.mjpg 38;5;13 ++.mjpeg 38;5;13 ++.gif 38;5;13 ++.bmp 38;5;13 ++.pbm 38;5;13 ++.pgm 38;5;13 ++.ppm 38;5;13 ++.tga 38;5;13 ++.xbm 38;5;13 ++.xpm 38;5;13 ++.tif 38;5;13 ++.tiff 38;5;13 ++.png 38;5;13 ++.svg 38;5;13 ++.svgz 38;5;13 ++.mng 38;5;13 ++.pcx 38;5;13 ++.mov 38;5;13 ++.mpg 38;5;13 ++.mpeg 38;5;13 ++.m2v 38;5;13 ++.mkv 38;5;13 ++.webm 38;5;13 ++.ogm 38;5;13 ++.mp4 38;5;13 ++.m4v 38;5;13 ++.mp4v 38;5;13 ++.vob 38;5;13 ++.qt 38;5;13 ++.nuv 38;5;13 ++.wmv 38;5;13 ++.asf 38;5;13 ++.rm 38;5;13 ++.rmvb 38;5;13 ++.flc 38;5;13 ++.avi 38;5;13 ++.fli 38;5;13 ++.flv 38;5;13 ++.gl 38;5;13 ++.dl 38;5;13 ++.xcf 38;5;13 ++.xwd 38;5;13 ++.yuv 38;5;13 ++.cgm 38;5;13 ++.emf 38;5;13 + + # https://wiki.xiph.org/MIME_Types_and_File_Extensions +-.ogv 01;35 +-.ogx 01;35 ++.ogv 38;5;13 ++.ogx 38;5;13 + + # audio formats +-.aac 00;36 +-.au 00;36 +-.flac 00;36 +-.m4a 00;36 +-.mid 00;36 +-.midi 00;36 +-.mka 00;36 +-.mp3 00;36 +-.mpc 00;36 +-.ogg 00;36 +-.ra 00;36 +-.wav 00;36 ++.aac 38;5;45 ++.au 38;5;45 ++.flac 38;5;45 ++.m4a 38;5;45 ++.mid 38;5;45 ++.midi 38;5;45 ++.mka 38;5;45 ++.mp3 38;5;45 ++.mpc 38;5;45 ++.ogg 38;5;45 ++.ra 38;5;45 ++.wav 38;5;45 + + # https://wiki.xiph.org/MIME_Types_and_File_Extensions +-.oga 00;36 +-.opus 00;36 +-.spx 00;36 +-.xspf 00;36 ++.oga 38;5;45 ++.opus 38;5;45 ++.spx 38;5;45 ++.xspf 38;5;45 +diff --git a/DIR_COLORS.lightbgcolor b/DIR_COLORS.lightbgcolor +index d2ea453..95d6879 100644 +--- a/DIR_COLORS.lightbgcolor ++++ b/DIR_COLORS.lightbgcolor +@@ -1,3 +1,9 @@ ++# Configuration file for the color ls utility - modified for lighter backgrounds ++ ++# This file goes in the /etc directory, and must be world readable. ++# You can copy this file to .dir_colors in your $HOME directory to override ++# the system defaults. ++ + # Configuration file for dircolors, a utility to help you set the + # LS_COLORS environment variable used by GNU ls with the --color option. + +@@ -8,6 +14,9 @@ + # The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the + # slackware version of dircolors) are recognized but ignored. + ++# For compatibility, the pattern "^COLOR.*none" is recognized as a way to ++# disable colorization. See https://bugzilla.redhat.com/1349579 for details. ++ + # Below are TERM entries, which can be a glob patterns, to match + # against the TERM environment variable to determine if it is colorizable. + TERM Eterm +@@ -46,17 +55,17 @@ TERM xterm* + #NORMAL 00 # no color code at all + #FILE 00 # regular file: use no color at all + RESET 0 # reset to "normal" color +-DIR 01;34 # directory +-LINK 01;36 # symbolic link. (If you set this to 'target' instead of a ++DIR 00;34 # directory ++LINK 00;36 # symbolic link. (If you set this to 'target' instead of a + # numerical value, the color is as for the file pointed to.) + MULTIHARDLINK 00 # regular file with more than one link + FIFO 40;33 # pipe +-SOCK 01;35 # socket +-DOOR 01;35 # door ++SOCK 00;35 # socket ++DOOR 00;35 # door + BLK 40;33;01 # block device driver + CHR 40;33;01 # character device driver + ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... +-MISSING 00 # ... and the files they point to ++MISSING 01;05;37;41 # ... and the files they point to + SETUID 37;41 # file that is setuid (u+s) + SETGID 30;43 # file that is setgid (g+s) + CAPABILITY 30;41 # file with capability +@@ -65,7 +74,7 @@ OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky + STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable + + # This is for files with execute permission: +-EXEC 01;32 ++EXEC 00;32 + + # List any file extensions like '.gz' or '.tar' that you would like ls + # to colorize below. Put the extension, a space, and the color init string. +@@ -82,107 +91,107 @@ EXEC 01;32 + #.sh 01;32 + #.csh 01;32 + +- # archives or compressed (bright red) +-.tar 01;31 +-.tgz 01;31 +-.arc 01;31 +-.arj 01;31 +-.taz 01;31 +-.lha 01;31 +-.lz4 01;31 +-.lzh 01;31 +-.lzma 01;31 +-.tlz 01;31 +-.txz 01;31 +-.tzo 01;31 +-.t7z 01;31 +-.zip 01;31 +-.z 01;31 +-.Z 01;31 +-.dz 01;31 +-.gz 01;31 +-.lrz 01;31 +-.lz 01;31 +-.lzo 01;31 +-.xz 01;31 +-.zst 01;31 +-.tzst 01;31 +-.bz2 01;31 +-.bz 01;31 +-.tbz 01;31 +-.tbz2 01;31 +-.tz 01;31 +-.deb 01;31 +-.rpm 01;31 +-.jar 01;31 +-.war 01;31 +-.ear 01;31 +-.sar 01;31 +-.rar 01;31 +-.alz 01;31 +-.ace 01;31 +-.zoo 01;31 +-.cpio 01;31 +-.7z 01;31 +-.rz 01;31 +-.cab 01;31 +-.wim 01;31 +-.swm 01;31 +-.dwm 01;31 +-.esd 01;31 ++# archives or compressed (red) ++.tar 00;31 ++.tgz 00;31 ++.arc 00;31 ++.arj 00;31 ++.taz 00;31 ++.lha 00;31 ++.lz4 00;31 ++.lzh 00;31 ++.lzma 00;31 ++.tlz 00;31 ++.txz 00;31 ++.tzo 00;31 ++.t7z 00;31 ++.zip 00;31 ++.z 00;31 ++.Z 00;31 ++.dz 00;31 ++.gz 00;31 ++.lrz 00;31 ++.lz 00;31 ++.lzo 00;31 ++.xz 00;31 ++.zst 00;31 ++.tzst 00;31 ++.bz2 00;31 ++.bz 00;31 ++.tbz 00;31 ++.tbz2 00;31 ++.tz 00;31 ++.deb 00;31 ++.rpm 00;31 ++.jar 00;31 ++.war 00;31 ++.ear 00;31 ++.sar 00;31 ++.rar 00;31 ++.alz 00;31 ++.ace 00;31 ++.zoo 00;31 ++.cpio 00;31 ++.7z 00;31 ++.rz 00;31 ++.cab 00;31 ++.wim 00;31 ++.swm 00;31 ++.dwm 00;31 ++.esd 00;31 + + # image formats +-.jpg 01;35 +-.jpeg 01;35 +-.mjpg 01;35 +-.mjpeg 01;35 +-.gif 01;35 +-.bmp 01;35 +-.pbm 01;35 +-.pgm 01;35 +-.ppm 01;35 +-.tga 01;35 +-.xbm 01;35 +-.xpm 01;35 +-.tif 01;35 +-.tiff 01;35 +-.png 01;35 +-.svg 01;35 +-.svgz 01;35 +-.mng 01;35 +-.pcx 01;35 +-.mov 01;35 +-.mpg 01;35 +-.mpeg 01;35 +-.m2v 01;35 +-.mkv 01;35 +-.webm 01;35 +-.ogm 01;35 +-.mp4 01;35 +-.m4v 01;35 +-.mp4v 01;35 +-.vob 01;35 +-.qt 01;35 +-.nuv 01;35 +-.wmv 01;35 +-.asf 01;35 +-.rm 01;35 +-.rmvb 01;35 +-.flc 01;35 +-.avi 01;35 +-.fli 01;35 +-.flv 01;35 +-.gl 01;35 +-.dl 01;35 +-.xcf 01;35 +-.xwd 01;35 +-.yuv 01;35 +-.cgm 01;35 +-.emf 01;35 ++.jpg 00;35 ++.jpeg 00;35 ++.mjpg 00;35 ++.mjpeg 00;35 ++.gif 00;35 ++.bmp 00;35 ++.pbm 00;35 ++.pgm 00;35 ++.ppm 00;35 ++.tga 00;35 ++.xbm 00;35 ++.xpm 00;35 ++.tif 00;35 ++.tiff 00;35 ++.png 00;35 ++.svg 00;35 ++.svgz 00;35 ++.mng 00;35 ++.pcx 00;35 ++.mov 00;35 ++.mpg 00;35 ++.mpeg 00;35 ++.m2v 00;35 ++.mkv 00;35 ++.webm 00;35 ++.ogm 00;35 ++.mp4 00;35 ++.m4v 00;35 ++.mp4v 00;35 ++.vob 00;35 ++.qt 00;35 ++.nuv 00;35 ++.wmv 00;35 ++.asf 00;35 ++.rm 00;35 ++.rmvb 00;35 ++.flc 00;35 ++.avi 00;35 ++.fli 00;35 ++.flv 00;35 ++.gl 00;35 ++.dl 00;35 ++.xcf 00;35 ++.xwd 00;35 ++.yuv 00;35 ++.cgm 00;35 ++.emf 00;35 + + # https://wiki.xiph.org/MIME_Types_and_File_Extensions +-.ogv 01;35 +-.ogx 01;35 ++.ogv 00;35 ++.ogx 00;35 + + # audio formats + .aac 00;36 +-- +2.5.5 + diff --git a/coreutils-8.26-selinuxenable.patch b/coreutils-8.26-selinuxenable.patch deleted file mode 100644 index d9b625a..0000000 --- a/coreutils-8.26-selinuxenable.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 6880c3dc9098b3337612850d1500b474aeb944ca Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Tue, 29 Aug 2017 17:33:51 +0200 -Subject: [PATCH] require_selinux_(): use selinuxenabled(8) if available - ---- - init.cfg | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/init.cfg b/init.cfg -index af6b581..f887b3a 100644 ---- a/init.cfg -+++ b/init.cfg -@@ -114,6 +114,9 @@ require_selinux_() - grep 'selinuxfs$' /proc/filesystems > /dev/null \ - || skip_ "this system lacks SELinux support" - -+ # use the 'selinuxenabled' utility if available -+ selinuxenabled; [ $? = 1 ] && skip_ "SELinux is disabled" -+ - # Independent of whether SELinux is enabled system-wide, - # the current file system may lack SELinux support. - # Also the current build may have SELinux support disabled. --- -2.9.5 - diff --git a/coreutils-8.27-CVE-2017-7476.patch b/coreutils-8.27-CVE-2017-7476.patch new file mode 100644 index 0000000..23fdb3f --- /dev/null +++ b/coreutils-8.27-CVE-2017-7476.patch @@ -0,0 +1,189 @@ +From fc286e2b3af5b2ed9aec44b520265bb0968f1660 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Mon, 24 Apr 2017 01:43:36 -0700 +Subject: [PATCH 1/2] time_rz: fix heap buffer overflow vulnerability + +This issue has been assigned CVE-2017-7476 and was +detected with American Fuzzy Lop 2.41b run on the +coreutils date(1) program with ASAN enabled. + + ERROR: AddressSanitizer: heap-buffer-overflow on address 0x... + WRITE of size 8 at 0x60d00000cff8 thread T0 + #1 0x443020 in extend_abbrs lib/time_rz.c:88 + #2 0x443356 in save_abbr lib/time_rz.c:155 + #3 0x44393f in localtime_rz lib/time_rz.c:290 + #4 0x41e4fe in parse_datetime2 lib/parse-datetime.y:1798 + +A minimized reproducer is the following 120 byte TZ value, +which goes beyond the value of ABBR_SIZE_MIN (119) on x86_64. +Extend the aa...b portion to overwrite more of the heap. + + date -d $(printf 'TZ="aaa%020daaaaaab%089d"') + +localtime_rz and mktime_z were affected since commit 4bc76593. +parse_datetime was affected since commit 4e6e16b3f. + +* lib/time_rz.c (save_abbr): Rearrange the calculation determining +whether there is enough buffer space available. The rearrangement +ensures we're only dealing with positive numbers, thus avoiding +the problematic promotion of signed to unsigned causing an invalid +comparison when zone_copy is more than ABBR_SIZE_MIN bytes beyond +the start of the buffer. +* tests/test-parse-datetime.c (main): Add a test case written by +Paul Eggert, which overwrites enough of the heap so that +standard glibc will fail with "free(): invalid pointer" +without the patch applied. +Reported and analyzed at https://bugzilla.redhat.com/1444774 + +Upstream-commit: 94e01571507835ff59dd8ce2a0b56a4b566965a4 +Signed-off-by: Kamil Dudka +--- + gnulib-tests/test-parse-datetime.c | 16 ++++++++++++++++ + lib/time_rz.c | 15 +++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/gnulib-tests/test-parse-datetime.c b/gnulib-tests/test-parse-datetime.c +index b42a51c..b6fe457 100644 +--- a/gnulib-tests/test-parse-datetime.c ++++ b/gnulib-tests/test-parse-datetime.c +@@ -432,5 +432,21 @@ main (int argc _GL_UNUSED, char **argv) + ASSERT ( parse_datetime (&result, "TZ=\"\\\\\"", &now)); + ASSERT ( parse_datetime (&result, "TZ=\"\\\"\"", &now)); + ++ /* Outlandishly-long time zone abbreviations should not cause problems. */ ++ { ++ static char const bufprefix[] = "TZ=\""; ++ enum { tzname_len = 2000 }; ++ static char const bufsuffix[] = "0\" 1970-01-01 01:02:03.123456789"; ++ enum { bufsize = sizeof bufprefix - 1 + tzname_len + sizeof bufsuffix }; ++ char buf[bufsize]; ++ memcpy (buf, bufprefix, sizeof bufprefix - 1); ++ memset (buf + sizeof bufprefix - 1, 'X', tzname_len); ++ strcpy (buf + bufsize - sizeof bufsuffix, bufsuffix); ++ ASSERT (parse_datetime (&result, buf, &now)); ++ LOG (buf, now, result); ++ ASSERT (result.tv_sec == 1 * 60 * 60 + 2 * 60 + 3 ++ && result.tv_nsec == 123456789); ++ } ++ + return 0; + } +diff --git a/lib/time_rz.c b/lib/time_rz.c +index adb9c1c..c41a8ef 100644 +--- a/lib/time_rz.c ++++ b/lib/time_rz.c +@@ -27,6 +27,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -35,6 +36,10 @@ + #include "flexmember.h" + #include "time-internal.h" + ++#ifndef SIZE_MAX ++# define SIZE_MAX ((size_t) -1) ++#endif ++ + #if !HAVE_TZSET + static void tzset (void) { } + #endif +@@ -43,7 +48,7 @@ static void tzset (void) { } + the largest "small" request for the GNU C library malloc. */ + enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 }; + +-/* Minimum size of the ABBRS member of struct abbr. ABBRS is larger ++/* Minimum size of the ABBRS member of struct tm_zone. ABBRS is larger + only in the unlikely case where an abbreviation longer than this is + used. */ + enum { ABBR_SIZE_MIN = DEFAULT_MXFAST - offsetof (struct tm_zone, abbrs) }; +@@ -150,7 +155,13 @@ save_abbr (timezone_t tz, struct tm *tm) + if (! (*zone_copy || (zone_copy == tz->abbrs && tz->tz_is_set))) + { + size_t zone_size = strlen (zone) + 1; +- if (zone_size < tz->abbrs + ABBR_SIZE_MIN - zone_copy) ++ size_t zone_used = zone_copy - tz->abbrs; ++ if (SIZE_MAX - zone_used < zone_size) ++ { ++ errno = ENOMEM; ++ return false; ++ } ++ if (zone_used + zone_size < ABBR_SIZE_MIN) + extend_abbrs (zone_copy, zone, zone_size); + else + { +-- +2.9.3 + + +From 9579f90484c71e5a22f32f35189192a82e47550e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Wed, 26 Apr 2017 20:51:39 -0700 +Subject: [PATCH 2/2] date,touch: test and document large TZ security issue + +Add a test for CVE-2017-7476 which was fixed in gnulib at: +http://git.sv.gnu.org/gitweb/?p=gnulib.git;a=commitdiff;h=94e01571 + +* tests/misc/date-tz.sh: Add a new test which overwrites enough +of the heap to trigger a segfault, even without ASAN enabled. +* tests/local.mk: Reference the new test. +* NEWS: Mention the bug fix. + +Upstream-commit: 9287ef2b1707e2a222f8ae776ce3785abcb16fba +Signed-off-by: Kamil Dudka +--- + tests/local.mk | 1 + + tests/misc/date-tz.sh | 26 ++++++++++++++++++++++++++ + 2 files changed, 27 insertions(+) + create mode 100755 tests/misc/date-tz.sh + +diff --git a/tests/local.mk b/tests/local.mk +index 9f1a853..ec0b414 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -282,6 +282,7 @@ all_tests = \ + tests/misc/csplit-suppress-matched.pl \ + tests/misc/date-debug.sh \ + tests/misc/date-sec.sh \ ++ tests/misc/date-tz.sh \ + tests/misc/dircolors.pl \ + tests/misc/dirname.pl \ + tests/misc/env-null.sh \ +diff --git a/tests/misc/date-tz.sh b/tests/misc/date-tz.sh +new file mode 100755 +index 0000000..3fe1579 +--- /dev/null ++++ b/tests/misc/date-tz.sh +@@ -0,0 +1,26 @@ ++#!/bin/sh ++# Verify TZ processing. ++ ++# Copyright (C) 2017 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ date ++ ++# coreutils-8.27 would overwrite the heap with large TZ values ++tz_long=$(printf '%2000s' | tr ' ' a) ++date -d "TZ=\"${tz_long}0\" 2017" || fail=1 ++ ++Exit $fail +-- +2.9.3 + diff --git a/coreutils-8.27-date-debug-test.patch b/coreutils-8.27-date-debug-test.patch new file mode 100644 index 0000000..a8def7b --- /dev/null +++ b/coreutils-8.27-date-debug-test.patch @@ -0,0 +1,50 @@ +From ee2017f191f1ad177405fbd8816df0a55127804a Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Thu, 9 Mar 2017 23:59:05 -0800 +Subject: [PATCH] tests: port to tzdb-2017a + +Problem reported by Bernhard Voelker in: +http://lists.gnu.org/archive/html/coreutils/2017-03/msg00026.html +* tests/misc/date-debug.sh: Port test to tzdb 2017a, +and future-proof the America/Belize test. + +Upstream-commit: 612086660bab9bf981894da146550e9101224b17 +Signed-off-by: Kamil Dudka +--- + tests/misc/date-debug.sh | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/tests/misc/date-debug.sh b/tests/misc/date-debug.sh +index 48f4605..8e0b2af 100755 +--- a/tests/misc/date-debug.sh ++++ b/tests/misc/date-debug.sh +@@ -52,10 +52,11 @@ date: output timezone: +09:00 (set from TZ="Asia/Tokyo" environment value) + date: final: 661095000.000000000 (epoch-seconds) + date: final: (Y-M-D) 1990-12-13 13:30:00 (UTC0) + date: final: (Y-M-D) 1990-12-13 22:30:00 (output timezone TZ=+09:00) +-Thu Dec 13 07:30:00 CST 1990 ++Thu Dec 13 07:30:00 -0600 1990 + EOF + +-TZ=America/Belize date --debug -d "$in1" >out1 2>&1 || fail=1 ++TZ=America/Belize date --debug -d "$in1" +'%a %b %e %T %z %Y' >out1 2>&1 || ++ fail=1 + + compare exp1 out1 || fail=1 + +@@ -94,10 +95,10 @@ date: output timezone: -05:00 (set from TZ="America/Lima" environment value) + date: final: 1.000000000 (epoch-seconds) + date: final: (Y-M-D) 1970-01-01 00:00:01 (UTC0) + date: final: (Y-M-D) 1969-12-31 19:00:01 (output timezone TZ=-05:00) +-Wed Dec 31 19:00:01 PET 1969 ++Wed Dec 31 19:00:01 -0500 1969 + EOF + +-TZ=America/Lima date --debug -d "$in3" >out3 2>&1 || fail=1 ++TZ=America/Lima date --debug -d "$in3" +'%a %b %e %T %z %Y' >out3 2>&1 || fail=1 + compare exp3 out3 || fail=1 + + ## +-- +2.9.3 + diff --git a/coreutils-8.27-df-stat.patch b/coreutils-8.27-df-stat.patch new file mode 100644 index 0000000..fbfa283 --- /dev/null +++ b/coreutils-8.27-df-stat.patch @@ -0,0 +1,82 @@ +From 9c4641f42bbecf63ec0a0e05caacbccd5332b831 Mon Sep 17 00:00:00 2001 +From: Philipp Thomas +Date: Sun, 26 Mar 2017 22:34:00 -0700 +Subject: [PATCH 1/2] df: avoid querying excluded file systems + +* src/df.c (filter_mount_list): Avoid stat() on +explicitly excluded file systems, which is especially +significant in cases like `-x nfs` which may hang. +* NEWS: Mention the bug fix. + +Upstream-commit: 7c228bc55ed3fd6d56a6ad135438066de2f54a30 +Signed-off-by: Kamil Dudka +--- + src/df.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/df.c b/src/df.c +index 5b9e8fd..e0ebed7 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -682,9 +682,11 @@ filter_mount_list (bool devices_only) + On Linux we probably have me_dev populated from /proc/self/mountinfo, + however we still stat() in case another device was mounted later. */ + if ((me->me_remote && show_local_fs) ++ || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type)) + || -1 == stat (me->me_mountdir, &buf)) + { +- /* If remote, and showing just local, add ME for filtering later. ++ /* If remote, and showing just local, or FS type is excluded, ++ add ME for filtering later. + If stat failed; add ME to be able to complain about it later. */ + buf.st_dev = me->me_dev; + } +-- +2.13.6 + + +From 605ec5a50d341fb2d3eea6ad68316e229c7b8382 Mon Sep 17 00:00:00 2001 +From: Josef Cejka +Date: Tue, 1 Aug 2017 01:50:34 +0200 +Subject: [PATCH 2/2] df: avoid stat() for dummy file systems with -l + +When systemd is configured to automount a remote file system - see +'man systemd.automount(5)', then the mount point is initially +mounted by systemd with the file system type "autofs". +When the resource is used later on, then the wanted file system is +mounted over that mount point on demand. +'df -l' triggered systemd to mount the file system because it called +stat() on the mount point. +Instead of single-casing "autofs" targets, we can avoid stat()ing +all dummy file systems (which includes "autofs"), because those are +skipped later on in get_dev() anyway. + +*src/df.c (filter_mount_list): Also skip dummy file systems unless +the -a option or a specific target are given. +* NEWS: Mention the fix. + +Co-authored-by: Bernhard Voelker + +Fixes http://bugzilla.suse.com/show_bug.cgi?id=1043059 + +Upstream-commit: a19ff5d8179a7de38109fc78278229fd96f3941a +Signed-off-by: Kamil Dudka +--- + src/df.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/df.c b/src/df.c +index e0ebed7..11b5a22 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -682,6 +682,7 @@ filter_mount_list (bool devices_only) + On Linux we probably have me_dev populated from /proc/self/mountinfo, + however we still stat() in case another device was mounted later. */ + if ((me->me_remote && show_local_fs) ++ || (me->me_dummy && !show_all_fs && !show_listed_fs) + || (!selected_fstype (me->me_type) || excluded_fstype (me->me_type)) + || -1 == stat (me->me_mountdir, &buf)) + { +-- +2.13.6 + diff --git a/coreutils-8.27-ptx-int-overflow.patch b/coreutils-8.27-ptx-int-overflow.patch new file mode 100644 index 0000000..897c2ad --- /dev/null +++ b/coreutils-8.27-ptx-int-overflow.patch @@ -0,0 +1,547 @@ +From 7408a9758924a1ccbabf9fcab401a31ef1b7c755 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Thu, 17 Aug 2017 12:02:16 -0700 +Subject: [PATCH] ptx: fix some integer overflow bugs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Problem reported by Lukas Zachar at: +http://bugzilla.redhat.com/1482445 +* src/ptx.c (line_width, gap_size, maximum_word_length) +(reference_max_width, half_line_width, before_max_width) +(keyafter_max_width, truncation_string_length, compare_words) +(compare_occurs, search_table, find_occurs_in_text, print_spaces) +(fix_output_parameters, define_all_fields): +Use ptrdiff_t, not int, for object offsets and sizes. +(WORD, OCCURS): Use ptrdiff_t, not short int. +(WORD_TABLE, number_of_occurs, generate_all_output): +Prefer ptrdiff_t to size_t where either will do. +(total_line_count, file_line_count, OCCURS, fix_output_parameters) +(define_all_fields): +Use intmax_t, not int, for line counts. +(DELTA): Remove. All uses changed. +(OCCURS, find_occurs_in_text, fix_output_parameters): +Use int, not size_t, for file indexes. +(tail_truncation, before_truncation, keyafter_truncation) +(head_truncation, search_table, define_all_fields) +(generate_all_output): +Use bool for booleans. +(digest_word_file, find_occurs_in_text): +Use x2nrealloc instead of checking for overflow by hand. +(find_occurs_in_text, fix_output_parameters, define_all_fields): +Omit unnecessary cast. +(fix_output_parameters): Don’t assume integers fit in 11 digits. +(fix_output_parameters, define_all_fields): +Use sprintf return value rather than calling strlen. +(define_all_fields): Do not rely on sprintf to generate a string +that may contain more than INT_MAX bytes. +(main): Use xstrtoimax, not xstrtoul. +Use xnmalloc to catch integer overflow. + +Upstream-commit: 1d9765a764790cc68ec52c16d7ccbf633c404f0e +Signed-off-by: Kamil Dudka +--- + src/ptx.c | 194 +++++++++++++++++++++++++++++--------------------------------- + 1 file changed, 91 insertions(+), 103 deletions(-) + +diff --git a/src/ptx.c b/src/ptx.c +index c0c9733..2aababf 100644 +--- a/src/ptx.c ++++ b/src/ptx.c +@@ -59,9 +59,9 @@ + /* Global definitions. */ + + /* FIXME: There are many unchecked integer overflows in this file, +- that will cause this command to misbehave given large inputs or +- options. Many of the "int" values below should be "size_t" or +- something else like that. */ ++ and in theory they could cause this command to have undefined ++ behavior given large inputs or options. This command should ++ diagnose any such overflow and exit. */ + + /* Program options. */ + +@@ -77,8 +77,8 @@ static bool gnu_extensions = true; /* trigger all GNU extensions */ + static bool auto_reference = false; /* refs are 'file_name:line_number:' */ + static bool input_reference = false; /* refs at beginning of input lines */ + static bool right_reference = false; /* output refs after right context */ +-static int line_width = 72; /* output line width in characters */ +-static int gap_size = 3; /* number of spaces between output fields */ ++static ptrdiff_t line_width = 72; /* output line width in characters */ ++static ptrdiff_t gap_size = 3; /* number of spaces between output fields */ + static const char *truncation_string = "/"; + /* string used to mark line truncations */ + static const char *macro_name = "xx"; /* macro name for roff or TeX output */ +@@ -105,8 +105,8 @@ static struct regex_data context_regex; /* end of context */ + static struct regex_data word_regex; /* keyword */ + + /* A BLOCK delimit a region in memory of arbitrary size, like the copy of a +- whole file. A WORD is something smaller, its length should fit in a +- short integer. A WORD_TABLE may contain several WORDs. */ ++ whole file. A WORD is similar, except it is intended for smaller regions. ++ A WORD_TABLE may contain several WORDs. */ + + typedef struct + { +@@ -118,7 +118,7 @@ BLOCK; + typedef struct + { + char *start; /* pointer to beginning of region */ +- short int size; /* length of the region */ ++ ptrdiff_t size; /* length of the region */ + } + WORD; + +@@ -126,7 +126,7 @@ typedef struct + { + WORD *start; /* array of WORDs */ + size_t alloc; /* allocated length */ +- size_t length; /* number of used entries */ ++ ptrdiff_t length; /* number of used entries */ + } + WORD_TABLE; + +@@ -149,10 +149,10 @@ static struct re_registers word_regs; + static char word_fastmap[CHAR_SET_SIZE]; + + /* Maximum length of any word read. */ +-static int maximum_word_length; ++static ptrdiff_t maximum_word_length; + + /* Maximum width of any reference used. */ +-static int reference_max_width; ++static ptrdiff_t reference_max_width; + + /* Ignore and Only word tables. */ + +@@ -162,9 +162,9 @@ static WORD_TABLE only_table; /* table of words to select */ + /* Source text table, and scanning macros. */ + + static int number_input_files; /* number of text input files */ +-static int total_line_count; /* total number of lines seen so far */ ++static intmax_t total_line_count; /* total number of lines seen so far */ + static const char **input_file_name; /* array of text input file names */ +-static int *file_line_count; /* array of 'total_line_count' values at end */ ++static intmax_t *file_line_count; /* array of line count values at end */ + + static BLOCK *text_buffers; /* files to study */ + +@@ -219,20 +219,18 @@ static BLOCK *text_buffers; /* files to study */ + + When automatic references are used, the 'reference' value is the + overall line number in all input files read so far, in this case, it +- is of type (int). When input references are used, the 'reference' ++ is of type intmax_t. When input references are used, the 'reference' + value indicates the distance between the keyword beginning and the +- start of the reference field, it is of type (DELTA) and usually ++ start of the reference field, and it fits in ptrdiff_t and is usually + negative. */ + +-typedef short int DELTA; /* to hold displacement within one context */ +- + typedef struct + { + WORD key; /* description of the keyword */ +- DELTA left; /* distance to left context start */ +- DELTA right; /* distance to right context end */ +- int reference; /* reference descriptor */ +- size_t file_index; /* corresponding file */ ++ ptrdiff_t left; /* distance to left context start */ ++ ptrdiff_t right; /* distance to right context end */ ++ intmax_t reference; /* reference descriptor */ ++ int file_index; /* corresponding file */ + } + OCCURS; + +@@ -241,7 +239,7 @@ OCCURS; + + static OCCURS *occurs_table[1]; /* all words retained from the read text */ + static size_t occurs_alloc[1]; /* allocated size of occurs_table */ +-static size_t number_of_occurs[1]; /* number of used slots in occurs_table */ ++static ptrdiff_t number_of_occurs[1]; /* number of used slots in occurs_table */ + + + /* Communication among output routines. */ +@@ -249,10 +247,17 @@ static size_t number_of_occurs[1]; /* number of used slots in occurs_table */ + /* Indicate if special output processing is requested for each character. */ + static char edited_flag[CHAR_SET_SIZE]; + +-static int half_line_width; /* half of line width, reference excluded */ +-static int before_max_width; /* maximum width of before field */ +-static int keyafter_max_width; /* maximum width of keyword-and-after field */ +-static int truncation_string_length;/* length of string that flags truncation */ ++/* Half of line width, reference excluded. */ ++static ptrdiff_t half_line_width; ++ ++/* Maximum width of before field. */ ++static ptrdiff_t before_max_width; ++ ++/* Maximum width of keyword-and-after field. */ ++static ptrdiff_t keyafter_max_width; ++ ++/* Length of string that flags truncation. */ ++static ptrdiff_t truncation_string_length; + + /* When context is limited by lines, wraparound may happen on final output: + the 'head' pointer gives access to some supplementary left context which +@@ -261,16 +266,16 @@ static int truncation_string_length;/* length of string that flags truncation */ + beginning of the output line. */ + + static BLOCK tail; /* tail field */ +-static int tail_truncation; /* flag truncation after the tail field */ ++static bool tail_truncation; /* flag truncation after the tail field */ + + static BLOCK before; /* before field */ +-static int before_truncation; /* flag truncation before the before field */ ++static bool before_truncation; /* flag truncation before the before field */ + + static BLOCK keyafter; /* keyword-and-after field */ +-static int keyafter_truncation; /* flag truncation after the keyafter field */ ++static bool keyafter_truncation; /* flag truncation after the keyafter field */ + + static BLOCK head; /* head field */ +-static int head_truncation; /* flag truncation before the head field */ ++static bool head_truncation; /* flag truncation before the head field */ + + static BLOCK reference; /* reference field for input reference mode */ + +@@ -540,8 +545,8 @@ compare_words (const void *void_first, const void *void_second) + { + #define first ((const WORD *) void_first) + #define second ((const WORD *) void_second) +- int length; /* minimum of two lengths */ +- int counter; /* cursor in words */ ++ ptrdiff_t length; /* minimum of two lengths */ ++ ptrdiff_t counter; /* cursor in words */ + int value; /* value of comparison */ + + length = first->size < second->size ? first->size : second->size; +@@ -567,7 +572,7 @@ compare_words (const void *void_first, const void *void_second) + } + } + +- return first->size - second->size; ++ return first->size < second->size ? -1 : first->size > second->size; + #undef first + #undef second + } +@@ -586,21 +591,21 @@ compare_occurs (const void *void_first, const void *void_second) + int value; + + value = compare_words (&first->key, &second->key); +- return value == 0 ? first->key.start - second->key.start : value; ++ return (value ? value ++ : first->key.start < second->key.start ? -1 ++ : first->key.start > second->key.start); + #undef first + #undef second + } + +-/*------------------------------------------------------------. +-| Return !0 if WORD appears in TABLE. Uses a binary search. | +-`------------------------------------------------------------*/ ++/* True if WORD appears in TABLE. Uses a binary search. */ + +-static int _GL_ATTRIBUTE_PURE ++static bool _GL_ATTRIBUTE_PURE + search_table (WORD *word, WORD_TABLE *table) + { +- int lowest; /* current lowest possible index */ +- int highest; /* current highest possible index */ +- int middle; /* current middle index */ ++ ptrdiff_t lowest; /* current lowest possible index */ ++ ptrdiff_t highest; /* current highest possible index */ ++ ptrdiff_t middle; /* current middle index */ + int value; /* value from last comparison */ + + lowest = 0; +@@ -614,9 +619,9 @@ search_table (WORD *word, WORD_TABLE *table) + else if (value > 0) + lowest = middle + 1; + else +- return 1; ++ return true; + } +- return 0; ++ return false; + } + + /*---------------------------------------------------------------------. +@@ -713,14 +718,8 @@ digest_word_file (const char *file_name, WORD_TABLE *table) + if (cursor > word_start) + { + if (table->length == table->alloc) +- { +- if ((SIZE_MAX / sizeof *table->start - 1) / 2 < table->alloc) +- xalloc_die (); +- table->alloc = table->alloc * 2 + 1; +- table->start = xrealloc (table->start, +- table->alloc * sizeof *table->start); +- } +- ++ table->start = x2nrealloc (table->start, &table->alloc, ++ sizeof *table->start); + table->start[table->length].start = word_start; + table->start[table->length].size = cursor - word_start; + table->length++; +@@ -744,13 +743,13 @@ digest_word_file (const char *file_name, WORD_TABLE *table) + `----------------------------------------------------------------------*/ + + static void +-find_occurs_in_text (size_t file_index) ++find_occurs_in_text (int file_index) + { + char *cursor; /* for scanning the source text */ + char *scan; /* for scanning the source text also */ + char *line_start; /* start of the current input line */ + char *line_scan; /* newlines scanned until this point */ +- int reference_length; /* length of reference in input mode */ ++ ptrdiff_t reference_length; /* length of reference in input mode */ + WORD possible_key; /* possible key, to ease searches */ + OCCURS *occurs_cursor; /* current OCCURS under construction */ + +@@ -946,16 +945,9 @@ find_occurs_in_text (size_t file_index) + where it will be constructed. */ + + if (number_of_occurs[0] == occurs_alloc[0]) +- { +- if ((SIZE_MAX / sizeof *occurs_table[0] - 1) / 2 +- < occurs_alloc[0]) +- xalloc_die (); +- occurs_alloc[0] = occurs_alloc[0] * 2 + 1; +- occurs_table[0] = +- xrealloc (occurs_table[0], +- occurs_alloc[0] * sizeof *occurs_table[0]); +- } +- ++ occurs_table[0] = x2nrealloc (occurs_table[0], ++ &occurs_alloc[0], ++ sizeof *occurs_table[0]); + occurs_cursor = occurs_table[0] + number_of_occurs[0]; + + /* Define the reference field, if any. */ +@@ -990,8 +982,7 @@ find_occurs_in_text (size_t file_index) + of the reference. The reference position is simply the + value of 'line_start'. */ + +- occurs_cursor->reference +- = (DELTA) (line_start - possible_key.start); ++ occurs_cursor->reference = line_start - possible_key.start; + if (reference_length > reference_max_width) + reference_max_width = reference_length; + } +@@ -1023,11 +1014,9 @@ find_occurs_in_text (size_t file_index) + `-----------------------------------------*/ + + static void +-print_spaces (int number) ++print_spaces (ptrdiff_t number) + { +- int counter; +- +- for (counter = number; counter > 0; counter--) ++ for (ptrdiff_t counter = number; counter > 0; counter--) + putchar (' '); + } + +@@ -1200,10 +1189,9 @@ print_field (BLOCK field) + static void + fix_output_parameters (void) + { +- size_t file_index; /* index in text input file arrays */ +- int line_ordinal; /* line ordinal value for reference */ +- char ordinal_string[12]; /* edited line ordinal for reference */ +- int reference_width; /* width for the whole reference */ ++ int file_index; /* index in text input file arrays */ ++ intmax_t line_ordinal; /* line ordinal value for reference */ ++ ptrdiff_t reference_width; /* width for the whole reference */ + int character; /* character ordinal */ + const char *cursor; /* cursor in some constant strings */ + +@@ -1219,15 +1207,15 @@ fix_output_parameters (void) + line_ordinal = file_line_count[file_index] + 1; + if (file_index > 0) + line_ordinal -= file_line_count[file_index - 1]; +- sprintf (ordinal_string, "%d", line_ordinal); +- reference_width = strlen (ordinal_string); ++ char ordinal_string[INT_BUFSIZE_BOUND (intmax_t)]; ++ reference_width = sprintf (ordinal_string, "%"PRIdMAX, line_ordinal); + if (input_file_name[file_index]) + reference_width += strlen (input_file_name[file_index]); + if (reference_width > reference_max_width) + reference_max_width = reference_width; + } + reference_max_width++; +- reference.start = xmalloc ((size_t) reference_max_width + 1); ++ reference.start = xmalloc (reference_max_width + 1); + } + + /* If the reference appears to the left of the output line, reserve some +@@ -1355,14 +1343,14 @@ fix_output_parameters (void) + static void + define_all_fields (OCCURS *occurs) + { +- int tail_max_width; /* allowable width of tail field */ +- int head_max_width; /* allowable width of head field */ ++ ptrdiff_t tail_max_width; /* allowable width of tail field */ ++ ptrdiff_t head_max_width; /* allowable width of head field */ + char *cursor; /* running cursor in source text */ + char *left_context_start; /* start of left context */ + char *right_context_end; /* end of right context */ + char *left_field_start; /* conservative start for 'head'/'before' */ + const char *file_name; /* file name for reference */ +- int line_ordinal; /* line ordinal for reference */ ++ intmax_t line_ordinal; /* line ordinal for reference */ + const char *buffer_start; /* start of buffered file for this occurs */ + const char *buffer_end; /* end of buffered file for this occurs */ + +@@ -1435,7 +1423,7 @@ define_all_fields (OCCURS *occurs) + before_truncation = cursor > left_context_start; + } + else +- before_truncation = 0; ++ before_truncation = false; + + SKIP_WHITE (before.start, buffer_end); + +@@ -1468,11 +1456,11 @@ define_all_fields (OCCURS *occurs) + + if (tail.end > tail.start) + { +- keyafter_truncation = 0; ++ keyafter_truncation = false; + tail_truncation = truncation_string && tail.end < right_context_end; + } + else +- tail_truncation = 0; ++ tail_truncation = false; + + SKIP_WHITE_BACKWARDS (tail.end, tail.start); + } +@@ -1483,7 +1471,7 @@ define_all_fields (OCCURS *occurs) + + tail.start = NULL; + tail.end = NULL; +- tail_truncation = 0; ++ tail_truncation = false; + } + + /* 'head' could not take more columns than what has been left in the right +@@ -1506,12 +1494,12 @@ define_all_fields (OCCURS *occurs) + + if (head.end > head.start) + { +- before_truncation = 0; ++ before_truncation = false; + head_truncation = (truncation_string + && head.start > left_context_start); + } + else +- head_truncation = 0; ++ head_truncation = false; + + SKIP_WHITE (head.start, head.end); + } +@@ -1522,7 +1510,7 @@ define_all_fields (OCCURS *occurs) + + head.start = NULL; + head.end = NULL; +- head_truncation = 0; ++ head_truncation = false; + } + + if (auto_reference) +@@ -1540,8 +1528,8 @@ define_all_fields (OCCURS *occurs) + if (occurs->file_index > 0) + line_ordinal -= file_line_count[occurs->file_index - 1]; + +- sprintf (reference.start, "%s:%d", file_name, line_ordinal); +- reference.end = reference.start + strlen (reference.start); ++ char *file_end = stpcpy (reference.start, file_name); ++ reference.end = file_end + sprintf (file_end, ":%"PRIdMAX, line_ordinal); + } + else if (input_reference) + { +@@ -1549,7 +1537,7 @@ define_all_fields (OCCURS *occurs) + /* Reference starts at saved position for reference and extends right + until some white space is met. */ + +- reference.start = keyafter.start + (DELTA) occurs->reference; ++ reference.start = keyafter.start + occurs->reference; + reference.end = reference.start; + SKIP_NON_WHITE (reference.end, right_context_end); + } +@@ -1753,7 +1741,7 @@ output_one_dumb_line (void) + static void + generate_all_output (void) + { +- size_t occurs_index; /* index of keyword entry being processed */ ++ ptrdiff_t occurs_index; /* index of keyword entry being processed */ + OCCURS *occurs_cursor; /* current keyword entry being processed */ + + /* The following assignments are useful to provide default values in case +@@ -1762,11 +1750,11 @@ generate_all_output (void) + + tail.start = NULL; + tail.end = NULL; +- tail_truncation = 0; ++ tail_truncation = false; + + head.start = NULL; + head.end = NULL; +- head_truncation = 0; ++ head_truncation = false; + + /* Loop over all keyword occurrences. */ + +@@ -1946,12 +1934,12 @@ main (int argc, char **argv) + + case 'g': + { +- unsigned long int tmp_ulong; +- if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK +- || ! (0 < tmp_ulong && tmp_ulong <= INT_MAX)) ++ intmax_t tmp; ++ if (! (xstrtoimax (optarg, NULL, 0, &tmp, NULL) == LONGINT_OK ++ && 0 < tmp && tmp <= PTRDIFF_MAX)) + die (EXIT_FAILURE, 0, _("invalid gap width: %s"), + quote (optarg)); +- gap_size = tmp_ulong; ++ gap_size = tmp; + break; + } + +@@ -1973,12 +1961,12 @@ main (int argc, char **argv) + + case 'w': + { +- unsigned long int tmp_ulong; +- if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) != LONGINT_OK +- || ! (0 < tmp_ulong && tmp_ulong <= INT_MAX)) ++ intmax_t tmp; ++ if (! (xstrtoimax (optarg, NULL, 0, &tmp, NULL) == LONGINT_OK ++ && 0 < tmp && tmp <= PTRDIFF_MAX)) + die (EXIT_FAILURE, 0, _("invalid line width: %s"), + quote (optarg)); +- line_width = tmp_ulong; ++ line_width = tmp; + break; + } + +@@ -2045,9 +2033,9 @@ main (int argc, char **argv) + else if (gnu_extensions) + { + number_input_files = argc - optind; +- input_file_name = xmalloc (number_input_files * sizeof *input_file_name); +- file_line_count = xmalloc (number_input_files * sizeof *file_line_count); +- text_buffers = xmalloc (number_input_files * sizeof *text_buffers); ++ input_file_name = xnmalloc (number_input_files, sizeof *input_file_name); ++ file_line_count = xnmalloc (number_input_files, sizeof *file_line_count); ++ text_buffers = xnmalloc (number_input_files, sizeof *text_buffers); + + for (file_index = 0; file_index < number_input_files; file_index++) + { +-- +2.9.5 + diff --git a/coreutils-8.27-runcon-doc.patch b/coreutils-8.27-runcon-doc.patch new file mode 100644 index 0000000..41c0a8a --- /dev/null +++ b/coreutils-8.27-runcon-doc.patch @@ -0,0 +1,33 @@ +From 76be8a7f9eb717b3d47009eb25d39fe7139a2c2d Mon Sep 17 00:00:00 2001 +From: Sebastian Kisela +Date: Tue, 30 May 2017 09:29:32 +0200 +Subject: [PATCH] doc: mention `setpriv --no-new-privs` feature in runcon info + +upstream commit: 6ebaf8195000d6d3590a2eac13f13b158e325452 +--- + doc/coreutils.texi | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 68df075..e16e885 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -16583,7 +16583,14 @@ are interpreted as arguments to the command. + With neither @var{context} nor @var{command}, print the current + security context. + +-The program accepts the following options. Also see @ref{Common options}. ++@cindex restricted security context ++@cindex NO_NEW_PRIVS ++Note also the @command{setpriv} command which can be used to set the ++NO_NEW_PRIVS bit using @command{setpriv --no-new-privs runcon ...}, ++thus disallowing usage of a security context with more privileges ++than the process would normally have. ++ ++@command{runcon} accepts the following options. Also see @ref{Common options}. + + @table @samp + +-- +2.9.4 + diff --git a/coreutils-8.27-tail-inotify-recreate.patch b/coreutils-8.27-tail-inotify-recreate.patch new file mode 100644 index 0000000..1a63655 --- /dev/null +++ b/coreutils-8.27-tail-inotify-recreate.patch @@ -0,0 +1,168 @@ +From ba5fe2d4b8b6a8366f48b1ad1f97fe26c9089b53 Mon Sep 17 00:00:00 2001 +From: Sebastian Kisela +Date: Wed, 5 Apr 2017 09:40:41 +0200 +Subject: [PATCH] tail: revert to polling if a followed directory is replaced + +* src/tail.c (tail_forever_inotify): Add the IN_DELETE_SELF flag when +creating watch for the parent directory. After the parent directory +is removed, an event is caught and then we switch from inotify to +polling mode. Till now, inotify has always frozen because it waited for +an event from a watched dir, which has been already deleted and was not +added again. +* tests/tail-2/inotify-dir-recreate.sh: Add a test case. +* tests/local.mk: Reference the new test. +Fixes http://bugs.gnu.org/26363 +Reported at https://bugzilla.redhat.com/1283760 + +Upstream-commit: ba5fe2d4b8b6a8366f48b1ad1f97fe26c9089b53 + +--- + src/tail.c | 22 +++++++++- + tests/local.mk | 1 + + tests/tail-2/inotify-dir-recreate.sh | 82 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 107 insertions(+), 1 deletion(-) + create mode 100755 tests/tail-2/inotify-dir-recreate.sh + +diff --git a/src/tail.c b/src/tail.c +index d1552d4..6328fe0 100644 +--- a/src/tail.c ++++ b/src/tail.c +@@ -1457,7 +1457,8 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, + In that case the same watch descriptor is returned. */ + f[i].parent_wd = inotify_add_watch (wd, dirlen ? f[i].name : ".", + (IN_CREATE | IN_DELETE +- | IN_MOVED_TO | IN_ATTRIB)); ++ | IN_MOVED_TO | IN_ATTRIB ++ | IN_DELETE_SELF)); + + f[i].name[dirlen] = prev; + +@@ -1628,6 +1629,25 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files, + ev = void_ev; + evbuf_off += sizeof (*ev) + ev->len; + ++ /* If a directory is deleted, IN_DELETE_SELF is emitted ++ with ev->name of length 0. ++ We need to catch it, otherwise it would wait forever, ++ as wd for directory becomes inactive. Revert to polling now. */ ++ if ((ev->mask & IN_DELETE_SELF) && ! ev->len) ++ { ++ for (i = 0; i < n_files; i++) ++ { ++ if (ev->wd == f[i].parent_wd) ++ { ++ hash_free (wd_to_name); ++ error (0, 0, ++ _("directory containing watched file was removed")); ++ errno = 0; /* we've already diagnosed enough errno detail. */ ++ return true; ++ } ++ } ++ } ++ + if (ev->len) /* event on ev->name in watched directory. */ + { + size_t j; +diff --git a/tests/local.mk b/tests/local.mk +index 3fe9ba8..e890c9a 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -176,6 +176,7 @@ all_tests = \ + tests/tail-2/descriptor-vs-rename.sh \ + tests/tail-2/inotify-rotate.sh \ + tests/tail-2/inotify-rotate-resources.sh \ ++ tests/tail-2/inotify-dir-recreate.sh \ + tests/chmod/no-x.sh \ + tests/chgrp/basic.sh \ + tests/rm/dangling-symlink.sh \ +diff --git a/tests/tail-2/inotify-dir-recreate.sh b/tests/tail-2/inotify-dir-recreate.sh +new file mode 100755 +index 0000000..eaa8422 +--- /dev/null ++++ b/tests/tail-2/inotify-dir-recreate.sh +@@ -0,0 +1,82 @@ ++#!/bin/sh ++# Makes sure, inotify will switch to polling mode if directory ++# of the watched file was removed and recreated. ++# (...instead of getting stuck forever) ++ ++# Copyright (C) 2006-2017 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ tail ++ ++ ++# Terminate any background tail process ++cleanup_() { kill $pid 2>/dev/null && wait $pid; } ++ ++cleanup_fail_ () ++{ ++ warn_ $1 ++ cleanup_ ++ fail=1 ++} ++ ++# $check_re - string to be found ++# $check_f - file to be searched ++check_tail_output_ () ++{ ++ local delay="$1" ++ grep $check_re $check_f > /dev/null || ++ { sleep $delay ; return 1; } ++} ++ ++grep_timeout_ () ++{ ++ check_re="$1" ++ check_f="$2" ++ retry_delay_ check_tail_output_ .1 5 ++} ++ ++# Prepare the file to be watched ++mkdir dir && echo 'inotify' > dir/file || framework_failure_ ++ ++#tail must print content of the file to stdout, verify ++timeout 60 tail -F dir/file &>out & pid=$! ++grep_timeout_ 'inotify' 'out' || ++{ cleanup_fail_ 'file to be tailed does not exist'; } ++ ++# Remove the directory, should get the message about the deletion ++rm -r dir || framework_failure_ ++grep_timeout_ 'polling' 'out' || ++{ cleanup_fail_ 'tail did not switch to polling mode'; } ++ ++# Recreate the dir, must get a message about recreation ++mkdir dir && touch dir/file || framework_failure_ ++grep_timeout_ 'appeared' 'out' || ++{ cleanup_fail_ 'previously removed file did not appear'; } ++ ++cleanup_ ++ ++# Expected result for the whole process ++cat <<\EOF > exp || framework_failure_ ++inotify ++tail: 'dir/file' has become inaccessible: No such file or directory ++tail: directory containing watched file was removed ++tail: inotify cannot be used, reverting to polling ++tail: 'dir/file' has appeared; following new file ++EOF ++ ++compare exp out || fail=1 ++ ++Exit $fail +-- +2.9.3 + diff --git a/coreutils-8.27.tar.xz.sig b/coreutils-8.27.tar.xz.sig new file mode 100644 index 0000000..7555c00 --- /dev/null +++ b/coreutils-8.27.tar.xz.sig @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIcBAABAgAGBQJYwOwaAAoJEN9v2XEwYDfZQrUP/RdXj/ug35e+u+VD1ts9/b8n +7JihJmxngEZQAJECNTMbJ7mNj6DhpMY0Jg/Hwg7zJT28T6QDeS1Iuk3Id4uM5eFa +CgHKAZumntSMTkQdNvnCEFEIqu+L8BtBYGcOaw66wAFNFw3jdJUUs2sOST2r46jR +N7aY9oARKJuHfgTZ2BI2zL0Q+poXM1O0k/U+BScE6c139zJsbg+1uM9kGVtJWPkM +EPLFWkbTgjYnt+qEFrDlWL0YFOS42sgR7P1sVfBC1nAu5lwgzPy62OtGv9WCEBhm +3+PRNZ0KLW8CKp06llG/0bG4QwssWs6p/vPwrRGeAg6pKsRNN1ni27AnDThiPgvz +YbBLgU+EZj1HuibvYArHXNKY2+O5ZC3nYU6bdAffl3TAtrGFA1ncZXGiFD5UgOQ2 +V9Q38S41FUEwKGtf9tWGCRTxrb4FQ1CDzJglV9vHKetn4mgH/HpEG/q07k4RNW5d +ikfrS0xFxbqtLjlY3UqvtkrFyVQFY093ozsP7fKsq53JAtEWc3YvXR8UCbliU+gV +5qug0REBQafe9EAyH+oq0dzD2BZ3KtFcjtKI/2UzAf3idcyygsHgcEPQObqI8BfD +NscEMjdFY7+Zh5w2shQlyq4xr2aI2nXCX3+AMcS/6Yfg6W6fBvgIjtmXBrQsbWpV +DBcx50TVDa/ERBX1+FI1 +=skPR +-----END PGP SIGNATURE----- diff --git a/coreutils-8.32-DIR_COLORS.patch b/coreutils-8.32-DIR_COLORS.patch deleted file mode 100644 index 37ce3e6..0000000 --- a/coreutils-8.32-DIR_COLORS.patch +++ /dev/null @@ -1,100 +0,0 @@ -From bca11e30e8a6281a8cbddc9fb196dd86ab09c955 Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Fri, 17 Jun 2016 16:58:18 +0200 -Subject: [PATCH] downstream changes to default DIR_COLORS - ---- - DIR_COLORS | 9 ++++++++- - DIR_COLORS.lightbgcolor | 21 +++++++++++++++------ - 2 files changed, 23 insertions(+), 7 deletions(-) - -diff --git a/DIR_COLORS b/DIR_COLORS -index 540f6cd..b4785b6 100644 ---- a/DIR_COLORS -+++ b/DIR_COLORS -@@ -1,3 +1,7 @@ -+# This file goes in the /etc directory, and must be world readable. -+# You can override the system defaults by making a copy of this file -+# as ~/.dir_colors -+ - # Configuration file for dircolors, a utility to help you set the - # LS_COLORS environment variable used by GNU ls with the --color option. - -@@ -11,6 +15,9 @@ - - # Global config options can be specified before TERM or COLORTERM entries - -+# For compatibility, the pattern "^COLOR.*none" is recognized as a way to -+# disable colorization. See https://bugzilla.redhat.com/1349579 for details. -+ - # =================================================================== - # Terminal filters - # =================================================================== -@@ -70,7 +77,7 @@ DOOR 01;35 # door - BLK 40;33;01 # block device driver - CHR 40;33;01 # character device driver - ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... --MISSING 00 # ... and the files they point to -+MISSING 01;37;41 # ... and the files they point to - SETUID 37;41 # regular file that is setuid (u+s) - SETGID 30;43 # regular file that is setgid (g+s) - CAPABILITY 00 # regular file with capability (very expensive to lookup) -diff --git a/DIR_COLORS.lightbgcolor b/DIR_COLORS.lightbgcolor -index e3b0ec3..39a0a4c 100644 ---- a/DIR_COLORS.lightbgcolor -+++ b/DIR_COLORS.lightbgcolor -@@ -1,3 +1,9 @@ -+# Configuration file for the color ls utility - modified for lighter backgrounds -+ -+# This file goes in the /etc directory, and must be world readable. -+# You can override the system defaults by making a copy of this file -+# as ~/.dir_colors -+ - # Configuration file for dircolors, a utility to help you set the - # LS_COLORS environment variable used by GNU ls with the --color option. - -@@ -11,6 +17,9 @@ - - # Global config options can be specified before TERM or COLORTERM entries - -+# For compatibility, the pattern "^COLOR.*none" is recognized as a way to -+# disable colorization. See https://bugzilla.redhat.com/1349579 for details. -+ - # =================================================================== - # Terminal filters - # =================================================================== -@@ -60,17 +69,17 @@ TERM xterm* - #NORMAL 00 # no color code at all - #FILE 00 # regular file: use no color at all - RESET 0 # reset to "normal" color --DIR 01;34 # directory --LINK 01;36 # symbolic link. (If you set this to 'target' instead of a -+DIR 00;34 # directory -+LINK 00;36 # symbolic link. (If you set this to 'target' instead of a - # numerical value, the color is as for the file pointed to.) - MULTIHARDLINK 00 # regular file with more than one link - FIFO 40;33 # pipe --SOCK 01;35 # socket --DOOR 01;35 # door -+SOCK 00;35 # socket -+DOOR 00;35 # door - BLK 40;33;01 # block device driver - CHR 40;33;01 # character device driver - ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ... --MISSING 00 # ... and the files they point to -+MISSING 01;37;41 # ... and the files they point to - SETUID 37;41 # regular file that is setuid (u+s) - SETGID 30;43 # regular file that is setgid (g+s) - CAPABILITY 00 # regular file with capability (very expensive to lookup) -@@ -79,7 +88,7 @@ OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky - STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable - - # This is for regular files with execute permission: --EXEC 01;32 -+EXEC 00;32 - - # =================================================================== - # File extension attributes --- -2.49.0 - diff --git a/coreutils-8.4-mkdir-modenote.patch b/coreutils-8.4-mkdir-modenote.patch new file mode 100644 index 0000000..51a129e --- /dev/null +++ b/coreutils-8.4-mkdir-modenote.patch @@ -0,0 +1,13 @@ +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 400e135..47e4480 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -10074,6 +10074,8 @@ incorrect. @xref{Directory Setuid and Setgid}, for how the + set-user-ID and set-group-ID bits of directories are inherited unless + overridden in this way. + ++Note: The @option{--mode},@option{-m} option only applies to the right-most directories listed on the command line. When combined with @option{--parents}, @option{-p} option, any parent directories are created with @samp{u+wx} modified by umask. ++ + @item -p + @itemx --parents + @opindex -p diff --git a/coreutils-8.5-dircolors.patch b/coreutils-8.5-dircolors.patch new file mode 100644 index 0000000..8707c0a --- /dev/null +++ b/coreutils-8.5-dircolors.patch @@ -0,0 +1,13 @@ +diff -urNp coreutils-8.5-orig/src/dircolors.hin coreutils-8.5/src/dircolors.hin +--- coreutils-8.5-orig/src/dircolors.hin 2010-04-20 21:52:04.000000000 +0200 ++++ coreutils-8.5/src/dircolors.hin 2010-07-22 16:18:41.978036926 +0200 +@@ -127,6 +127,9 @@ EXEC 01;32 + .deb 01;31 + .rpm 01;31 + .jar 01;31 ++.war 01;31 ++.ear 01;31 ++.sar 01;31 + .rar 01;31 + .ace 01;31 + .zoo 01;31 diff --git a/coreutils-9.9-fix-cut-test-aarch64.patch b/coreutils-9.9-fix-cut-test-aarch64.patch deleted file mode 100644 index 600f87b..0000000 --- a/coreutils-9.9-fix-cut-test-aarch64.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 95044cb5eaea83d02f768feb5ab79fcf5e6ad782 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?P=C3=A1draig=20Brady?= -Date: Mon, 22 Dec 2025 17:12:48 +0000 -Subject: [PATCH] tests: avoid false failure due to ulimit on aarch64 - -* tests/cut/cut-huge-range.sh: Add an extra 1MiB headroom, -which was seen with aarch64. -Reported at https://bugzilla.redhat.com/2424302 - -Cherry-picked-by: Lukáš Zaoral -Upstream-commit: 95044cb5eaea83d02f768feb5ab79fcf5e6ad782 ---- - tests/cut/cut-huge-range.sh | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/tests/cut/cut-huge-range.sh b/tests/cut/cut-huge-range.sh -index 4bd1b129d8..98d7e8f0b9 100755 ---- a/tests/cut/cut-huge-range.sh -+++ b/tests/cut/cut-huge-range.sh -@@ -22,6 +22,7 @@ getlimits_ - - vm=$(get_min_ulimit_v_ returns_ 0 cut -b1 /dev/null) \ - || skip_ 'shell lacks ulimit, or ASAN enabled' -+vm=$(($vm+1000)) # https://bugzilla.redhat.com/2424302 - - # Ensure we can cut up to our sentinel value. - # Don't use expr to subtract one, - diff --git a/coreutils-9.9-gnulib-c23.patch b/coreutils-9.9-gnulib-c23.patch deleted file mode 100644 index 82e3899..0000000 --- a/coreutils-9.9-gnulib-c23.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 891761bca1aa78336e5b18c121075b6e4696c5d4 Mon Sep 17 00:00:00 2001 -From: Paul Eggert -Date: Sun, 23 Nov 2025 00:50:40 -0800 -Subject: [PATCH] Port to C23 qualifier-generic fns like strchr -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This ports Gnulib to strict C23 platforms that reject code -like ‘char *q = strchr (P, 'x');’ when P is a pointer to const, -because in C23 strchr is a qualifier-generic function so -strchr (P, 'x') returns char const *. -This patch does not attempt to do the following two things, -which might be useful in the future: -1. When compiling on non-C23 platforms, check user code for -portability to platforms that define qualifier-generic functions. -2. Port Gnulib to platforms that have qualifier-generic functions -not listed in the C23 standard, e.g., strchrnul. I don’t know -of any such platforms. -* lib/mbschr.c (mbschr): -* lib/memchr2.c (memchr2): -Port to C23, where functions like strchr are qualifier-generic. -* lib/c++defs.h (_GL_FUNCDECL_SYS_NAME): New macro. -* lib/c++defs.h (_GL_FUNCDECL_SYS): -* lib/stdlib.in.h (bsearch): -Use it, to prevent C23 names like strchr from acting like macros. -* lib/string.in.h (memchr, strchr, strpbrk, strrchr): -Do not #undef when GNULIB_POSIXCHECK is defined, as this could -cause conforming C23 code to fail to conform. It’s not clear why -_GL_WARN_ON_USE_CXX; perhaps it was needed but isn’t any more? -But for now, limit the removal of #undef to these four functions -where #undeffing is clearly undesirable in C23. -* lib/wchar.in.h (wmemchr): Parenthesize function name in decl, -to prevent it from acting like a macro. - -Cherry-picked-by: Lukáš Zaoral -Upstream-commit: df17f4f37ed3ca373d23ad42eae51122bdb96626 ---- - lib/c++defs.h | 12 +++++++++++- - lib/mbschr.c | 2 +- - lib/memchr2.c | 2 +- - lib/stdlib.in.h | 6 +++--- - lib/string.in.h | 4 ---- - lib/wchar.in.h | 2 +- - 6 files changed, 17 insertions(+), 11 deletions(-) - -diff --git a/lib/c++defs.h b/lib/c++defs.h -index b77979a..7384457 100644 ---- a/lib/c++defs.h -+++ b/lib/c++defs.h -@@ -127,6 +127,16 @@ - #define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters,...) \ - _GL_EXTERN_C_FUNC __VA_ARGS__ rettype rpl_func parameters - -+/* _GL_FUNCDECL_SYS_NAME (func) expands to plain func if C++, and to -+ parenthsized func otherwise. Parenthesization is needed in C23 if -+ the function is like strchr and so is a qualifier-generic macro -+ that expands to something more complicated. */ -+#ifdef __cplusplus -+# define _GL_FUNCDECL_SYS_NAME(func) func -+#else -+# define _GL_FUNCDECL_SYS_NAME(func) (func) -+#endif -+ - /* _GL_FUNCDECL_SYS (func, rettype, parameters, [attributes]); - declares the system function, named func, with the given prototype, - consisting of return type, parameters, and attributes. -@@ -139,7 +149,7 @@ - _GL_FUNCDECL_SYS (posix_openpt, int, (int flags), _GL_ATTRIBUTE_NODISCARD); - */ - #define _GL_FUNCDECL_SYS(func,rettype,parameters,...) \ -- _GL_EXTERN_C_FUNC __VA_ARGS__ rettype func parameters -+ _GL_EXTERN_C_FUNC __VA_ARGS__ rettype _GL_FUNCDECL_SYS_NAME (func) parameters - - /* _GL_CXXALIAS_RPL (func, rettype, parameters); - declares a C++ alias called GNULIB_NAMESPACE::func -diff --git a/lib/mbschr.c b/lib/mbschr.c -index c9e14b5..6582134 100644 ---- a/lib/mbschr.c -+++ b/lib/mbschr.c -@@ -65,5 +65,5 @@ mbschr (const char *string, int c) - return NULL; - } - else -- return strchr (string, c); -+ return (char *) strchr (string, c); - } -diff --git a/lib/memchr2.c b/lib/memchr2.c -index 7493823..d7724ae 100644 ---- a/lib/memchr2.c -+++ b/lib/memchr2.c -@@ -55,7 +55,7 @@ memchr2 (void const *s, int c1_in, int c2_in, size_t n) - c2 = (unsigned char) c2_in; - - if (c1 == c2) -- return memchr (s, c1, n); -+ return (void *) memchr (s, c1, n); - - /* Handle the first few bytes by reading one byte at a time. - Do this until VOID_PTR is aligned on a longword boundary. */ -diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h -index bef0aaa..fd0e1e0 100644 ---- a/lib/stdlib.in.h -+++ b/lib/stdlib.in.h -@@ -224,9 +224,9 @@ _GL_INLINE_HEADER_BEGIN - - /* Declarations for ISO C N3322. */ - #if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__ --_GL_EXTERN_C void *bsearch (const void *__key, -- const void *__base, size_t __nmemb, size_t __size, -- int (*__compare) (const void *, const void *)) -+_GL_EXTERN_C void *_GL_FUNCDECL_SYS_NAME (bsearch) -+ (const void *__key, const void *__base, size_t __nmemb, size_t __size, -+ int (*__compare) (const void *, const void *)) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3) _GL_ARG_NONNULL ((5)); - _GL_EXTERN_C void qsort (void *__base, size_t __nmemb, size_t __size, - int (*__compare) (const void *, const void *)) -diff --git a/lib/string.in.h b/lib/string.in.h -index fdcdd21..8b56acf 100644 ---- a/lib/string.in.h -+++ b/lib/string.in.h -@@ -409,7 +409,6 @@ _GL_CXXALIASWARN1 (memchr, void const *, - _GL_CXXALIASWARN (memchr); - # endif - #elif defined GNULIB_POSIXCHECK --# undef memchr - /* Assume memchr is always declared. */ - _GL_WARN_ON_USE (memchr, "memchr has platform-specific bugs - " - "use gnulib module memchr for portability" ); -@@ -674,7 +673,6 @@ _GL_WARN_ON_USE (stpncpy, "stpncpy is unportable - " - #if defined GNULIB_POSIXCHECK - /* strchr() does not work with multibyte strings if the locale encoding is - GB18030 and the character to be searched is a digit. */ --# undef strchr - /* Assume strchr is always declared. */ - _GL_WARN_ON_USE_CXX (strchr, - const char *, char *, (const char *, int), -@@ -981,7 +979,6 @@ _GL_CXXALIASWARN (strpbrk); - Even in this simple case, it does not work with multibyte strings if the - locale encoding is GB18030 and one of the characters to be searched is a - digit. */ --# undef strpbrk - _GL_WARN_ON_USE_CXX (strpbrk, - const char *, char *, (const char *, const char *), - "strpbrk cannot work correctly on character strings " -@@ -1011,7 +1008,6 @@ _GL_WARN_ON_USE (strspn, "strspn cannot work correctly on character strings " - #if defined GNULIB_POSIXCHECK - /* strrchr() does not work with multibyte strings if the locale encoding is - GB18030 and the character to be searched is a digit. */ --# undef strrchr - /* Assume strrchr is always declared. */ - _GL_WARN_ON_USE_CXX (strrchr, - const char *, char *, (const char *, int), -diff --git a/lib/wchar.in.h b/lib/wchar.in.h -index ab602a2..6be4515 100644 ---- a/lib/wchar.in.h -+++ b/lib/wchar.in.h -@@ -301,7 +301,7 @@ _GL_EXTERN_C int wcsncmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3); - # ifndef __cplusplus --_GL_EXTERN_C wchar_t *wmemchr (const wchar_t *__s, wchar_t __wc, size_t __n) -+_GL_EXTERN_C wchar_t *(wmemchr) (const wchar_t *__s, wchar_t __wc, size_t __n) - _GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3); - # endif - _GL_EXTERN_C wchar_t *wmemset (wchar_t *__s, wchar_t __wc, size_t __n) --- -2.52.0 - diff --git a/coreutils-colorls.csh b/coreutils-colorls.csh index 66ec2fa..f631762 100755 --- a/coreutils-colorls.csh +++ b/coreutils-colorls.csh @@ -15,6 +15,11 @@ alias l. 'ls -d .*' set COLORS=/etc/DIR_COLORS if ($?TERM) then + if ( -e "/etc/DIR_COLORS.256color" ) then + if ( "`/usr/bin/tput colors`" == "256" ) then + set COLORS=/etc/DIR_COLORS.256color + endif + endif if ( -e "/etc/DIR_COLORS.$TERM" ) then set COLORS="/etc/DIR_COLORS.$TERM" endif diff --git a/coreutils-colorls.sh b/coreutils-colorls.sh index 5162f1e..ac92268 100755 --- a/coreutils-colorls.sh +++ b/coreutils-colorls.sh @@ -22,6 +22,10 @@ if [ -z "$USER_LS_COLORS" ]; then [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.$TERM" ] && \ COLORS="/etc/DIR_COLORS.$TERM" + [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS.256color" ] && \ + [ "x`/usr/bin/tty -s && /usr/bin/tput colors 2>/dev/null`" = "x256" ] && \ + COLORS="/etc/DIR_COLORS.256color" + [ -z "$COLORS" ] && [ -e "/etc/DIR_COLORS" ] && \ COLORS="/etc/DIR_COLORS" diff --git a/coreutils-df-direct.patch b/coreutils-df-direct.patch index 341ee2c..a69d896 100644 --- a/coreutils-df-direct.patch +++ b/coreutils-df-direct.patch @@ -1,20 +1,8 @@ -From 91be1a584108a6a3d96f64382bbf206c4213b3db Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Mon, 29 Mar 2010 17:20:34 +0000 -Subject: [PATCH] coreutils-df-direct.patch - ---- - doc/coreutils.texi | 7 ++++++ - src/df.c | 34 ++++++++++++++++++++++++++-- - tests/df/direct.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 94 insertions(+), 2 deletions(-) - create mode 100755 tests/df/direct.sh - diff --git a/doc/coreutils.texi b/doc/coreutils.texi -index b420606..0ccb368 100644 +index a507280..400e135 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi -@@ -12597,6 +12597,13 @@ some systems (notably Solaris), doing this yields more up to date results, +@@ -11303,6 +11303,13 @@ some systems (notably SunOS), doing this yields more up to date results, but in general this option makes @command{df} much slower, especially when there are many or very busy file systems. @@ -27,12 +15,12 @@ index b420606..0ccb368 100644 + @item --total @opindex --total - @cindex grand total of file system size, usage and available space + @cindex grand total of disk size, usage and available space diff --git a/src/df.c b/src/df.c -index 75e638c..ef9f0a7 100644 +index 8f760db..a7385fd 100644 --- a/src/df.c +++ b/src/df.c -@@ -121,6 +121,9 @@ static bool print_type; +@@ -120,6 +120,9 @@ static bool print_type; /* If true, print a grand total at the end. */ static bool print_grand_total; @@ -42,7 +30,7 @@ index 75e638c..ef9f0a7 100644 /* Grand total data. */ static struct fs_usage grand_fsu; -@@ -248,13 +251,15 @@ enum +@@ -247,13 +250,15 @@ enum NO_SYNC_OPTION = CHAR_MAX + 1, SYNC_OPTION, TOTAL_OPTION, @@ -53,16 +41,16 @@ index 75e638c..ef9f0a7 100644 static struct option const long_options[] = { - {"all", no_argument, nullptr, 'a'}, - {"block-size", required_argument, nullptr, 'B'}, -+ {"direct", no_argument, nullptr, DIRECT_OPTION}, - {"inodes", no_argument, nullptr, 'i'}, - {"human-readable", no_argument, nullptr, 'h'}, - {"si", no_argument, nullptr, 'H'}, -@@ -571,7 +576,10 @@ get_header (void) - for (idx_t col = 0; col < ncolumns; col++) + {"all", no_argument, NULL, 'a'}, + {"block-size", required_argument, NULL, 'B'}, ++ {"direct", no_argument, NULL, DIRECT_OPTION}, + {"inodes", no_argument, NULL, 'i'}, + {"human-readable", no_argument, NULL, 'h'}, + {"si", no_argument, NULL, 'H'}, +@@ -509,7 +514,10 @@ get_header (void) + for (col = 0; col < ncolumns; col++) { - char *cell; + char *cell = NULL; - char const *header = _(columns[col]->caption); + char const *header = (columns[col]->field == TARGET_FIELD + && direct_statfs)? @@ -71,7 +59,7 @@ index 75e638c..ef9f0a7 100644 if (columns[col]->field == SIZE_FIELD && (header_mode == DEFAULT_MODE -@@ -1446,6 +1454,17 @@ get_point (char const *point, const struct stat *statp) +@@ -1397,6 +1405,19 @@ get_point (const char *point, const struct stat *statp) static void get_entry (char const *name, struct stat const *statp) { @@ -79,17 +67,19 @@ index 75e638c..ef9f0a7 100644 + { + char *resolved = canonicalize_file_name (name); + if (resolved) -+ { -+ get_dev (NULL, resolved, name, NULL, NULL, false, false, NULL, false); -+ free (resolved); -+ return; -+ } ++ { ++ char *mp = find_mount_point (name, statp); ++ get_dev (NULL, mp, resolved, NULL, NULL, false, false, NULL, false); ++ free(mp); ++ free (resolved); ++ return; ++ } + } + if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) - && get_device (name)) + && get_disk (name)) return; -@@ -1516,6 +1535,7 @@ or all file systems by default.\n\ +@@ -1467,6 +1488,7 @@ or all file systems by default.\n\ -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ '-BM' prints sizes in units of 1,048,576 bytes;\n\ see SIZE format below\n\ @@ -97,7 +87,7 @@ index 75e638c..ef9f0a7 100644 -h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\ -H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\ "), stdout); -@@ -1610,6 +1630,9 @@ main (int argc, char **argv) +@@ -1557,6 +1579,9 @@ main (int argc, char **argv) xstrtol_fatal (e, oi, c, long_options, optarg); } break; @@ -107,14 +97,14 @@ index 75e638c..ef9f0a7 100644 case 'i': if (header_mode == OUTPUT_MODE) { -@@ -1706,6 +1729,13 @@ main (int argc, char **argv) +@@ -1653,6 +1678,13 @@ main (int argc, char **argv) } } + if (direct_statfs && show_local_fs) + { + error (0, 0, _("options --direct and --local (-l) are mutually " -+ "exclusive")); ++ "exclusive")); + usage (EXIT_FAILURE); + } + @@ -122,7 +112,7 @@ index 75e638c..ef9f0a7 100644 { if (posix_format) diff --git a/tests/df/direct.sh b/tests/df/direct.sh -new file mode 100755 +new file mode 100644 index 0000000..8e4cfb8 --- /dev/null +++ b/tests/df/direct.sh @@ -182,6 +172,3 @@ index 0000000..8e4cfb8 +compare file_out file_exp || fail=1 + +Exit $fail --- -2.52.0 - diff --git a/coreutils-find-requires.sh b/coreutils-find-requires.sh new file mode 100755 index 0000000..27d1368 --- /dev/null +++ b/coreutils-find-requires.sh @@ -0,0 +1,25 @@ +#!/bin/sh - +# Reduce requires for coreutils-single +# Needed since it has overlapping "binaries" with the main package +# Ideally we could do the following in the spec only for the single subpackage +# %define __requires_exclude_from ^(%{_bindir}|%{_sbindir})/([^c]|c[^o]|co[^r]|cor[^e]) + +original_find_requires="$1" +shift + +# Get the list of files. +files=`sed "s/['\"]/\\\&/g"` + +single_bin='/usr/bin/coreutils' + +single=`echo $files | grep "$single_bin"` + +echo $files | tr [:blank:] '\n' | +if [ "$single" ]; then + # Only allow the coreutils multicall binary + # Also adjust for .single renaming + sed -n 's|\(.*'"$single_bin"'\)\(.single\)\?$|\1.single|p' +else + cat +fi | +$original_find_requires diff --git a/coreutils-getgrouplist.patch b/coreutils-getgrouplist.patch new file mode 100644 index 0000000..5b35f42 --- /dev/null +++ b/coreutils-getgrouplist.patch @@ -0,0 +1,86 @@ +diff --git a/lib/getugroups.c b/lib/getugroups.c +index 299bae6..8ece29b 100644 +--- a/lib/getugroups.c ++++ b/lib/getugroups.c +@@ -19,6 +19,9 @@ + + #include + ++/* We do not need this code if getgrouplist(3) is available. */ ++#ifndef HAVE_GETGROUPLIST ++ + #include "getugroups.h" + + #include +@@ -126,3 +129,4 @@ getugroups (int maxcount, gid_t *grouplist, char const *username, + } + + #endif /* HAVE_GRP_H */ ++#endif /* have getgrouplist */ +diff --git a/lib/mgetgroups.c b/lib/mgetgroups.c +index 76474c2..0a9d221 100644 +--- a/lib/mgetgroups.c ++++ b/lib/mgetgroups.c +@@ -121,9 +121,17 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) + /* else no username, so fall through and use getgroups. */ + #endif + +- max_n_groups = (username +- ? getugroups (0, NULL, username, gid) +- : getgroups (0, NULL)); ++ if (!username) ++ max_n_groups = getgroups(0, NULL); ++ else ++ { ++#ifdef HAVE_GETGROUPLIST ++ max_n_groups = 0; ++ getgrouplist (username, gid, NULL, &max_n_groups); ++#else ++ max_n_groups = getugroups (0, NULL, username, gid); ++#endif ++ } + + /* If we failed to count groups because there is no supplemental + group support, then return an array containing just GID. +@@ -145,10 +153,25 @@ mgetgroups (char const *username, gid_t gid, gid_t **groups) + if (g == NULL) + return -1; + +- ng = (username +- ? getugroups (max_n_groups, g, username, gid) +- : getgroups (max_n_groups - (gid != (gid_t) -1), +- g + (gid != (gid_t) -1))); ++ if (!username) ++ ng = getgroups (max_n_groups - (gid != (gid_t)-1), g + (gid != (gid_t)-1)); ++ else ++ { ++#ifdef HAVE_GETGROUPLIST ++ int e; ++ ng = max_n_groups; ++ while ((e = getgrouplist (username, gid, g, &ng)) == -1 ++ && ng > max_n_groups) ++ { ++ max_n_groups = ng; ++ g = xrealloc (g, max_n_groups * sizeof (GETGROUPS_T)); ++ } ++ if (e == -1) ++ ng = -1; ++#else ++ ng = getugroups (max_n_groups, g, username, gid); ++#endif ++ } + + if (ng < 0) + { +diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4 +index 62777c7..5180243 100644 +--- a/m4/jm-macros.m4 ++++ b/m4/jm-macros.m4 +@@ -82,6 +82,7 @@ AC_DEFUN([coreutils_MACROS], + fchown + fchmod + ftruncate ++ getgrouplist + iswspace + mkfifo + mbrlen diff --git a/coreutils-i18n-cut-old.patch b/coreutils-i18n-cut-old.patch new file mode 100644 index 0000000..7fcc8ff --- /dev/null +++ b/coreutils-i18n-cut-old.patch @@ -0,0 +1,565 @@ +diff --git a/src/cut.c b/src/cut.c +index 7ab6be4..022d0ad 100644 +--- a/src/cut.c ++++ b/src/cut.c +@@ -28,6 +28,11 @@ + #include + #include + #include ++ ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + #include "system.h" + + #include "error.h" +@@ -38,6 +43,18 @@ + + #include "set-fields.h" + ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# undef MB_LEN_MAX ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "cut" + +@@ -54,6 +71,52 @@ + } \ + while (0) + ++/* Refill the buffer BUF to get a multibyte character. */ ++#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ ++ do \ ++ { \ ++ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ ++ { \ ++ memmove (BUF, BUFPOS, BUFLEN); \ ++ BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ ++ BUFPOS = BUF; \ ++ } \ ++ } \ ++ while (0) ++ ++/* Get wide character on BUFPOS. BUFPOS is not included after that. ++ If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */ ++#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ if (BUFLEN < 1) \ ++ { \ ++ WC = WEOF; \ ++ break; \ ++ } \ ++ \ ++ /* Get a wide character. */ \ ++ CONVFAIL = false; \ ++ state_bak = STATE; \ ++ MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-1: \ ++ case (size_t)-2: \ ++ CONVFAIL = true; \ ++ STATE = state_bak; \ ++ /* Fall througn. */ \ ++ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ break; \ ++ } \ ++ } \ ++ while (0) ++ + + /* Pointer inside RP. When checking if a byte or field is selected + by a finite range, we check if it is between CURRENT_RP.LO +@@ -61,6 +124,9 @@ + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ + static struct field_range_pair *current_rp; + ++/* Length of the delimiter given as argument to -d. */ ++size_t delimlen; ++ + /* This buffer is used to support the semantics of the -s option + (or lack of same) when the specified field list includes (does + not include) the first field. In both of those cases, the entire +@@ -77,15 +143,25 @@ enum operating_mode + { + undefined_mode, + +- /* Output characters that are in the given bytes. */ ++ /* Output bytes that are at the given positions. */ + byte_mode, + ++ /* Output characters that are at the given positions. */ ++ character_mode, ++ + /* Output the given delimiter-separated fields. */ + field_mode + }; + + static enum operating_mode operating_mode; + ++/* If nonzero, when in byte mode, don't split multibyte characters. */ ++static int byte_mode_character_aware; ++ ++/* If nonzero, the function for single byte locale is work ++ if this program runs on multibyte locale. */ ++static int force_singlebyte_mode; ++ + /* If true do not output lines containing no delimiter characters. + Otherwise, all such lines are printed. This option is valid only + with field mode. */ +@@ -97,6 +173,9 @@ static bool complement; + + /* The delimiter character for field mode. */ + static unsigned char delim; ++#if HAVE_WCHAR_H ++static wchar_t wcdelim; ++#endif + + /* The delimiter for each line/record. */ + static unsigned char line_delim = '\n'; +@@ -164,7 +243,7 @@ Print selected parts of lines from each FILE to standard output.\n\ + -f, --fields=LIST select only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b: don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\n\ +@@ -280,6 +359,82 @@ cut_bytes (FILE *stream) + } + } + ++#if HAVE_MBRTOWC ++/* This function is in use for the following case. ++ ++ 1. Read from the stream STREAM, printing to standard output any selected ++ characters. ++ ++ 2. Read from stream STREAM, printing to standard output any selected bytes, ++ without splitting multibyte characters. */ ++ ++static void ++cut_characters_or_cut_bytes_no_split (FILE *stream) ++{ ++ size_t idx; /* number of bytes or characters in the line so far. */ ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail = false; /* true, when conversion failed. Otherwise false. */ ++ /* Whether to begin printing delimiters between ranges for the current line. ++ Set after we've begun printing data corresponding to the first range. */ ++ bool print_delimiter = false; ++ ++ idx = 0; ++ buflen = 0; ++ bufpos = buf; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ current_rp = frp; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); ++ (void) convfail; /* ignore unused */ ++ ++ if (wc == WEOF) ++ { ++ if (idx > 0) ++ putchar (line_delim); ++ break; ++ } ++ else if (wc == line_delim) ++ { ++ putchar (line_delim); ++ idx = 0; ++ print_delimiter = false; ++ current_rp = frp; ++ } ++ else ++ { ++ next_item (&idx); ++ if (print_kth (idx)) ++ { ++ if (output_delimiter_specified) ++ { ++ if (print_delimiter && is_range_start_index (idx)) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ print_delimiter = true; ++ } ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ } ++ } ++ ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++} ++#endif ++ + /* Read from stream STREAM, printing to standard output any selected fields. */ + + static void +@@ -425,13 +580,211 @@ cut_fields (FILE *stream) + } + } + ++#if HAVE_MBRTOWC ++static void ++cut_fields_mb (FILE *stream) ++{ ++ int c; ++ size_t field_idx; ++ int found_any_selected_field; ++ int buffer_first_field; ++ int empty_input; ++ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ ++ char *bufpos; /* Next read position of BUF. */ ++ size_t buflen; /* The length of the byte sequence in buf. */ ++ wint_t wc = 0; /* A gotten wide character. */ ++ size_t mblength; /* The byte size of a multibyte character which shows ++ as same character as WC. */ ++ mbstate_t state; /* State of the stream. */ ++ bool convfail = false; /* true, when conversion failed. Otherwise false. */ ++ ++ current_rp = frp; ++ ++ found_any_selected_field = 0; ++ field_idx = 1; ++ bufpos = buf; ++ buflen = 0; ++ memset (&state, '\0', sizeof(mbstate_t)); ++ ++ c = getc (stream); ++ empty_input = (c == EOF); ++ if (c != EOF) ++ { ++ ungetc (c, stream); ++ wc = 0; ++ } ++ else ++ wc = WEOF; ++ ++ /* To support the semantics of the -s flag, we may have to buffer ++ all of the first field to determine whether it is `delimited.' ++ But that is unnecessary if all non-delimited lines must be printed ++ and the first field has been selected, or if non-delimited lines ++ must be suppressed and the first field has *not* been selected. ++ That is because a non-delimited line has exactly one field. */ ++ buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); ++ ++ while (1) ++ { ++ if (field_idx == 1 && buffer_first_field) ++ { ++ int len = 0; ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ ++ field_1_buffer = xrealloc (field_1_buffer, len + mblength); ++ memcpy (field_1_buffer + len, bufpos, mblength); ++ len += mblength; ++ buflen -= mblength; ++ bufpos += mblength; ++ ++ if (!convfail && (wc == line_delim || wc == wcdelim)) ++ break; ++ } ++ ++ if (len <= 0 && wc == WEOF) ++ break; ++ ++ /* If the first field extends to the end of line (it is not ++ delimited) and we are printing all non-delimited lines, ++ print this one. */ ++ if (convfail || (!convfail && wc != wcdelim)) ++ { ++ if (suppress_non_delimited) ++ { ++ /* Empty. */ ++ } ++ else ++ { ++ fwrite (field_1_buffer, sizeof (char), len, stdout); ++ /* Make sure the output line is newline terminated. */ ++ if (convfail || (!convfail && wc != line_delim)) ++ putchar (line_delim); ++ } ++ continue; ++ } ++ ++ if (print_kth (1)) ++ { ++ /* Print the field, but not the trailing delimiter. */ ++ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); ++ found_any_selected_field = 1; ++ } ++ next_item (&field_idx); ++ } ++ ++ if (wc != WEOF) ++ { ++ if (print_kth (field_idx)) ++ { ++ if (found_any_selected_field) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ found_any_selected_field = 1; ++ } ++ ++ while (1) ++ { ++ REFILL_BUFFER (buf, bufpos, buflen, stream); ++ ++ GET_NEXT_WC_FROM_BUFFER ++ (wc, bufpos, buflen, mblength, state, convfail); ++ ++ if (wc == WEOF) ++ break; ++ else if (!convfail && (wc == wcdelim || wc == line_delim)) ++ { ++ buflen -= mblength; ++ bufpos += mblength; ++ break; ++ } ++ ++ if (print_kth (field_idx)) ++ fwrite (bufpos, mblength, sizeof(char), stdout); ++ ++ buflen -= mblength; ++ bufpos += mblength; ++ } ++ } ++ ++ if ((!convfail || wc == line_delim) && buflen < 1) ++ wc = WEOF; ++ ++ if (!convfail && wc == wcdelim) ++ next_item (&field_idx); ++ else if (wc == WEOF || (!convfail && wc == line_delim)) ++ { ++ if (found_any_selected_field ++ || (!empty_input && !(suppress_non_delimited && field_idx == 1))) ++ putchar (line_delim); ++ if (wc == WEOF) ++ break; ++ field_idx = 1; ++ current_rp = frp; ++ found_any_selected_field = 0; ++ } ++ } ++} ++#endif ++ + static void + cut_stream (FILE *stream) + { +- if (operating_mode == byte_mode) +- cut_bytes (stream); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ switch (operating_mode) ++ { ++ case byte_mode: ++ if (byte_mode_character_aware) ++ cut_characters_or_cut_bytes_no_split (stream); ++ else ++ cut_bytes (stream); ++ break; ++ ++ case character_mode: ++ cut_characters_or_cut_bytes_no_split (stream); ++ break; ++ ++ case field_mode: ++ if (delimlen == 1) ++ { ++ /* Check if we have utf8 multibyte locale, so we can use this ++ optimization because of uniqueness of characters, which is ++ not true for e.g. SJIS */ ++ char * loc = setlocale(LC_CTYPE, NULL); ++ if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") || ++ strstr (loc, "UTF8") || strstr (loc, "utf8"))) ++ { ++ cut_fields (stream); ++ break; ++ } ++ } ++ cut_fields_mb (stream); ++ break; ++ ++ default: ++ abort (); ++ } ++ } + else +- cut_fields (stream); ++#endif ++ { ++ if (operating_mode == field_mode) ++ cut_fields (stream); ++ else ++ cut_bytes (stream); ++ } + } + + /* Process file FILE to standard output. +@@ -483,6 +836,7 @@ main (int argc, char **argv) + bool ok; + bool delim_specified = false; + char *spec_list_string IF_LINT ( = NULL); ++ char mbdelim[MB_LEN_MAX + 1]; + + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -505,7 +859,6 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -513,6 +866,14 @@ main (int argc, char **argv) + spec_list_string = optarg; + break; + ++ case 'c': ++ /* Build the character list. */ ++ if (operating_mode != undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode = character_mode; ++ spec_list_string = optarg; ++ break; ++ + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) +@@ -524,10 +885,38 @@ main (int argc, char **argv) + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ +- if (optarg[0] != '\0' && optarg[1] != '\0') +- FATAL_ERROR (_("the delimiter must be a single character")); +- delim = optarg[0]; +- delim_specified = true; ++ { ++#if HAVE_MBRTOWC ++ if(MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, '\0', sizeof(mbstate_t)); ++ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state); ++ ++ if (delimlen == (size_t)-1 || delimlen == (size_t)-2) ++ ++force_singlebyte_mode; ++ else ++ { ++ delimlen = (delimlen < 1) ? 1 : delimlen; ++ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ memcpy (mbdelim, optarg, delimlen); ++ mbdelim[delimlen] = '\0'; ++ if (delimlen == 1) ++ delim = *optarg; ++ } ++ } ++ ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ if (optarg[0] != '\0' && optarg[1] != '\0') ++ FATAL_ERROR (_("the delimiter must be a single character")); ++ delim = (unsigned char) optarg[0]; ++ } ++ delim_specified = true; ++ } + break; + + case OUTPUT_DELIMITER_OPTION: +@@ -540,6 +929,7 @@ main (int argc, char **argv) + break; + + case 'n': ++ byte_mode_character_aware = 1; + break; + + case 's': +@@ -579,15 +969,34 @@ main (int argc, char **argv) + | (complement ? SETFLD_COMPLEMENT : 0) ); + + if (!delim_specified) +- delim = '\t'; ++ { ++ delim = '\t'; ++#ifdef HAVE_MBRTOWC ++ wcdelim = L'\t'; ++ mbdelim[0] = '\t'; ++ mbdelim[1] = '\0'; ++ delimlen = 1; ++#endif ++ } + + if (output_delimiter_string == NULL) + { +- static char dummy[2]; +- dummy[0] = delim; +- dummy[1] = '\0'; +- output_delimiter_string = dummy; +- output_delimiter_length = 1; ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) ++ { ++ output_delimiter_string = xstrdup(mbdelim); ++ output_delimiter_length = delimlen; ++ } ++ ++ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) ++#endif ++ { ++ static char dummy[2]; ++ dummy[0] = delim; ++ dummy[1] = '\0'; ++ output_delimiter_string = dummy; ++ output_delimiter_length = 1; ++ } + } + + if (optind == argc) diff --git a/coreutils-i18n-cut.patch b/coreutils-i18n-cut.patch new file mode 100644 index 0000000..f4015d1 --- /dev/null +++ b/coreutils-i18n-cut.patch @@ -0,0 +1,587 @@ +(sb) lin18nux/lsb compliance - cut - not stable enough, not applied + +--- coreutils-8.24/src/cut.c 2015-06-26 19:05:22.000000000 +0200 ++++ cut.c 2016-01-15 10:15:04.863804121 +0100 +@@ -28,6 +28,11 @@ + #include + #include + #include ++ ++#include ++#include ++#include ++ + #include "system.h" + + #include "error.h" +@@ -61,25 +66,16 @@ + CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ + static struct field_range_pair *current_rp; + +-/* This buffer is used to support the semantics of the -s option +- (or lack of same) when the specified field list includes (does +- not include) the first field. In both of those cases, the entire +- first field must be read into this buffer to determine whether it +- is followed by a delimiter or a newline before any of it may be +- output. Otherwise, cut_fields can do the job without using this +- buffer. */ +-static char *field_1_buffer; +- +-/* The number of bytes allocated for FIELD_1_BUFFER. */ +-static size_t field_1_bufsize; +- + enum operating_mode + { + undefined_mode, + +- /* Output characters that are in the given bytes. */ ++ /* Output the given bytes. */ + byte_mode, + ++ /* Output characters that are in the given positions . */ ++ char_mode, ++ + /* Output the given delimiter-separated fields. */ + field_mode + }; +@@ -91,12 +87,16 @@ static enum operating_mode operating_mode; + with field mode. */ + static bool suppress_non_delimited; + ++/* Unless true, we do not recognize multibyte characters in byte-splitting ++ mode. */ ++static bool no_break_mb_chars; ++ + /* If true, print all bytes, characters, or fields _except_ + those that were specified. */ + static bool complement; + + /* The delimiter character for field mode. */ +-static unsigned char delim; ++static mbf_char_t delim; + + /* The delimiter for each line/record. */ + static unsigned char line_delim = '\n'; +@@ -109,7 +109,7 @@ static size_t output_delimiter_length; + + /* The output field separator string. Defaults to the 1-character + string consisting of the input delimiter. */ +-static char *output_delimiter_string; ++static char const *output_delimiter_string; + + /* True if we have ever read standard input. */ + static bool have_read_stdin; +@@ -164,7 +164,7 @@ Print selected parts of lines from each FILE to standard output.\n\ + -f, --fields=LIST select only these fields; also print any line\n\ + that contains no delimiter character, unless\n\ + the -s option is specified\n\ +- -n (ignored)\n\ ++ -n with -b, don't split multibyte characters\n\ + "), stdout); + fputs (_("\ + --complement complement the set of selected bytes, characters\n\ +@@ -211,6 +211,12 @@ next_item (size_t *item_idx) + current_rp++; + } + ++static inline void ++next_item_n (size_t *item_idx, size_t n) ++{ ++ while (n-- > 0) ++ next_item (item_idx); ++} + /* Return nonzero if the K'th field or byte is printable. */ + + static inline bool +@@ -219,6 +225,15 @@ print_kth (size_t k) + return current_rp->lo <= k; + } + ++/* The lo and hi params should be used for the current characters byte position ++ * and byte size, respectively. */ ++static inline bool ++rp_intersect (size_t lo, size_t hi) ++{ ++ return ((current_rp->lo <= lo && current_rp->hi >= lo) ++ || (current_rp->lo <= hi && current_rp->hi >= hi)); ++} ++ + /* Return nonzero if K'th byte is the beginning of a range. */ + + static inline bool +@@ -281,23 +296,215 @@ cut_bytes (FILE *stream) + } + + /* Read from stream STREAM, printing to standard output any selected fields. */ ++extern ssize_t ++mb_getndelim2 (mbf_char_t **lineptr, size_t *linesize, size_t nmax, ++ mbf_char_t delim1, mbf_char_t delim2, mb_file_t *stream) ++{ ++/* The maximum value that getndelim2 can return without suffering from ++ overflow problems, either internally (because of pointer ++ subtraction overflow) or due to the API (because of ssize_t). */ ++#define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX) ++ ++/* Try to add at least this many bytes when extending the buffer. ++ MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */ ++#define MIN_CHUNK 64 ++ size_t nchars_avail; /* Allocated but unused chars in *LINEPTR. */ ++ mbf_char_t *read_pos; /* Where we're reading into *LINEPTR. */ ++ ssize_t chars_stored = -1; ++ mbf_char_t *ptr = *lineptr; ++ size_t size = *linesize; ++ bool found_delimiter; ++ ++ if (!ptr) ++ { ++ size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK; ++ ptr = malloc (size * sizeof (mbf_char_t)); ++ if (!ptr) ++ return -1; ++ } ++ ++ if (size < 0) ++ goto done; ++ ++ nchars_avail = size; ++ read_pos = ptr; ++ ++ if (nchars_avail == 0 && nmax <= size) ++ goto done; ++ ++ /* Normalize delimiters, since memchr2 doesn't handle EOF. */ ++ if (mb_iseof (delim1)) ++ mb_copy (&delim1, &delim2); ++ else if (mb_iseof (delim2)) ++ mb_copy (&delim2, &delim1); ++ ++ flockfile (stream); ++ ++ found_delimiter = false; ++ do ++ { ++ /* Here always ptr + size == read_pos + nchars_avail. ++ Also nchars_avail > 0 || size < nmax. */ ++ ++ mbf_char_t c IF_LINT (= 0); ++ { ++ mbf_getc (c, *stream); ++ if (mb_iseof (c)) ++ { ++ /* Return partial line, if any. */ ++ if (read_pos == ptr) ++ goto unlock_done; ++ else ++ break; ++ } ++ if (mb_equal (c, delim1) || mb_equal (c, delim2)) ++ found_delimiter = true; ++ } ++ ++ /* We always want at least one byte left in the buffer, since we ++ always (unless we get an error while reading the first byte) ++ NUL-terminate the line buffer. */ ++ ++ if (!nchars_avail) ++ { ++ /* Grow size proportionally, not linearly, to avoid O(n^2) ++ running time. */ ++ size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size; ++ mbf_char_t *newptr; ++ ++ /* Respect nmax. This handles possible integer overflow. */ ++ if (! (size < newsize && newsize <= nmax)) ++ newsize = nmax; ++ ++ if (GETNDELIM2_MAXIMUM < newsize) ++ { ++ size_t newsizemax = GETNDELIM2_MAXIMUM + 1; ++ if (size == newsizemax) ++ goto unlock_done; ++ newsize = newsizemax; ++ } ++ nchars_avail = newsize - (read_pos - ptr); ++ newptr = realloc (ptr, newsize * sizeof (mbf_char_t)); ++ if (!newptr) ++ goto unlock_done; ++ ptr = newptr; ++ size = newsize; ++ read_pos = size - nchars_avail + ptr; ++ } ++ ++ /* Here, if size < nmax, nchars_avail >= buffer_len + 1. ++ If size == nmax, nchars_avail > 0. */ ++ ++ if (1 < nchars_avail--) ++ { ++ mb_copy(read_pos++, &c); ++ } ++ ++ } ++ while (!found_delimiter); ++ ++ chars_stored = (read_pos - ptr); ++ ++ unlock_done: ++ funlockfile (stream); ++ ++ done: ++ *lineptr = ptr; ++ *linesize = size; ++ return chars_stored; ++} ++ ++static void ++cut_chars (FILE *stream) ++{ ++ size_t char_idx; /* Number of chars in the line so far. */ ++ bool print_delimiter; ++ mbf_char_t c; ++ mb_file_t mbf; ++ ++ print_delimiter = false; ++ char_idx = 0; ++ current_rp = frp; ++ ++ mbf_init (mbf, stream); ++ while (true) ++ { ++ mbf_getc (c, mbf); ++ ++ if (mb_iseq (c, line_delim)) ++ { ++ putc (line_delim, stdout); ++ char_idx = 0; ++ print_delimiter = false; ++ current_rp = frp; ++ } ++ else if (mb_iseof (c)) ++ { ++ if (char_idx > 0) ++ putc (line_delim, stdout); ++ break; ++ } ++ else ++ { ++ /* Forward by one byte. */ ++ next_item (&char_idx); ++ ++ /* Check if the current characters byte range is within ++ * the argument list. */ ++ if (rp_intersect (char_idx, char_idx + mb_len (c) - 1)) ++ { ++ if (output_delimiter_specified) ++ { ++ if (print_delimiter && is_range_start_index (char_idx)) ++ { ++ fwrite (output_delimiter_string, sizeof (char), ++ output_delimiter_length, stdout); ++ } ++ print_delimiter = true; ++ } ++ mb_putc (c, stdout); ++ } ++ ++ /* Byte mode with multibyte characters uncut (-b -n). */ ++ if (no_break_mb_chars) ++ /* Forward by an additional byte_length (c) - 1. */ ++ next_item_n (&char_idx, mb_len (c) - 1); ++ } ++ } ++} + + static void + cut_fields (FILE *stream) + { +- int c; ++ ++ /* This buffer is used to support the semantics of the -s option ++ (or lack of same) when the specified field list includes (does ++ not include) the first field. In both of those cases, the entire ++ first field must be read into this buffer to determine whether it ++ is followed by a delimiter or a newline before any of it may be ++ output. Otherwise, cut_fields can do the job without using this ++ buffer. */ ++ mbf_char_t *field_1_buffer = 0; ++ /* The number of bytes allocated for FIELD_1_BUFFER. */ ++ size_t field_1_bufsize; ++ ++ ++ mbf_char_t c, d; ++ mb_file_t mbf; + size_t field_idx = 1; + bool found_any_selected_field = false; + bool buffer_first_field; + + current_rp = frp; + +- c = getc (stream); +- if (c == EOF) ++ mbf_init (mbf, stream); ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) + return; + +- ungetc (c, stream); +- c = 0; ++ mbf_ungetc (c, mbf); ++ mb_setascii (&c, 0); ++ mb_copy (&d, &delim); + + /* To support the semantics of the -s flag, we may have to buffer + all of the first field to determine whether it is 'delimited.' +@@ -312,10 +519,14 @@ cut_fields (FILE *stream) + if (field_idx == 1 && buffer_first_field) + { + ssize_t len; +- size_t n_bytes; ++ size_t n_chars; ++ mbf_char_t nl; ++ mb_setascii (&nl, line_delim); ++ ++ len = mb_getndelim2 (&field_1_buffer, &field_1_bufsize, ++ GETNLINE_NO_LIMIT, d, nl, &mbf); ++ + +- len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, +- GETNLINE_NO_LIMIT, delim, line_delim, stream); + if (len < 0) + { + free (field_1_buffer); +@@ -325,15 +536,15 @@ cut_fields (FILE *stream) + xalloc_die (); + } + +- n_bytes = len; +- assert (n_bytes != 0); ++ n_chars = len; ++ //assert (n_chars != 0); + +- c = 0; ++ mb_setascii (&c, 0); + + /* If the first field extends to the end of line (it is not + delimited) and we are printing all non-delimited lines, + print this one. */ +- if (to_uchar (field_1_buffer[n_bytes - 1]) != delim) ++ if (!mb_equal (field_1_buffer[n_chars - 1], d)) + { + if (suppress_non_delimited) + { +@@ -341,26 +552,30 @@ cut_fields (FILE *stream) + } + else + { +- fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); ++ for (int i = 0; i < n_chars; ++i) ++ mb_putc (field_1_buffer[i], stdout); ++ + /* Make sure the output line is newline terminated. */ +- if (field_1_buffer[n_bytes - 1] != line_delim) ++ if (!mb_iseq (field_1_buffer[n_chars - 1], line_delim)) + putchar (line_delim); +- c = line_delim; ++ mb_setascii (&c, line_delim); + } + continue; + } + if (print_kth (1)) + { + /* Print the field, but not the trailing delimiter. */ +- fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout); ++ for (int i = 0; i < n_chars - 1; ++i) ++ mb_putc (field_1_buffer[i], stdout); + + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ +- if (delim == line_delim) ++ if (mb_iseq (d, line_delim)) + { +- int last_c = getc (stream); +- if (last_c != EOF) ++ mbf_char_t last_c; ++ mbf_getc (last_c, mbf); ++ if (!mb_iseof (last_c)) + { +- ungetc (last_c, stream); ++ mbf_ungetc (last_c, mbf); + found_any_selected_field = true; + } + } +@@ -370,7 +585,8 @@ cut_fields (FILE *stream) + next_item (&field_idx); + } + +- int prev_c = c; ++ mbf_char_t prev_c; ++ mb_copy (&prev_c, &c); + + if (print_kth (field_idx)) + { +@@ -381,42 +597,46 @@ cut_fields (FILE *stream) + } + found_any_selected_field = true; + +- while ((c = getc (stream)) != delim && c != line_delim && c != EOF) ++ mbf_getc (c, mbf); ++ while (!mb_equal (c, d) && !mb_iseq (c, line_delim) && !mb_iseof (c)) + { +- putchar (c); +- prev_c = c; ++ mb_putc (c, stdout); ++ mb_copy (&prev_c, &c); ++ mbf_getc (c, mbf); + } + } + else + { +- while ((c = getc (stream)) != delim && c != line_delim && c != EOF) ++ mbf_getc (c, mbf); ++ while (!mb_equal (c, d) && !mb_iseq (c, line_delim) && !mb_iseof (c)) + { +- prev_c = c; ++ mb_copy (&prev_c, &c); ++ mbf_getc (c, mbf); + } + } + + /* With -d$'\n' don't treat the last '\n' as a delimiter. */ +- if (delim == line_delim && c == delim) ++ if (mb_iseq (d, line_delim) && mb_equal (c, d)) + { +- int last_c = getc (stream); +- if (last_c != EOF) +- ungetc (last_c, stream); ++ mbf_char_t last_c; ++ mbf_getc (last_c, mbf); ++ if (!mb_iseof (last_c)) ++ mbf_ungetc (last_c, mbf); + else +- c = last_c; ++ mb_copy (&c, &last_c); + } + +- if (c == delim) ++ if (mb_equal (c, d)) + next_item (&field_idx); +- else if (c == line_delim || c == EOF) ++ else if (mb_iseq (c, line_delim) || mb_iseof (c)) + { + if (found_any_selected_field + || !(suppress_non_delimited && field_idx == 1)) + { +- if (c == line_delim || prev_c != line_delim +- || delim == line_delim) ++ if (mb_iseq (c, line_delim) || !mb_iseq (prev_c, line_delim) || mb_iseq (d, line_delim)) + putchar (line_delim); + } +- if (c == EOF) ++ if (mb_iseof (c)) + break; + field_idx = 1; + current_rp = frp; +@@ -429,7 +649,14 @@ static void + cut_stream (FILE *stream) + { + if (operating_mode == byte_mode) +- cut_bytes (stream); ++ { ++ if (no_break_mb_chars) ++ cut_chars (stream); ++ else ++ cut_bytes (stream); ++ } ++ else if (operating_mode == char_mode) ++ cut_chars (stream); + else + cut_fields (stream); + } +@@ -483,6 +710,7 @@ main (int argc, char **argv) + bool ok; + bool delim_specified = false; + char *spec_list_string IF_LINT ( = NULL); ++ mbi_iterator_t iter; + + initialize_main (&argc, &argv); + set_program_name (argv[0]); +@@ -496,8 +724,10 @@ main (int argc, char **argv) + + /* By default, all non-delimited lines are printed. */ + suppress_non_delimited = false; ++ /* Default behaviour for -b, unless -n is also specified. */ ++ no_break_mb_chars = false; + +- delim = '\0'; ++ mb_setascii (&delim, '\0'); + have_read_stdin = false; + + while ((optc = getopt_long (argc, argv, "b:c:d:f:nsz", longopts, NULL)) != -1) +@@ -505,7 +735,6 @@ main (int argc, char **argv) + switch (optc) + { + case 'b': +- case 'c': + /* Build the byte list. */ + if (operating_mode != undefined_mode) + FATAL_ERROR (_("only one type of list may be specified")); +@@ -513,6 +742,14 @@ main (int argc, char **argv) + spec_list_string = optarg; + break; + ++ case 'c': ++ /* Build the char list. */ ++ if (operating_mode != undefined_mode) ++ FATAL_ERROR (_("only one type of list may be specified")); ++ operating_mode = char_mode; ++ spec_list_string = optarg; ++ break; ++ + case 'f': + /* Build the field list. */ + if (operating_mode != undefined_mode) +@@ -524,9 +761,17 @@ main (int argc, char **argv) + case 'd': + /* New delimiter. */ + /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ +- if (optarg[0] != '\0' && optarg[1] != '\0') ++ mbi_init (iter, optarg, strlen (optarg)); ++ if (!mbi_avail (iter)) ++ mb_setascii (&delim, '\0'); ++ else ++ { ++ mb_copy (&delim, &mbi_cur (iter)); ++ ++ mbi_advance (iter); ++ if (mbi_avail (iter)) + FATAL_ERROR (_("the delimiter must be a single character")); +- delim = optarg[0]; ++ } + delim_specified = true; + break; + +@@ -540,6 +785,7 @@ main (int argc, char **argv) + break; + + case 'n': ++ no_break_mb_chars = true; + break; + + case 's': +@@ -579,15 +825,12 @@ main (int argc, char **argv) + | (complement ? SETFLD_COMPLEMENT : 0) ); + + if (!delim_specified) +- delim = '\t'; ++ mb_setascii (&delim, '\t'); + + if (output_delimiter_string == NULL) + { +- static char dummy[2]; +- dummy[0] = delim; +- dummy[1] = '\0'; +- output_delimiter_string = dummy; +- output_delimiter_length = 1; ++ output_delimiter_string = mb_ptr (delim); ++ output_delimiter_length = mb_len (delim); + } + + if (optind == argc) diff --git a/coreutils-i18n-expand-unexpand.patch b/coreutils-i18n-expand-unexpand.patch new file mode 100644 index 0000000..b5f571f --- /dev/null +++ b/coreutils-i18n-expand-unexpand.patch @@ -0,0 +1,848 @@ +From e87ab5b991b08092a7e07af82b3ec822a8604151 Mon Sep 17 00:00:00 2001 +From: Ondrej Oprala +Date: Wed, 5 Aug 2015 09:15:09 +0200 +Subject: [PATCH] expand,unexpand: add multibyte support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* NEWS: Mention the changes. +* bootstrap.conf: Add mbfile to the list of modules. +* configure.ac: Properly initialize mbfile. +* src/expand.c (expand): Iterate over multibyte characters properly. +* src/unexpand.c (unexpand): Iterate over multibyte characters +properly. +* tests/local.mk: Add new tests. +* tests/{expand,unexpand}/mb.sh: New tests. + +Co-authored-by: Pádraig Brady +--- + bootstrap.conf | 1 + + configure.ac | 2 + + lib/mbfile.c | 3 + + lib/mbfile.h | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++ + m4/mbfile.m4 | 14 +++ + src/expand.c | 43 +++++---- + src/unexpand.c | 54 +++++++---- + tests/expand/mb.sh | 98 ++++++++++++++++++++ + tests/local.mk | 2 + + tests/unexpand/mb.sh | 97 ++++++++++++++++++++ + 10 files changed, 535 insertions(+), 34 deletions(-) + create mode 100644 lib/mbfile.c + create mode 100644 lib/mbfile.h + create mode 100644 m4/mbfile.m4 + create mode 100755 tests/expand/mb.sh + create mode 100755 tests/unexpand/mb.sh + +diff --git a/bootstrap.conf b/bootstrap.conf +index 8a0ff31..a1c78b2 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -152,6 +152,7 @@ gnulib_modules=" + maintainer-makefile + malloc-gnu + manywarnings ++ mbfile + mbrlen + mbrtowc + mbsalign +diff --git a/configure.ac b/configure.ac +index 1e74b36..24c9725 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -427,6 +427,8 @@ fi + # I'm leaving it here for now. This whole thing needs to be modernized... + gl_WINSIZE_IN_PTEM + ++gl_MBFILE ++ + gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H + + if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \ +diff --git a/lib/mbfile.c b/lib/mbfile.c +new file mode 100644 +index 0000000..b0a468e +--- /dev/null ++++ b/lib/mbfile.c +@@ -0,0 +1,3 @@ ++#include ++#define MBFILE_INLINE _GL_EXTERN_INLINE ++#include "mbfile.h" +diff --git a/lib/mbfile.h b/lib/mbfile.h +new file mode 100644 +index 0000000..11f1b12 +--- /dev/null ++++ b/lib/mbfile.h +@@ -0,0 +1,255 @@ ++/* Multibyte character I/O: macros for multi-byte encodings. ++ Copyright (C) 2001, 2005, 2009-2015 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Written by Mitsuru Chinen ++ and Bruno Haible . */ ++ ++/* The macros in this file implement multi-byte character input from a ++ stream. ++ ++ mb_file_t ++ is the type for multibyte character input stream, usable for variable ++ declarations. ++ ++ mbf_char_t ++ is the type for multibyte character or EOF, usable for variable ++ declarations. ++ ++ mbf_init (mbf, stream) ++ initializes the MB_FILE for reading from stream. ++ ++ mbf_getc (mbc, mbf) ++ reads the next multibyte character from mbf and stores it in mbc. ++ ++ mb_iseof (mbc) ++ returns true if mbc represents the EOF value. ++ ++ Here are the function prototypes of the macros. ++ ++ extern void mbf_init (mb_file_t mbf, FILE *stream); ++ extern void mbf_getc (mbf_char_t mbc, mb_file_t mbf); ++ extern bool mb_iseof (const mbf_char_t mbc); ++ */ ++ ++#ifndef _MBFILE_H ++#define _MBFILE_H 1 ++ ++#include ++#include ++#include ++#include ++ ++/* Tru64 with Desktop Toolkit C has a bug: must be included before ++ . ++ BSD/OS 4.1 has a bug: and must be included before ++ . */ ++#include ++#include ++#include ++ ++#include "mbchar.h" ++ ++#ifndef _GL_INLINE_HEADER_BEGIN ++ #error "Please include config.h first." ++#endif ++_GL_INLINE_HEADER_BEGIN ++#ifndef MBFILE_INLINE ++# define MBFILE_INLINE _GL_INLINE ++#endif ++ ++struct mbfile_multi { ++ FILE *fp; ++ bool eof_seen; ++ bool have_pushback; ++ mbstate_t state; ++ unsigned int bufcount; ++ char buf[MBCHAR_BUF_SIZE]; ++ struct mbchar pushback; ++}; ++ ++MBFILE_INLINE void ++mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf) ++{ ++ size_t bytes; ++ ++ /* If EOF has already been seen, don't use getc. This matters if ++ mbf->fp is connected to an interactive tty. */ ++ if (mbf->eof_seen) ++ goto eof; ++ ++ /* Return character pushed back, if there is one. */ ++ if (mbf->have_pushback) ++ { ++ mb_copy (mbc, &mbf->pushback); ++ mbf->have_pushback = false; ++ return; ++ } ++ ++ /* Before using mbrtowc, we need at least one byte. */ ++ if (mbf->bufcount == 0) ++ { ++ int c = getc (mbf->fp); ++ if (c == EOF) ++ { ++ mbf->eof_seen = true; ++ goto eof; ++ } ++ mbf->buf[0] = (unsigned char) c; ++ mbf->bufcount++; ++ } ++ ++ /* Handle most ASCII characters quickly, without calling mbrtowc(). */ ++ if (mbf->bufcount == 1 && mbsinit (&mbf->state) && is_basic (mbf->buf[0])) ++ { ++ /* These characters are part of the basic character set. ISO C 99 ++ guarantees that their wide character code is identical to their ++ char code. */ ++ mbc->wc = mbc->buf[0] = mbf->buf[0]; ++ mbc->wc_valid = true; ++ mbc->ptr = &mbc->buf[0]; ++ mbc->bytes = 1; ++ mbf->bufcount = 0; ++ return; ++ } ++ ++ /* Use mbrtowc on an increasing number of bytes. Read only as many bytes ++ from mbf->fp as needed. This is needed to give reasonable interactive ++ behaviour when mbf->fp is connected to an interactive tty. */ ++ for (;;) ++ { ++ /* We don't know whether the 'mbrtowc' function updates the state when ++ it returns -2, - this is the ISO C 99 and glibc-2.2 behaviour - or ++ not - amended ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We ++ don't have an autoconf test for this, yet. ++ The new behaviour would allow us to feed the bytes one by one into ++ mbrtowc. But the old behaviour forces us to feed all bytes since ++ the end of the last character into mbrtowc. Since we want to retry ++ with more bytes when mbrtowc returns -2, we must backup the state ++ before calling mbrtowc, because implementations with the new ++ behaviour will clobber it. */ ++ mbstate_t backup_state = mbf->state; ++ ++ bytes = mbrtowc (&mbc->wc, &mbf->buf[0], mbf->bufcount, &mbf->state); ++ ++ if (bytes == (size_t) -1) ++ { ++ /* An invalid multibyte sequence was encountered. */ ++ /* Return a single byte. */ ++ bytes = 1; ++ mbc->wc_valid = false; ++ break; ++ } ++ else if (bytes == (size_t) -2) ++ { ++ /* An incomplete multibyte character. */ ++ mbf->state = backup_state; ++ if (mbf->bufcount == MBCHAR_BUF_SIZE) ++ { ++ /* An overlong incomplete multibyte sequence was encountered. */ ++ /* Return a single byte. */ ++ bytes = 1; ++ mbc->wc_valid = false; ++ break; ++ } ++ else ++ { ++ /* Read one more byte and retry mbrtowc. */ ++ int c = getc (mbf->fp); ++ if (c == EOF) ++ { ++ /* An incomplete multibyte character at the end. */ ++ mbf->eof_seen = true; ++ bytes = mbf->bufcount; ++ mbc->wc_valid = false; ++ break; ++ } ++ mbf->buf[mbf->bufcount] = (unsigned char) c; ++ mbf->bufcount++; ++ } ++ } ++ else ++ { ++ if (bytes == 0) ++ { ++ /* A null wide character was encountered. */ ++ bytes = 1; ++ assert (mbf->buf[0] == '\0'); ++ assert (mbc->wc == 0); ++ } ++ mbc->wc_valid = true; ++ break; ++ } ++ } ++ ++ /* Return the multibyte sequence mbf->buf[0..bytes-1]. */ ++ mbc->ptr = &mbc->buf[0]; ++ memcpy (&mbc->buf[0], &mbf->buf[0], bytes); ++ mbc->bytes = bytes; ++ ++ mbf->bufcount -= bytes; ++ if (mbf->bufcount > 0) ++ { ++ /* It's not worth calling memmove() for so few bytes. */ ++ unsigned int count = mbf->bufcount; ++ char *p = &mbf->buf[0]; ++ ++ do ++ { ++ *p = *(p + bytes); ++ p++; ++ } ++ while (--count > 0); ++ } ++ return; ++ ++eof: ++ /* An mbchar_t with bytes == 0 is used to indicate EOF. */ ++ mbc->ptr = NULL; ++ mbc->bytes = 0; ++ mbc->wc_valid = false; ++ return; ++} ++ ++MBFILE_INLINE void ++mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf) ++{ ++ mb_copy (&mbf->pushback, mbc); ++ mbf->have_pushback = true; ++} ++ ++typedef struct mbfile_multi mb_file_t; ++ ++typedef mbchar_t mbf_char_t; ++ ++#define mbf_init(mbf, stream) \ ++ ((mbf).fp = (stream), \ ++ (mbf).eof_seen = false, \ ++ (mbf).have_pushback = false, \ ++ memset (&(mbf).state, '\0', sizeof (mbstate_t)), \ ++ (mbf).bufcount = 0) ++ ++#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf)) ++ ++#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf)) ++ ++#define mb_iseof(mbc) ((mbc).bytes == 0) ++ ++#ifndef _GL_INLINE_HEADER_BEGIN ++ #error "Please include config.h first." ++#endif ++_GL_INLINE_HEADER_BEGIN ++ ++#endif /* _MBFILE_H */ +diff --git a/m4/mbfile.m4 b/m4/mbfile.m4 +new file mode 100644 +index 0000000..8589902 +--- /dev/null ++++ b/m4/mbfile.m4 +@@ -0,0 +1,14 @@ ++# mbfile.m4 serial 7 ++dnl Copyright (C) 2005, 2008-2015 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++dnl autoconf tests required for use of mbfile.h ++dnl From Bruno Haible. ++ ++AC_DEFUN([gl_MBFILE], ++[ ++ AC_REQUIRE([AC_TYPE_MBSTATE_T]) ++ : ++]) +diff --git a/src/expand.c b/src/expand.c +index 9fa2e10..380e020 100644 +--- a/src/expand.c ++++ b/src/expand.c +@@ -37,6 +37,9 @@ + #include + #include + #include ++ ++#include ++ + #include "system.h" + #include "die.h" + #include "xstrndup.h" +@@ -100,19 +103,19 @@ expand (void) + { + /* Input stream. */ + FILE *fp = next_file (NULL); ++ mb_file_t mbf; ++ mbf_char_t c; + + if (!fp) + return; + ++ mbf_init (mbf, fp); ++ + while (true) + { +- /* Input character, or EOF. */ +- int c; +- + /* If true, perform translations. */ + bool convert = true; + +- + /* The following variables have valid values only when CONVERT + is true: */ + +@@ -122,17 +125,23 @@ expand (void) + /* Index in TAB_LIST of next tab stop to examine. */ + size_t tab_index = 0; + +- + /* Convert a line of text. */ + + do + { +- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) +- continue; ++ do { ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) ++ { ++ mbf_init (mbf, fp = next_file (fp)); ++ continue; ++ } ++ } ++ while (false); + + if (convert) + { +- if (c == '\t') ++ if (mb_iseq (c, '\t')) + { + /* Column the next input tab stop is on. */ + uintmax_t next_tab_column; +@@ -151,32 +160,34 @@ expand (void) + if (putchar (' ') < 0) + die (EXIT_FAILURE, errno, _("write error")); + +- c = ' '; ++ mb_setascii (&c, ' '); + } +- else if (c == '\b') ++ else if (mb_iseq (c, '\b')) + { + /* Go back one column, and force recalculation of the + next tab stop. */ + column -= !!column; + tab_index -= !!tab_index; + } +- else ++ /* A leading control character could make us trip over. */ ++ else if (!mb_iscntrl (c)) + { +- column++; ++ column += mb_width (c); + if (!column) + die (EXIT_FAILURE, 0, _("input line is too long")); + } + +- convert &= convert_entire_line || !! isblank (c); ++ convert &= convert_entire_line || mb_isblank (c); + } + +- if (c < 0) ++ if (mb_iseof (c)) + return; + +- if (putchar (c) < 0) ++ mb_putc (c, stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + } +- while (c != '\n'); ++ while (!mb_iseq (c, '\n')); + } + } + +diff --git a/src/unexpand.c b/src/unexpand.c +index 7801274..569a7ee 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -38,6 +38,9 @@ + #include + #include + #include ++ ++#include ++ + #include "system.h" + #include "die.h" + #include "xstrndup.h" +@@ -107,11 +110,12 @@ unexpand (void) + { + /* Input stream. */ + FILE *fp = next_file (NULL); ++ mb_file_t mbf; + + /* The array of pending blanks. In non-POSIX locales, blanks can + include characters other than spaces, so the blanks must be + stored, not merely counted. */ +- char *pending_blank; ++ mbf_char_t *pending_blank; + + if (!fp) + return; +@@ -119,12 +123,14 @@ unexpand (void) + /* The worst case is a non-blank character, then one blank, then a + tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so + allocate MAX_COLUMN_WIDTH bytes to store the blanks. */ +- pending_blank = xmalloc (max_column_width); ++ pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t)); ++ ++ mbf_init (mbf, fp); + + while (true) + { + /* Input character, or EOF. */ +- int c; ++ mbf_char_t c; + + /* If true, perform translations. */ + bool convert = true; +@@ -158,12 +164,19 @@ unexpand (void) + + do + { +- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) +- continue; ++ do { ++ mbf_getc (c, mbf); ++ if (mb_iseof (c)) ++ { ++ mbf_init (mbf, fp = next_file (fp)); ++ continue; ++ } ++ } ++ while (false); + + if (convert) + { +- bool blank = !! isblank (c); ++ bool blank = mb_isblank (c); + + if (blank) + { +@@ -180,16 +193,16 @@ unexpand (void) + if (next_tab_column < column) + die (EXIT_FAILURE, 0, _("input line is too long")); + +- if (c == '\t') ++ if (mb_iseq (c, '\t')) + { + column = next_tab_column; + + if (pending) +- pending_blank[0] = '\t'; ++ mb_setascii (&pending_blank[0], '\t'); + } + else + { +- column++; ++ column += mb_width (c); + + if (! (prev_blank && column == next_tab_column)) + { +@@ -197,13 +210,14 @@ unexpand (void) + will be replaced by tabs. */ + if (column == next_tab_column) + one_blank_before_tab_stop = true; +- pending_blank[pending++] = c; ++ mb_copy (&pending_blank[pending++], &c); + prev_blank = true; + continue; + } + + /* Replace the pending blanks by a tab or two. */ +- pending_blank[0] = c = '\t'; ++ mb_setascii (&c, '\t'); ++ mb_setascii (&pending_blank[0], '\t'); + } + + /* Discard pending blanks, unless it was a single +@@ -211,7 +225,7 @@ unexpand (void) + pending = one_blank_before_tab_stop; + } + } +- else if (c == '\b') ++ else if (mb_iseq (c, '\b')) + { + /* Go back one column, and force recalculation of the + next tab stop. */ +@@ -221,7 +235,7 @@ unexpand (void) + } + else + { +- column++; ++ column += mb_width (c); + if (!column) + die (EXIT_FAILURE, 0, _("input line is too long")); + } +@@ -229,8 +243,11 @@ unexpand (void) + if (pending) + { + if (pending > 1 && one_blank_before_tab_stop) +- pending_blank[0] = '\t'; +- if (fwrite (pending_blank, 1, pending, stdout) != pending) ++ mb_setascii (&pending_blank[0], '\t'); ++ ++ for (int n = 0; n < pending; ++n) ++ mb_putc (pending_blank[n], stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + pending = 0; + one_blank_before_tab_stop = false; +@@ -240,16 +257,17 @@ unexpand (void) + convert &= convert_entire_line || blank; + } + +- if (c < 0) ++ if (mb_iseof (c)) + { + free (pending_blank); + return; + } + +- if (putchar (c) < 0) ++ mb_putc (c, stdout); ++ if (ferror (stdout)) + die (EXIT_FAILURE, errno, _("write error")); + } +- while (c != '\n'); ++ while (!mb_iseq (c, '\n')); + } + } + +diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh +new file mode 100755 +index 0000000..7971e18 +--- /dev/null ++++ b/tests/expand/mb.sh +@@ -0,0 +1,98 @@ ++#!/bin/sh ++ ++# Copyright (C) 2012-2015 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ expand ++ ++export LC_ALL=en_US.UTF-8 ++ ++#input containing multibyte characters ++cat <<\EOF > in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++EOF ++env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ ++ ++cat <<\EOF > exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++#test characters with display widths != 1 ++env printf '12345678 ++e\t|ascii(1) ++\u00E9\t|composed(1) ++e\u0301\t|decomposed(1) ++\u3000\t|ideo-space(2) ++\uFF0D\t|full-hypen(2) ++' > in || framework_failure_ ++ ++env printf '12345678 ++e |ascii(1) ++\u00E9 |composed(1) ++e\u0301 |decomposed(1) ++\u3000 |ideo-space(2) ++\uFF0D |full-hypen(2) ++' > exp || framework_failure_ ++ ++expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++#shouldn't fail with "input line too long" ++#when a line starts with a control character ++env printf '\n' > in || framework_failure_ ++ ++expand < in > out || fail=1 ++compare in out > /dev/null 2>&1 || fail=1 ++ ++#non-Unicode characters interspersed between Unicode ones ++env printf '12345678 ++\t\xFF| ++\xFF\t| ++\t\xFFä| ++ä\xFF\t| ++\tä\xFF| ++\xFF\tä| ++äbcdef\xFF\t| ++' > in || framework_failure_ ++ ++env printf '12345678 ++ \xFF| ++\xFF | ++ \xFFä| ++ä\xFF | ++ ä\xFF| ++\xFF ä| ++äbcdef\xFF | ++' > exp || framework_failure_ ++ ++expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++exit $fail +diff --git a/tests/local.mk b/tests/local.mk +index 192f776..8053397 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -544,6 +544,7 @@ all_tests = \ + tests/du/threshold.sh \ + tests/du/trailing-slash.sh \ + tests/du/two-args.sh \ ++ tests/expand/mb.sh \ + tests/id/gnu-zero-uids.sh \ + tests/id/no-context.sh \ + tests/id/context.sh \ +@@ -684,6 +685,7 @@ all_tests = \ + tests/touch/read-only.sh \ + tests/touch/relative.sh \ + tests/touch/trailing-slash.sh \ ++ tests/unexpand/mb.sh \ + $(all_root_tests) + + # See tests/factor/create-test.sh. +diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh +new file mode 100755 +index 0000000..60d4c1a +--- /dev/null ++++ b/tests/unexpand/mb.sh +@@ -0,0 +1,97 @@ ++#!/bin/sh ++ ++# Copyright (C) 2012-2015 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ unexpand ++ ++export LC_ALL=en_US.UTF-8 ++ ++#input containing multibyte characters ++cat > in <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++cat > exp <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++unexpand -a < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++#test characters with a display width larger than 1 ++ ++env printf '12345678 ++e |ascii(1) ++\u00E9 |composed(1) ++e\u0301 |decomposed(1) ++\u3000 |ideo-space(2) ++\uFF0D |full-hypen(2) ++' > in || framework_failure_ ++ ++env printf '12345678 ++e\t|ascii(1) ++\u00E9\t|composed(1) ++e\u0301\t|decomposed(1) ++\u3000\t|ideo-space(2) ++\uFF0D\t|full-hypen(2) ++' > exp || framework_failure_ ++ ++unexpand -a < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++#test input where a blank of width > 1 is not being substituted ++in="$(LC_ALL=en_US.UTF-8 printf ' \u3000 ö ü ß')" ++exp='   ö ü ß' ++ ++unexpand -a < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++#non-Unicode characters interspersed between Unicode ones ++env printf '12345678 ++ \xFF| ++\xFF | ++ \xFFä| ++ä\xFF | ++ ä\xFF| ++\xFF ä| ++äbcdef\xFF | ++' > in || framework_failure_ ++ ++env printf '12345678 ++\t\xFF| ++\xFF\t| ++\t\xFFä| ++ä\xFF\t| ++\tä\xFF| ++\xFF\tä| ++äbcdef\xFF\t| ++' > exp || framework_failure_ ++ ++unexpand -a < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 +-- +2.7.4 + diff --git a/coreutils-i18n-fix-unexpand.patch b/coreutils-i18n-fix-unexpand.patch new file mode 100644 index 0000000..f0c347c --- /dev/null +++ b/coreutils-i18n-fix-unexpand.patch @@ -0,0 +1,28 @@ +From 02424bfcd719bbaa695f4e1c3ef17ad91b0d23c0 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Thu, 28 Jan 2016 20:57:22 +0100 +Subject: [PATCH] unexpand: fix blank line handling + + echo '' |./src/unexpand -a + +Really? +--- + src/unexpand.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/unexpand.c b/src/unexpand.c +index 569a7ee..3bbbd66 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -233,7 +233,7 @@ unexpand (void) + next_tab_column = column; + tab_index -= !!tab_index; + } +- else ++ else if (!mb_iseq (c, '\n')) + { + column += mb_width (c); + if (!column) +-- +2.7.4 + diff --git a/coreutils-i18n-fix2-expand-unexpand.patch b/coreutils-i18n-fix2-expand-unexpand.patch new file mode 100644 index 0000000..b34d7b7 --- /dev/null +++ b/coreutils-i18n-fix2-expand-unexpand.patch @@ -0,0 +1,108 @@ +diff --git a/src/expand.c b/src/expand.c +index 380e020..310b349 100644 +--- a/src/expand.c ++++ b/src/expand.c +@@ -129,15 +129,19 @@ expand (void) + + do + { +- do { ++ while (true) { + mbf_getc (c, mbf); +- if (mb_iseof (c)) ++ if ((mb_iseof (c)) && (fp = next_file (fp))) + { +- mbf_init (mbf, fp = next_file (fp)); ++ mbf_init (mbf, fp); + continue; + } ++ else ++ { ++ break; ++ } + } +- while (false); ++ + + if (convert) + { +diff --git a/src/unexpand.c b/src/unexpand.c +index 3bbbd66..863a90a 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -164,15 +164,19 @@ unexpand (void) + + do + { +- do { ++ while (true) { + mbf_getc (c, mbf); +- if (mb_iseof (c)) ++ if ((mb_iseof (c)) && (fp = next_file (fp))) + { +- mbf_init (mbf, fp = next_file (fp)); ++ mbf_init (mbf, fp); + continue; + } ++ else ++ { ++ break; ++ } + } +- while (false); ++ + + if (convert) + { +diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh +index 7971e18..031be7a 100755 +--- a/tests/expand/mb.sh ++++ b/tests/expand/mb.sh +@@ -44,6 +44,20 @@ EOF + expand < in > out || fail=1 + compare exp out > /dev/null 2>&1 || fail=1 + ++#multiple files as an input ++cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++expand ./in ./in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ + #test characters with display widths != 1 + env printf '12345678 + e\t|ascii(1) +diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh +index 60d4c1a..8d75652 100755 +--- a/tests/unexpand/mb.sh ++++ b/tests/unexpand/mb.sh +@@ -44,6 +44,22 @@ EOF + unexpand -a < in > out || fail=1 + compare exp out > /dev/null 2>&1 || fail=1 + ++ ++#multiple files as an input ++cat >> exp <<\EOF ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++ ++unexpand -a ./in ./in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ + #test characters with a display width larger than 1 + + env printf '12345678 diff --git a/coreutils-i18n-fold-newline.patch b/coreutils-i18n-fold-newline.patch new file mode 100644 index 0000000..f7286ef --- /dev/null +++ b/coreutils-i18n-fold-newline.patch @@ -0,0 +1,80 @@ +From ff424639fe863cbd6963add1a79b97290c1606c6 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 3 Feb 2017 12:26:53 +0100 +Subject: [PATCH] fold.c: preserve new-lines in mutlibyte text + +--- + src/fold.c | 49 ++++++++++++++++++++++++------------------------- + 1 file changed, 24 insertions(+), 25 deletions(-) + +diff --git a/src/fold.c b/src/fold.c +index d23edd5..8c232a7 100644 +--- a/src/fold.c ++++ b/src/fold.c +@@ -342,39 +342,38 @@ fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) + } + + rescan: +- if (operating_mode == byte_mode) /* byte mode */ ++ if (convfail) ++ increment = 1; ++ else if (wc == L'\n') ++ { ++ /* preserve newline */ ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ } ++ else if (operating_mode == byte_mode) /* byte mode */ + increment = mblength; + else if (operating_mode == character_mode) /* character mode */ + increment = 1; +- else /* column mode */ ++ else /* column mode */ + { +- if (convfail) +- increment = 1; +- else ++ switch (wc) + { +- switch (wc) +- { +- case L'\n': +- fwrite (line_out, sizeof(char), offset_out, stdout); +- START_NEW_LINE; +- continue; ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; ++ break; + +- case L'\b': +- increment = (column > 0) ? -1 : 0; +- break; ++ case L'\r': ++ increment = -1 * column; ++ break; + +- case L'\r': +- increment = -1 * column; +- break; ++ case L'\t': ++ increment = 8 - column % 8; ++ break; + +- case L'\t': +- increment = 8 - column % 8; +- break; +- +- default: +- increment = wcwidth (wc); +- increment = (increment < 0) ? 0 : increment; +- } ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; + } + } + +-- +2.7.4 + diff --git a/coreutils-i18n-sort-human.patch b/coreutils-i18n-sort-human.patch new file mode 100644 index 0000000..6752493 --- /dev/null +++ b/coreutils-i18n-sort-human.patch @@ -0,0 +1,35 @@ +From 3976ef5a20369d8b490907ab2cba2d617305a5e0 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 30 May 2016 16:19:20 +0200 +Subject: [PATCH] sort: do not use static array 'blanks' in human_numcompare() + +... because the array is not initialized with MB locales. Note this is +rather a conservative fix. I plan to do more cleanup of the i18n patch +in Fedora to prevent mistakes like this in future updates of coreutils. +--- + src/sort.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/sort.c b/src/sort.c +index 9e07ad8..e47b039 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -2304,12 +2304,10 @@ find_unit_order (char const *number) + < K/k < M < G < T < P < E < Z < Y */ + + static int +-human_numcompare (char const *a, char const *b) ++human_numcompare (char *a, char *b) + { +- while (blanks[to_uchar (*a)]) +- a++; +- while (blanks[to_uchar (*b)]) +- b++; ++ skipblanks(&a, a + strlen(a)); ++ skipblanks(&b, b + strlen(b)); + + int diff = find_unit_order (a) - find_unit_order (b); + return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); +-- +2.5.5 + diff --git a/coreutils-i18n-un-expand-BOM.patch b/coreutils-i18n-un-expand-BOM.patch new file mode 100644 index 0000000..2ccdcca --- /dev/null +++ b/coreutils-i18n-un-expand-BOM.patch @@ -0,0 +1,456 @@ +From 7a7c776a4e228d180e74614fd8c8afcad5d4bdf7 Mon Sep 17 00:00:00 2001 +From: Jakub Martisko +Date: Thu, 7 Jul 2016 12:53:26 +0200 +Subject: [PATCH] coreutils-i18n-un-expand-BOM.patch + +--- + src/expand-common.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ + src/expand-common.h | 12 ++++++ + src/expand.c | 45 +++++++++++++++++++- + src/unexpand.c | 43 ++++++++++++++++++- + tests/expand/mb.sh | 71 ++++++++++++++++++++++++++++++++ + tests/unexpand/mb.sh | 59 ++++++++++++++++++++++++++ + 6 files changed, 342 insertions(+), 2 deletions(-) + +diff --git a/src/expand-common.c b/src/expand-common.c +index 4657e46..97cbb09 100644 +--- a/src/expand-common.c ++++ b/src/expand-common.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include "system.h" + #include "die.h" + #include "error.h" +@@ -105,6 +106,119 @@ set_extend_size (uintmax_t tabval) + return ok; + } + ++extern int ++set_utf_locale (void) ++{ ++ /*try using some predefined locale */ ++ const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"}; ++ ++ const int predef_locales_count=3; ++ for (int i=0;ibufcount=0; ++ if (c == 0xEF) ++ { ++ c=fgetc(fp); ++ } ++ else ++ { ++ if (c != EOF) ++ { ++ ungetc(c,fp); ++ } ++ return false; ++ } ++ ++ if (c == 0xBB) ++ { ++ c=fgetc(fp); ++ } ++ else ++ { ++ if ( c!= EOF ) ++ { ++ mbf->buf[0]=(unsigned char) 0xEF; ++ mbf->bufcount=1; ++ ungetc(c,fp); ++ return false; ++ } ++ else ++ { ++ ungetc(0xEF,fp); ++ return false; ++ } ++ } ++ if (c == 0xBF) ++ { ++ mbf->bufcount=0; ++ return true; ++ } ++ else ++ { ++ if (c != EOF) ++ { ++ mbf->buf[0]=(unsigned char) 0xEF; ++ mbf->buf[1]=(unsigned char) 0xBB; ++ mbf->bufcount=2; ++ ungetc(c,fp); ++ return false; ++ } ++ else ++ { ++ mbf->buf[0]=(unsigned char) 0xEF; ++ mbf->bufcount=1; ++ ungetc(0xBB,fp); ++ return false; ++ } ++ } ++ return false; ++} ++ ++extern void ++print_bom(void) ++{ ++ putc (0xEF, stdout); ++ putc (0xBB, stdout); ++ putc (0xBF, stdout); ++} ++ + /* Add the comma or blank separated list of tab stops STOPS + to the list of tab stops. */ + extern void +diff --git a/src/expand-common.h b/src/expand-common.h +index 8cb2079..763bfda 100644 +--- a/src/expand-common.h ++++ b/src/expand-common.h +@@ -34,6 +34,18 @@ extern size_t max_column_width; + /* The desired exit status. */ + extern int exit_status; + ++extern int ++set_utf_locale (void); ++ ++extern bool ++check_utf_locale(void); ++ ++extern bool ++check_bom(FILE* fp, mb_file_t *mbf); ++ ++extern void ++print_bom(void); ++ + /* Add tab stop TABVAL to the end of 'tab_list'. */ + extern void + add_tab_stop (uintmax_t tabval); +diff --git a/src/expand.c b/src/expand.c +index 310b349..4136824 100644 +--- a/src/expand.c ++++ b/src/expand.c +@@ -105,11 +105,33 @@ expand (void) + FILE *fp = next_file (NULL); + mb_file_t mbf; + mbf_char_t c; ++ /* True if the starting locale is utf8. */ ++ bool using_utf_locale; ++ ++ /* True if the first file contains BOM header. */ ++ bool found_bom; ++ using_utf_locale=check_utf_locale(); + + if (!fp) + return; +- + mbf_init (mbf, fp); ++ found_bom=check_bom(fp,&mbf); ++ ++ if (using_utf_locale == false && found_bom == true) ++ { ++ /*try using some predefined locale */ ++ ++ if (set_utf_locale () != 0) ++ { ++ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); ++ } ++ } ++ ++ ++ if (found_bom == true) ++ { ++ print_bom(); ++ } + + while (true) + { +@@ -134,6 +156,27 @@ expand (void) + if ((mb_iseof (c)) && (fp = next_file (fp))) + { + mbf_init (mbf, fp); ++ if (fp!=NULL) ++ { ++ if (check_bom(fp,&mbf)==true) ++ { ++ /*Not the first file - check BOM header*/ ++ if (using_utf_locale==false && found_bom==false) ++ { ++ /*BOM header in subsequent file but not in the first one. */ ++ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); ++ } ++ } ++ else ++ { ++ if(using_utf_locale==false && found_bom==true) ++ { ++ /*First file conatined BOM header - locale was switched to UTF ++ /*all subsequent files should contain BOM. */ ++ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); ++ } ++ } ++ } + continue; + } + else +diff --git a/src/unexpand.c b/src/unexpand.c +index 863a90a..5681b58 100644 +--- a/src/unexpand.c ++++ b/src/unexpand.c +@@ -116,16 +116,36 @@ unexpand (void) + include characters other than spaces, so the blanks must be + stored, not merely counted. */ + mbf_char_t *pending_blank; ++ /* True if the starting locale is utf8. */ ++ bool using_utf_locale; ++ ++ /* True if the first file contains BOM header. */ ++ bool found_bom; ++ using_utf_locale=check_utf_locale(); + + if (!fp) + return; ++ mbf_init (mbf, fp); ++ found_bom=check_bom(fp,&mbf); ++ ++ if (using_utf_locale == false && found_bom == true) ++ { ++ /*try using some predefined locale */ + ++ if (set_utf_locale () != 0) ++ { ++ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); ++ } ++ } + /* The worst case is a non-blank character, then one blank, then a + tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so + allocate MAX_COLUMN_WIDTH bytes to store the blanks. */ + pending_blank = xmalloc (max_column_width * sizeof (mbf_char_t)); + +- mbf_init (mbf, fp); ++ if (found_bom == true) ++ { ++ print_bom(); ++ } + + while (true) + { +@@ -169,6 +189,27 @@ unexpand (void) + if ((mb_iseof (c)) && (fp = next_file (fp))) + { + mbf_init (mbf, fp); ++ if (fp!=NULL) ++ { ++ if (check_bom(fp,&mbf)==true) ++ { ++ /*Not the first file - check BOM header*/ ++ if (using_utf_locale==false && found_bom==false) ++ { ++ /*BOM header in subsequent file but not in the first one. */ ++ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); ++ } ++ } ++ else ++ { ++ if(using_utf_locale==false && found_bom==true) ++ { ++ /*First file conatined BOM header - locale was switched to UTF ++ /*all subsequent files should contain BOM. */ ++ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); ++ } ++ } ++ } + continue; + } + else +diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh +index 031be7a..1621c84 100755 +--- a/tests/expand/mb.sh ++++ b/tests/expand/mb.sh +@@ -109,4 +109,75 @@ env printf '12345678 + expand < in > out || fail=1 + compare exp out > /dev/null 2>&1 || fail=1 + ++ ++ ++#BOM header test 1 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++EOF ++env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++ ++expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LANG=C expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LC_ALL=C expand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++ ++printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++EOF ++env printf ' äöü\t. öüä. \tä xx\n' >> in1 || framework_failure_ ++ ++ ++printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++expand in1 in1 > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LANG=C expand in1 in1 > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LC_ALL=C expand in1 in1 > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ + exit $fail +diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh +index 8d75652..9d4ee3e 100755 +--- a/tests/unexpand/mb.sh ++++ b/tests/unexpand/mb.sh +@@ -111,3 +111,62 @@ env printf '12345678 + + unexpand -a < in > out || fail=1 + compare exp out > /dev/null 2>&1 || fail=1 ++ ++#BOM header test 1 ++printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++unexpand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LANG=C unexpand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LC_ALL=C unexpand < in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++ ++printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++1234567812345678123456781 ++. . . . ++a b c d ++. . . . ++ä ö ü ß ++. . . . ++ äöü . öüä. ä xx ++EOF ++ ++ ++unexpand in in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LANG=C unexpand in in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 ++ ++LC_ALL=C unexpand in in > out || fail=1 ++compare exp out > /dev/null 2>&1 || fail=1 +-- +2.9.3 + diff --git a/coreutils-i18n.patch b/coreutils-i18n.patch index 83579e9..ab5d8dc 100644 --- a/coreutils-i18n.patch +++ b/coreutils-i18n.patch @@ -1,80 +1,39 @@ -From a81b096084524e9aeef5e8b81fc829eb9efec581 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Wed, 30 Aug 2023 17:19:58 +0200 +From 29117b2d07af00f4d4b87cf778e4294588ab1a83 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 1 Dec 2016 15:10:04 +0100 Subject: [PATCH] coreutils-i18n.patch +TODO: merge upstream --- - bootstrap.conf | 2 + - configure.ac | 6 + lib/linebuffer.h | 8 + - lib/mbfile.c | 20 + - lib/mbfile.h | 283 +++++++++++++ - m4/mbfile.m4 | 16 + - src/cut.c | 508 +++++++++++++++++++++-- - src/expand-common.c | 114 ++++++ - src/expand-common.h | 12 + - src/expand.c | 90 +++- - src/local.mk | 4 +- - src/pr.c | 443 ++++++++++++++++++-- - src/sort.c | 791 +++++++++++++++++++++++++++++++++--- - src/unexpand.c | 101 ++++- - tests/Coreutils.pm | 3 + - tests/expand/mb.sh | 183 +++++++++ + src/fold.c | 308 ++++++++++++++++-- + src/join.c | 359 ++++++++++++++++++--- + src/pr.c | 443 ++++++++++++++++++++++--- + src/sort.c | 764 +++++++++++++++++++++++++++++++++++++++++--- + src/uniq.c | 265 ++++++++++++++- tests/i18n/sort.sh | 29 ++ - tests/local.mk | 4 + - tests/misc/expand.pl | 42 ++ - tests/misc/sort-mb-tests.sh | 45 ++ - tests/misc/unexpand.pl | 39 ++ + tests/local.mk | 2 + + tests/misc/cut.pl | 7 +- + tests/misc/expand.pl | 42 +++ + tests/misc/fold.pl | 50 ++- + tests/misc/join.pl | 50 +++ + tests/misc/sort-mb-tests.sh | 45 +++ + tests/misc/sort-merge.pl | 42 +++ + tests/misc/sort.pl | 40 ++- + tests/misc/unexpand.pl | 39 +++ + tests/misc/uniq.pl | 55 ++++ tests/pr/pr-tests.pl | 49 +++ - tests/sort/sort-merge.pl | 42 ++ - tests/sort/sort.pl | 40 +- - tests/unexpand/mb.sh | 172 ++++++++ - 25 files changed, 2879 insertions(+), 167 deletions(-) - create mode 100644 lib/mbfile.c - create mode 100644 lib/mbfile.h - create mode 100644 m4/mbfile.m4 - create mode 100644 tests/expand/mb.sh + 18 files changed, 2435 insertions(+), 162 deletions(-) create mode 100644 tests/i18n/sort.sh create mode 100644 tests/misc/sort-mb-tests.sh - create mode 100644 tests/unexpand/mb.sh -diff --git a/bootstrap.conf b/bootstrap.conf -index ec68ac8..ec2fbbe 100644 ---- a/bootstrap.conf -+++ b/bootstrap.conf -@@ -171,6 +171,8 @@ gnulib_modules=" - malloc-gnu - manywarnings - mbbuf -+ mbchar -+ mbfile - mbrlen - mbrtoc32 - mbrtowc -diff --git a/configure.ac b/configure.ac -index 5e99ef3..ac07577 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -465,6 +465,12 @@ fi - # I'm leaving it here for now. This whole thing needs to be modernized... - gl_WINSIZE_IN_PTEM - -+gl_MBFILE -+dnl Do not use gl_MODULE_INDICATOR([mbfile]) here: we don't want 'struct mbchar' -+dnl to have a different size in lib/ than in tests/. -+AC_DEFINE([GNULIB_MBFILE], [1], -+ [Define to 1 if the gnulib module 'mbfile' is in use.]) -+ - gl_HEADER_TIOCGWINSZ_IN_TERMIOS_H - - if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no && \ diff --git a/lib/linebuffer.h b/lib/linebuffer.h -index ca56f80..509b7e6 100644 +index 64181af..9b8fe5a 100644 --- a/lib/linebuffer.h +++ b/lib/linebuffer.h -@@ -27,6 +27,11 @@ extern "C" { - #endif +@@ -21,6 +21,11 @@ + # include +/* Get mbstate_t. */ +# if HAVE_WCHAR_H @@ -84,9 +43,9 @@ index ca56f80..509b7e6 100644 /* A 'struct linebuffer' holds a line of text. */ struct linebuffer -@@ -34,6 +39,9 @@ struct linebuffer - idx_t size; /* Allocated. */ - idx_t length; /* Used. */ +@@ -28,6 +33,9 @@ struct linebuffer + size_t size; /* Allocated. */ + size_t length; /* Used. */ char *buffer; +# if HAVE_WCHAR_H + mbstate_t state; @@ -94,365 +53,32 @@ index ca56f80..509b7e6 100644 }; /* Initialize linebuffer LINEBUFFER for use. */ -diff --git a/lib/mbfile.c b/lib/mbfile.c -new file mode 100644 -index 0000000..f4e3e77 ---- /dev/null -+++ b/lib/mbfile.c -@@ -0,0 +1,20 @@ -+/* Multibyte character I/O: macros for multi-byte encodings. -+ Copyright (C) 2012-2025 Free Software Foundation, Inc. -+ -+ This file is free software: you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation, either version 3 of the -+ License, or (at your option) any later version. -+ -+ This file is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public License -+ along with this program. If not, see . */ -+ -+#include -+ -+#define MBFILE_INLINE _GL_EXTERN_INLINE -+#include "mbfile.h" -diff --git a/lib/mbfile.h b/lib/mbfile.h -new file mode 100644 -index 0000000..c852f31 ---- /dev/null -+++ b/lib/mbfile.h -@@ -0,0 +1,283 @@ -+/* Multibyte character I/O: macros for multi-byte encodings. -+ Copyright (C) 2001, 2005, 2009-2025 Free Software Foundation, Inc. -+ -+ This file is free software: you can redistribute it and/or modify -+ it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation, either version 3 of the -+ License, or (at your option) any later version. -+ -+ This file is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public License -+ along with this program. If not, see . */ -+ -+/* Written by Mitsuru Chinen -+ and Bruno Haible . */ -+ -+/* The macros in this file implement multi-byte character input from a -+ stream. -+ -+ mb_file_t -+ is the type for multibyte character input stream, usable for variable -+ declarations. -+ -+ mbf_char_t -+ is the type for multibyte character or EOF, usable for variable -+ declarations. -+ -+ mbf_init (mbf, stream) -+ initializes the MB_FILE for reading from stream. -+ -+ mbf_getc (mbc, mbf) -+ reads the next multibyte character from mbf and stores it in mbc. -+ -+ mb_iseof (mbc) -+ returns true if mbc represents the EOF value. -+ -+ Here are the function prototypes of the macros. -+ -+ extern void mbf_init (mb_file_t mbf, FILE *stream); -+ extern void mbf_getc (mbf_char_t mbc, mb_file_t mbf); -+ extern bool mb_iseof (const mbf_char_t mbc); -+ */ -+ -+#ifndef _MBFILE_H -+#define _MBFILE_H 1 -+ -+/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -+#if !_GL_CONFIG_H_INCLUDED -+ #error "Please include config.h first." -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "mbchar.h" -+ -+_GL_INLINE_HEADER_BEGIN -+#ifndef MBFILE_INLINE -+# define MBFILE_INLINE _GL_INLINE -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+/* Guarantee two characters of pushback. */ -+#define MBFILE_MAX_PUSHBACK 2 -+ -+struct mbfile_multi { -+ FILE *fp; -+ bool eof_seen; -+ unsigned int pushback_count; /* <= MBFILE_MAX_PUSHBACK */ -+ mbstate_t state; -+ unsigned int bufcount; -+ char buf[MBCHAR_BUF_SIZE]; -+ struct mbchar pushback[MBFILE_MAX_PUSHBACK]; -+}; -+ -+MBFILE_INLINE void -+mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf) -+{ -+ unsigned int new_bufcount; -+ size_t bytes; -+ -+ /* Return character pushed back, if there is one. */ -+ if (mbf->pushback_count > 0) -+ { -+ mb_copy (mbc, &mbf->pushback[mbf->pushback_count - 1]); -+ mbf->pushback_count--; -+ return; -+ } -+ -+ /* If EOF has already been seen, don't use getc. This matters if -+ mbf->fp is connected to an interactive tty. */ -+ if (mbf->eof_seen) -+ goto eof; -+ -+ new_bufcount = mbf->bufcount; -+ -+ /* If mbf->state is not in an initial state, some more 32-bit wide character -+ may be hiding in the state. We need to call mbrtoc32 again. */ -+ #if GNULIB_MBRTOC32_REGULAR -+ assert (mbsinit (&mbf->state)); -+ #else -+ if (mbsinit (&mbf->state)) -+ #endif -+ { -+ /* Before using mbrtoc32, we need at least one byte. */ -+ if (new_bufcount == 0) -+ { -+ int c = getc (mbf->fp); -+ if (c == EOF) -+ { -+ mbf->eof_seen = true; -+ goto eof; -+ } -+ mbf->buf[0] = (unsigned char) c; -+ new_bufcount++; -+ } -+ -+ /* Handle most ASCII characters quickly, without calling mbrtoc32(). */ -+ if (new_bufcount == 1 && is_basic (mbf->buf[0])) -+ { -+ /* These characters are part of the POSIX portable character set. -+ For most of them, namely those in the ISO C basic character set, -+ ISO C 99 guarantees that their wide character code is identical to -+ their char code. For the few other ones, this is the case as well, -+ in all locale encodings that are in use. The 32-bit wide character -+ code is the same as well. */ -+ mbc->wc = mbc->buf[0] = mbf->buf[0]; -+ mbc->wc_valid = true; -+ mbc->ptr = &mbc->buf[0]; -+ mbc->bytes = 1; -+ mbf->bufcount = 0; -+ return; -+ } -+ } -+ -+ /* Use mbrtoc32 on an increasing number of bytes. Read only as many bytes -+ from mbf->fp as needed. This is needed to give reasonable interactive -+ behaviour when mbf->fp is connected to an interactive tty. */ -+ for (;;) -+ { -+ /* Feed the bytes one by one into mbrtoc32. */ -+ bytes = mbrtoc32 (&mbc->wc, &mbf->buf[mbf->bufcount], new_bufcount - mbf->bufcount, &mbf->state); -+ -+ if (bytes == (size_t) -1) -+ { -+ /* An invalid multibyte sequence was encountered. */ -+ mbf->bufcount = new_bufcount; -+ /* Return a single byte. */ -+ bytes = 1; -+ mbc->wc_valid = false; -+ /* Allow the next invocation to continue from a sane state. */ -+ mbszero (&mbf->state); -+ break; -+ } -+ else if (bytes == (size_t) -2) -+ { -+ /* An incomplete multibyte character. */ -+ mbf->bufcount = new_bufcount; -+ if (mbf->bufcount == MBCHAR_BUF_SIZE) -+ { -+ /* An overlong incomplete multibyte sequence was encountered. */ -+ /* Return a single byte. */ -+ bytes = 1; -+ mbc->wc_valid = false; -+ break; -+ } -+ else -+ { -+ /* Read one more byte and retry mbrtoc32. */ -+ int c = getc (mbf->fp); -+ if (c == EOF) -+ { -+ /* An incomplete multibyte character at the end. */ -+ mbf->eof_seen = true; -+ bytes = new_bufcount; -+ mbc->wc_valid = false; -+ break; -+ } -+ mbf->buf[new_bufcount] = (unsigned char) c; -+ new_bufcount++; -+ } -+ } -+ else -+ { -+ #if !GNULIB_MBRTOC32_REGULAR -+ if (bytes == (size_t) -3) -+ { -+ /* The previous multibyte sequence produced an additional 32-bit -+ wide character. */ -+ mbf->bufcount = new_bufcount; -+ bytes = 0; -+ } -+ else -+ #endif -+ { -+ bytes = mbf->bufcount + bytes; -+ mbf->bufcount = new_bufcount; -+ if (bytes == 0) -+ { -+ /* A null 32-bit wide character was encountered. */ -+ bytes = 1; -+ assert (mbf->buf[0] == '\0'); -+ assert (mbc->wc == 0); -+ } -+ } -+ mbc->wc_valid = true; -+ break; -+ } -+ } -+ -+ /* Return the multibyte sequence mbf->buf[0..bytes-1]. */ -+ mbc->ptr = &mbc->buf[0]; -+ memcpy (&mbc->buf[0], &mbf->buf[0], bytes); -+ mbc->bytes = bytes; -+ -+ mbf->bufcount -= bytes; -+ if (mbf->bufcount > 0) -+ { -+ /* It's not worth calling memmove() for so few bytes. */ -+ unsigned int count = mbf->bufcount; -+ char *p = &mbf->buf[0]; -+ -+ do -+ { -+ *p = *(p + bytes); -+ p++; -+ } -+ while (--count > 0); -+ } -+ return; -+ -+eof: -+ /* An mbchar_t with bytes == 0 is used to indicate EOF. */ -+ mbc->ptr = NULL; -+ mbc->bytes = 0; -+ mbc->wc_valid = false; -+ return; -+} -+ -+MBFILE_INLINE void -+mbfile_multi_ungetc (const struct mbchar *mbc, struct mbfile_multi *mbf) -+{ -+ if (mbf->pushback_count == MBFILE_MAX_PUSHBACK) -+ abort (); -+ mb_copy (&mbf->pushback[mbf->pushback_count], mbc); -+ mbf->pushback_count++; -+} -+ -+typedef struct mbfile_multi mb_file_t; -+ -+typedef mbchar_t mbf_char_t; -+ -+#define mbf_init(mbf, stream) \ -+ ((mbf).fp = (stream), \ -+ (mbf).eof_seen = false, \ -+ (mbf).pushback_count = 0, \ -+ mbszero (&(mbf).state), \ -+ (mbf).bufcount = 0) -+ -+#define mbf_getc(mbc, mbf) mbfile_multi_getc (&(mbc), &(mbf)) -+ -+#define mbf_ungetc(mbc, mbf) mbfile_multi_ungetc (&(mbc), &(mbf)) -+ -+#define mb_iseof(mbc) ((mbc).bytes == 0) -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+_GL_INLINE_HEADER_END -+ -+#endif /* _MBFILE_H */ -diff --git a/m4/mbfile.m4 b/m4/mbfile.m4 -new file mode 100644 -index 0000000..1d126e0 ---- /dev/null -+++ b/m4/mbfile.m4 -@@ -0,0 +1,16 @@ -+# mbfile.m4 -+# serial 7 -+dnl Copyright (C) 2005, 2008-2025 Free Software Foundation, Inc. -+dnl This file is free software; the Free Software Foundation -+dnl gives unlimited permission to copy and/or distribute it, -+dnl with or without modifications, as long as this notice is preserved. -+dnl This file is offered as-is, without any warranty. -+ -+dnl autoconf tests required for use of mbfile.h -+dnl From Bruno Haible. -+ -+AC_DEFUN([gl_MBFILE], -+[ -+ AC_REQUIRE([AC_TYPE_MBSTATE_T]) -+ : -+]) -diff --git a/src/cut.c b/src/cut.c -index f0effb9..36479d6 100644 ---- a/src/cut.c -+++ b/src/cut.c -@@ -27,6 +27,11 @@ - #include +diff --git a/src/fold.c b/src/fold.c +index 8cd0d6b..d23edd5 100644 +--- a/src/fold.c ++++ b/src/fold.c +@@ -22,12 +22,34 @@ #include #include -+ -+/* Get mbstate_t, mbrtowc(). */ + ++/* Get mbstate_t, mbrtowc(), wcwidth(). */ +#if HAVE_WCHAR_H +# include +#endif ++ ++/* Get iswprint(), iswblank(), wcwidth(). */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ #include "system.h" - - #include "assure.h" -@@ -35,6 +40,18 @@ - - #include "set-fields.h" + #include "die.h" + #include "error.h" + #include "fadvise.h" + #include "xdectoint.h" +/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC -+ installation; work around this configuration error. */ ++ installation; work around this configuration error. */ +#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 +# undef MB_LEN_MAX +# define MB_LEN_MAX 16 @@ -463,965 +89,870 @@ index f0effb9..36479d6 100644 +# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) +#endif + + #define TAB_WIDTH 8 + /* The official name of this program (e.g., no 'g' prefix). */ - #define PROGRAM_NAME "cut" +@@ -35,20 +57,41 @@ -@@ -51,6 +68,52 @@ - } \ - while (0) + #define AUTHORS proper_name ("David MacKenzie") -+/* Refill the buffer BUF to get a multibyte character. */ -+#define REFILL_BUFFER(BUF, BUFPOS, BUFLEN, STREAM) \ -+ do \ -+ { \ -+ if (BUFLEN < MB_LEN_MAX && !feof (STREAM) && !ferror (STREAM)) \ -+ { \ -+ memmove (BUF, BUFPOS, BUFLEN); \ -+ BUFLEN += fread (BUF + BUFLEN, sizeof(char), BUFSIZ, STREAM); \ -+ BUFPOS = BUF; \ -+ } \ -+ } \ ++#define FATAL_ERROR(Message) \ ++ do \ ++ { \ ++ error (0, 0, (Message)); \ ++ usage (2); \ ++ } \ + while (0) + -+/* Get wide character on BUFPOS. BUFPOS is not included after that. -+ If byte sequence is not valid as a character, CONVFAIL is true. Otherwise false. */ -+#define GET_NEXT_WC_FROM_BUFFER(WC, BUFPOS, BUFLEN, MBLENGTH, STATE, CONVFAIL) \ -+ do \ -+ { \ -+ mbstate_t state_bak; \ -+ \ -+ if (BUFLEN < 1) \ -+ { \ -+ WC = WEOF; \ -+ break; \ -+ } \ -+ \ -+ /* Get a wide character. */ \ -+ CONVFAIL = false; \ -+ state_bak = STATE; \ -+ MBLENGTH = mbrtowc ((wchar_t *)&WC, BUFPOS, BUFLEN, &STATE); \ -+ \ -+ switch (MBLENGTH) \ -+ { \ -+ case (size_t)-1: \ -+ case (size_t)-2: \ -+ CONVFAIL = true; \ -+ STATE = state_bak; \ -+ /* Fall througn. */ \ -+ \ -+ case 0: \ -+ MBLENGTH = 1; \ -+ break; \ -+ } \ -+ } \ -+ while (0) -+ - - /* Pointer inside RP. When checking if a byte or field is selected - by a finite range, we check if it is between CURRENT_RP.LO -@@ -58,6 +121,9 @@ - CURRENT_RP.HI then we make CURRENT_RP to point to the next range pair. */ - static struct field_range_pair *current_rp; - -+/* Length of the delimiter given as argument to -d. */ -+size_t delimlen; -+ - /* This buffer is used to support the semantics of the -s option - (or lack of same) when the specified field list includes (does - not include) the first field. In both of those cases, the entire -@@ -70,6 +136,29 @@ static char *field_1_buffer; - /* The number of bytes allocated for FIELD_1_BUFFER. */ - static size_t field_1_bufsize; - +enum operating_mode -+ { -+ undefined_mode, ++{ ++ /* Fold texts by columns that are at the given positions. */ ++ column_mode, + -+ /* Output bytes that are at the given positions. */ -+ byte_mode, ++ /* Fold texts by bytes that are at the given positions. */ ++ byte_mode, + -+ /* Output characters that are at the given positions. */ -+ character_mode, -+ -+ /* Output the given delimiter-separated fields. */ -+ field_mode -+ }; ++ /* Fold texts by characters that are at the given positions. */ ++ character_mode, ++}; + ++/* The argument shows current mode. (Default: column_mode) */ +static enum operating_mode operating_mode; + -+/* If nonzero, when in byte mode, don't split multibyte characters. */ -+static int byte_mode_character_aware; -+ -+/* If nonzero, the function for single byte locale is work -+ if this program runs on multibyte locale. */ -+static int force_singlebyte_mode; -+ - /* If true, do not output lines containing no delimiter characters. - Otherwise, all such lines are printed. This option is valid only - with field mode. */ -@@ -81,10 +170,16 @@ static bool complement; + /* If nonzero, try to break on whitespace. */ + static bool break_spaces; - /* The delimiter character for field mode. */ - static unsigned char delim; -+#if HAVE_WCHAR_H -+static wchar_t wcdelim; -+#endif - - /* The delimiter for each line/record. */ - static unsigned char line_delim = '\n'; - -+/* True if the --output-delimiter=STRING option was specified. */ -+static bool output_delimiter_specified; -+ - /* The length of output_delimiter_string. */ - static size_t output_delimiter_length; - -@@ -92,9 +187,6 @@ static size_t output_delimiter_length; - string consisting of the input delimiter. */ - static char *output_delimiter_string; - --/* The output delimiter string contents, if the default. */ --static char output_delimiter_default[1]; +-/* If nonzero, count bytes, not column positions. */ +-static bool count_bytes; - - /* True if we have ever read standard input. */ + /* If nonzero, at least one of the files we read was standard input. */ static bool have_read_stdin; -@@ -148,7 +240,7 @@ Print selected parts of lines from each FILE to standard output.\n\ - -f, --fields=LIST select only these fields; also print any line\n\ - that contains no delimiter character, unless\n\ - the -s option is specified\n\ -- -n (ignored)\n\ -+ -n with -b: don't split multibyte characters\n\ - "), stdout); - fputs (_("\ - --complement complement the set of selected bytes, characters\n\ -@@ -252,7 +344,7 @@ cut_bytes (FILE *stream) - next_item (&byte_idx); - if (print_kth (byte_idx)) - { -- if (output_delimiter_string != output_delimiter_default) -+ if (output_delimiter_specified) - { - if (print_delimiter && is_range_start_index (byte_idx)) - { -@@ -271,6 +363,82 @@ cut_bytes (FILE *stream) - } - } +-static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; ++static char const shortopts[] = "bcsw:0::1::2::3::4::5::6::7::8::9::"; -+#if HAVE_MBRTOWC -+/* This function is in use for the following case. -+ -+ 1. Read from the stream STREAM, printing to standard output any selected -+ characters. -+ -+ 2. Read from stream STREAM, printing to standard output any selected bytes, -+ without splitting multibyte characters. */ -+ + static struct option const longopts[] = + { + {"bytes", no_argument, NULL, 'b'}, ++ {"characters", no_argument, NULL, 'c'}, + {"spaces", no_argument, NULL, 's'}, + {"width", required_argument, NULL, 'w'}, + {GETOPT_HELP_OPTION_DECL}, +@@ -76,6 +119,7 @@ Wrap input lines in each FILE, writing to standard output.\n\ + + fputs (_("\ + -b, --bytes count bytes rather than columns\n\ ++ -c, --characters count characters rather than columns\n\ + -s, --spaces break at spaces\n\ + -w, --width=WIDTH use WIDTH columns instead of 80\n\ + "), stdout); +@@ -93,7 +137,7 @@ Wrap input lines in each FILE, writing to standard output.\n\ + static size_t + adjust_column (size_t column, char c) + { +- if (!count_bytes) ++ if (operating_mode != byte_mode) + { + if (c == '\b') + { +@@ -116,30 +160,14 @@ adjust_column (size_t column, char c) + to stdout, with maximum line length WIDTH. + Return true if successful. */ + +-static bool +-fold_file (char const *filename, size_t width) +static void -+cut_characters_or_cut_bytes_no_split (FILE *stream) ++fold_text (FILE *istream, size_t width, int *saved_errno) + { +- FILE *istream; + int c; + size_t column = 0; /* Screen column where next char will go. */ + size_t offset_out = 0; /* Index in 'line_out' for next char. */ + static char *line_out = NULL; + static size_t allocated_out = 0; +- int saved_errno; +- +- if (STREQ (filename, "-")) +- { +- istream = stdin; +- have_read_stdin = true; +- } +- else +- istream = fopen (filename, "r"); +- +- if (istream == NULL) +- { +- error (0, errno, "%s", quotef (filename)); +- return false; +- } + + fadvise (istream, FADVISE_SEQUENTIAL); + +@@ -169,6 +197,15 @@ fold_file (char const *filename, size_t width) + bool found_blank = false; + size_t logical_end = offset_out; + ++ /* If LINE_OUT has no wide character, ++ put a new wide character in LINE_OUT ++ if column is bigger than width. */ ++ if (offset_out == 0) ++ { ++ line_out[offset_out++] = c; ++ continue; ++ } ++ + /* Look for the last blank. */ + while (logical_end) + { +@@ -215,11 +252,221 @@ fold_file (char const *filename, size_t width) + line_out[offset_out++] = c; + } + +- saved_errno = errno; ++ *saved_errno = errno; + + if (offset_out) + fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); + ++} ++ ++#if HAVE_MBRTOWC ++static void ++fold_multibyte_text (FILE *istream, size_t width, int *saved_errno) +{ -+ uintmax_t idx; /* number of bytes or characters in the line so far. */ + char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ char *bufpos; /* Next read position of BUF. */ -+ size_t buflen; /* The length of the byte sequence in buf. */ ++ size_t buflen = 0; /* The length of the byte sequence in buf. */ ++ char *bufpos = buf; /* Next read position of BUF. */ + wint_t wc; /* A gotten wide character. */ + size_t mblength; /* The byte size of a multibyte character which shows + as same character as WC. */ -+ mbstate_t state; /* State of the stream. */ -+ bool convfail = false; /* true, when conversion failed. Otherwise false. */ -+ /* Whether to begin printing delimiters between ranges for the current line. -+ Set after we've begun printing data corresponding to the first range. */ -+ bool print_delimiter = false; ++ mbstate_t state, state_bak; /* State of the stream. */ ++ int convfail = 0; /* 1, when conversion is failed. Otherwise 0. */ + -+ idx = 0; -+ buflen = 0; -+ bufpos = buf; ++ static char *line_out = NULL; ++ size_t offset_out = 0; /* Index in `line_out' for next char. */ ++ static size_t allocated_out = 0; ++ ++ int increment; ++ size_t column = 0; ++ ++ size_t last_blank_pos; ++ size_t last_blank_column; ++ int is_blank_seen; ++ int last_blank_increment = 0; ++ int is_bs_following_last_blank; ++ size_t bs_following_last_blank_num; ++ int is_cr_after_last_blank; ++ ++#define CLEAR_FLAGS \ ++ do \ ++ { \ ++ last_blank_pos = 0; \ ++ last_blank_column = 0; \ ++ is_blank_seen = 0; \ ++ is_bs_following_last_blank = 0; \ ++ bs_following_last_blank_num = 0; \ ++ is_cr_after_last_blank = 0; \ ++ } \ ++ while (0) ++ ++#define START_NEW_LINE \ ++ do \ ++ { \ ++ putchar ('\n'); \ ++ column = 0; \ ++ offset_out = 0; \ ++ CLEAR_FLAGS; \ ++ } \ ++ while (0) ++ ++ CLEAR_FLAGS; + memset (&state, '\0', sizeof(mbstate_t)); + -+ current_rp = frp; -+ -+ while (1) ++ for (;; bufpos += mblength, buflen -= mblength) + { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); -+ -+ GET_NEXT_WC_FROM_BUFFER (wc, bufpos, buflen, mblength, state, convfail); -+ (void) convfail; /* ignore unused */ -+ -+ if (wc == WEOF) ++ if (buflen < MB_LEN_MAX && !feof (istream) && !ferror (istream)) + { -+ if (idx > 0) -+ putchar (line_delim); ++ memmove (buf, bufpos, buflen); ++ buflen += fread (buf + buflen, sizeof(char), BUFSIZ, istream); ++ bufpos = buf; ++ } ++ ++ if (buflen < 1) ++ break; ++ ++ /* Get a wide character. */ ++ state_bak = state; ++ mblength = mbrtowc ((wchar_t *)&wc, bufpos, buflen, &state); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ convfail++; ++ state = state_bak; ++ /* Fall through. */ ++ ++ case 0: ++ mblength = 1; + break; + } -+ else if (wc == line_delim) ++ ++rescan: ++ if (operating_mode == byte_mode) /* byte mode */ ++ increment = mblength; ++ else if (operating_mode == character_mode) /* character mode */ ++ increment = 1; ++ else /* column mode */ + { -+ putchar (line_delim); -+ idx = 0; -+ print_delimiter = false; -+ current_rp = frp; -+ } -+ else -+ { -+ next_item (&idx); -+ if (print_kth (idx)) -+ { -+ if (output_delimiter_specified) -+ { -+ if (print_delimiter && is_range_start_index (idx)) -+ { -+ fwrite (output_delimiter_string, sizeof (char), -+ output_delimiter_length, stdout); -+ } -+ print_delimiter = true; -+ } -+ fwrite (bufpos, mblength, sizeof(char), stdout); -+ } -+ } -+ -+ buflen -= mblength; -+ bufpos += mblength; -+ } -+} -+#endif -+ - /* Read from stream STREAM, printing to standard output any selected fields. */ - - static void -@@ -433,11 +601,218 @@ cut_fields (FILE *stream) - } - } - --/* Process file FILE to standard output, using CUT_STREAM. -+#if HAVE_MBRTOWC -+static void -+cut_fields_mb (FILE *stream) -+{ -+ int c; -+ uintmax_t field_idx; -+ int found_any_selected_field; -+ int buffer_first_field; -+ int empty_input; -+ char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */ -+ char *bufpos; /* Next read position of BUF. */ -+ size_t buflen; /* The length of the byte sequence in buf. */ -+ wint_t wc = 0; /* A gotten wide character. */ -+ size_t mblength; /* The byte size of a multibyte character which shows -+ as same character as WC. */ -+ mbstate_t state; /* State of the stream. */ -+ bool convfail = false; /* true, when conversion failed. Otherwise false. */ -+ -+ current_rp = frp; -+ -+ found_any_selected_field = 0; -+ field_idx = 1; -+ bufpos = buf; -+ buflen = 0; -+ memset (&state, '\0', sizeof(mbstate_t)); -+ -+ c = getc (stream); -+ empty_input = (c == EOF); -+ if (c != EOF) -+ { -+ ungetc (c, stream); -+ wc = 0; -+ } -+ else -+ wc = WEOF; -+ -+ /* To support the semantics of the -s flag, we may have to buffer -+ all of the first field to determine whether it is `delimited.' -+ But that is unnecessary if all non-delimited lines must be printed -+ and the first field has been selected, or if non-delimited lines -+ must be suppressed and the first field has *not* been selected. -+ That is because a non-delimited line has exactly one field. */ -+ buffer_first_field = (suppress_non_delimited ^ !print_kth (1)); -+ -+ while (1) -+ { -+ if (field_idx == 1 && buffer_first_field) -+ { -+ int len = 0; -+ -+ while (1) -+ { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); -+ -+ GET_NEXT_WC_FROM_BUFFER -+ (wc, bufpos, buflen, mblength, state, convfail); -+ -+ if (wc == WEOF) -+ break; -+ -+ field_1_buffer = xrealloc (field_1_buffer, len + mblength); -+ memcpy (field_1_buffer + len, bufpos, mblength); -+ len += mblength; -+ buflen -= mblength; -+ bufpos += mblength; -+ -+ if (!convfail && (wc == line_delim || wc == wcdelim)) -+ break; -+ } -+ -+ if (len <= 0 && wc == WEOF) -+ break; -+ -+ /* If the first field extends to the end of line (it is not -+ delimited) and we are printing all non-delimited lines, -+ print this one. */ -+ if (convfail || (!convfail && wc != wcdelim)) -+ { -+ if (suppress_non_delimited) -+ { -+ /* Empty. */ -+ } -+ else -+ { -+ fwrite (field_1_buffer, sizeof (char), len, stdout); -+ /* Make sure the output line is newline terminated. */ -+ if (convfail || (!convfail && wc != line_delim)) -+ putchar (line_delim); -+ } -+ continue; -+ } -+ -+ if (print_kth (1)) -+ { -+ /* Print the field, but not the trailing delimiter. */ -+ fwrite (field_1_buffer, sizeof (char), len - 1, stdout); -+ found_any_selected_field = 1; -+ } -+ next_item (&field_idx); -+ } -+ -+ if (wc != WEOF) -+ { -+ if (print_kth (field_idx)) -+ { -+ if (found_any_selected_field) -+ { -+ fwrite (output_delimiter_string, sizeof (char), -+ output_delimiter_length, stdout); -+ } -+ found_any_selected_field = 1; -+ } -+ -+ while (1) -+ { -+ REFILL_BUFFER (buf, bufpos, buflen, stream); -+ -+ GET_NEXT_WC_FROM_BUFFER -+ (wc, bufpos, buflen, mblength, state, convfail); -+ -+ if (wc == WEOF) -+ break; -+ else if (!convfail && (wc == wcdelim || wc == line_delim)) -+ { -+ buflen -= mblength; -+ bufpos += mblength; -+ break; -+ } -+ -+ if (print_kth (field_idx)) -+ fwrite (bufpos, mblength, sizeof(char), stdout); -+ -+ buflen -= mblength; -+ bufpos += mblength; -+ } -+ } -+ -+ if ((!convfail || wc == line_delim) && buflen < 1) -+ wc = WEOF; -+ -+ if (!convfail && wc == wcdelim) -+ next_item (&field_idx); -+ else if (wc == WEOF || (!convfail && wc == line_delim)) -+ { -+ if (found_any_selected_field -+ || (!empty_input && !(suppress_non_delimited && field_idx == 1))) -+ putchar (line_delim); -+ if (wc == WEOF) -+ break; -+ field_idx = 1; -+ current_rp = frp; -+ found_any_selected_field = 0; -+ } -+ } -+} -+#endif -+ -+static void -+cut_stream (FILE *stream) -+{ -+#if HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) -+ { -+ switch (operating_mode) -+ { -+ case byte_mode: -+ if (byte_mode_character_aware) -+ cut_characters_or_cut_bytes_no_split (stream); ++ if (convfail) ++ increment = 1; + else -+ cut_bytes (stream); -+ break; -+ -+ case character_mode: -+ cut_characters_or_cut_bytes_no_split (stream); -+ break; -+ -+ case field_mode: -+ if (delimlen == 1) + { -+ /* Check if we have utf8 multibyte locale, so we can use this -+ optimization because of uniqueness of characters, which is -+ not true for e.g. SJIS */ -+ char * loc = setlocale(LC_CTYPE, NULL); -+ if (loc && (strstr (loc, "UTF-8") || strstr (loc, "utf-8") || -+ strstr (loc, "UTF8") || strstr (loc, "utf8"))) ++ switch (wc) + { -+ cut_fields (stream); ++ case L'\n': ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ continue; ++ ++ case L'\b': ++ increment = (column > 0) ? -1 : 0; + break; ++ ++ case L'\r': ++ increment = -1 * column; ++ break; ++ ++ case L'\t': ++ increment = 8 - column % 8; ++ break; ++ ++ default: ++ increment = wcwidth (wc); ++ increment = (increment < 0) ? 0 : increment; + } + } -+ cut_fields_mb (stream); -+ break; ++ } + -+ default: -+ abort (); ++ if (column + increment > width && break_spaces && last_blank_pos) ++ { ++ fwrite (line_out, sizeof(char), last_blank_pos, stdout); ++ putchar ('\n'); ++ ++ offset_out = offset_out - last_blank_pos; ++ column = column - last_blank_column + ((is_cr_after_last_blank) ++ ? last_blank_increment : bs_following_last_blank_num); ++ memmove (line_out, line_out + last_blank_pos, offset_out); ++ CLEAR_FLAGS; ++ goto rescan; ++ } ++ ++ if (column + increment > width && column != 0) ++ { ++ fwrite (line_out, sizeof(char), offset_out, stdout); ++ START_NEW_LINE; ++ goto rescan; ++ } ++ ++ if (allocated_out < offset_out + mblength) ++ { ++ line_out = X2REALLOC (line_out, &allocated_out); ++ } ++ ++ memcpy (line_out + offset_out, bufpos, mblength); ++ offset_out += mblength; ++ column += increment; ++ ++ if (is_blank_seen && !convfail && wc == L'\r') ++ is_cr_after_last_blank = 1; ++ ++ if (is_bs_following_last_blank && !convfail && wc == L'\b') ++ ++bs_following_last_blank_num; ++ else ++ is_bs_following_last_blank = 0; ++ ++ if (break_spaces && !convfail && iswblank (wc)) ++ { ++ last_blank_pos = offset_out; ++ last_blank_column = column; ++ is_blank_seen = 1; ++ last_blank_increment = increment; ++ is_bs_following_last_blank = 1; ++ bs_following_last_blank_num = 0; ++ is_cr_after_last_blank = 0; + } + } ++ ++ *saved_errno = errno; ++ ++ if (offset_out) ++ fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); ++ ++} ++#endif ++ ++/* Fold file FILENAME, or standard input if FILENAME is "-", ++ to stdout, with maximum line length WIDTH. ++ Return 0 if successful, 1 if an error occurs. */ ++ ++static bool ++fold_file (char const *filename, size_t width) ++{ ++ FILE *istream; ++ int saved_errno; ++ ++ if (STREQ (filename, "-")) ++ { ++ istream = stdin; ++ have_read_stdin = 1; ++ } ++ else ++ istream = fopen (filename, "r"); ++ ++ if (istream == NULL) ++ { ++ error (0, errno, "%s", filename); ++ return 1; ++ } ++ ++ /* Define how ISTREAM is being folded. */ ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ fold_multibyte_text (istream, width, &saved_errno); + else +#endif -+ { -+ if (operating_mode == field_mode) -+ cut_fields (stream); -+ else -+ cut_bytes (stream); -+ } -+} ++ fold_text (istream, width, &saved_errno); + -+/* Process file FILE to standard output. - Return true if successful. */ - - static bool --cut_file (char const *file, void (*cut_stream) (FILE *)) -+cut_file (char const *file) - { - FILE *stream; - -@@ -482,8 +857,8 @@ main (int argc, char **argv) - int optc; - bool ok; - bool delim_specified = false; -- bool byte_mode = false; -- char *spec_list_string = nullptr; -+ char *spec_list_string IF_LINT ( = nullptr); -+ char mbdelim[MB_LEN_MAX + 1]; - - initialize_main (&argc, &argv); - set_program_name (argv[0]); -@@ -493,6 +868,8 @@ main (int argc, char **argv) + if (ferror (istream)) + { + error (0, saved_errno, "%s", quotef (filename)); +@@ -252,7 +499,8 @@ main (int argc, char **argv) atexit (close_stdout); -+ operating_mode = undefined_mode; -+ - /* By default, all non-delimited lines are printed. */ - suppress_non_delimited = false; +- break_spaces = count_bytes = have_read_stdin = false; ++ operating_mode = column_mode; ++ break_spaces = have_read_stdin = false; -@@ -505,35 +882,77 @@ main (int argc, char **argv) + while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) + { +@@ -261,7 +509,15 @@ main (int argc, char **argv) switch (optc) { - case 'b': -- case 'c': - /* Build the byte list. */ -- byte_mode = true; -- FALLTHROUGH; -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); + case 'b': /* Count bytes rather than columns. */ +- count_bytes = true; ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); + operating_mode = byte_mode; -+ spec_list_string = optarg; + break; + + case 'c': -+ /* Build the character list. */ -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); ++ if (operating_mode != column_mode) ++ FATAL_ERROR (_("only one way of folding may be specified")); + operating_mode = character_mode; -+ spec_list_string = optarg; -+ break; -+ - case 'f': - /* Build the field list. */ -- if (spec_list_string) -- FATAL_ERROR (_("only one list may be specified")); -+ if (operating_mode != undefined_mode) -+ FATAL_ERROR (_("only one type of list may be specified")); -+ operating_mode = field_mode; - spec_list_string = optarg; break; - case 'd': - /* New delimiter. */ - /* Interpret -d '' to mean 'use the NUL byte as the delimiter.' */ -- if (optarg[0] != '\0' && optarg[1] != '\0') -- FATAL_ERROR (_("the delimiter must be a single character")); -- delim = optarg[0]; -- delim_specified = true; -+ { -+#if HAVE_MBRTOWC -+ if(MB_CUR_MAX > 1) -+ { -+ mbstate_t state; -+ -+ memset (&state, '\0', sizeof(mbstate_t)); -+ delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state); -+ -+ if (delimlen == (size_t)-1 || delimlen == (size_t)-2) -+ ++force_singlebyte_mode; -+ else -+ { -+ delimlen = (delimlen < 1) ? 1 : delimlen; -+ if (wcdelim != L'\0' && *(optarg + delimlen) != '\0') -+ FATAL_ERROR (_("the delimiter must be a single character")); -+ memcpy (mbdelim, optarg, delimlen); -+ mbdelim[delimlen] = '\0'; -+ if (delimlen == 1) -+ delim = *optarg; -+ } -+ } -+ -+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) -+#endif -+ { -+ if (optarg[0] != '\0' && optarg[1] != '\0') -+ FATAL_ERROR (_("the delimiter must be a single character")); -+ delim = (unsigned char) optarg[0]; -+ } -+ delim_specified = true; -+ } - break; - - case OUTPUT_DELIMITER_OPTION: -+ output_delimiter_specified = true; - /* Interpret --output-delimiter='' to mean - 'use the NUL byte as the delimiter.' */ - output_delimiter_length = (optarg[0] == '\0' - ? 1 : strlen (optarg)); -- output_delimiter_string = optarg; -+ output_delimiter_string = xstrdup (optarg); - break; - - case 'n': -+ byte_mode_character_aware = 1; - break; - - case 's': -@@ -555,40 +974,57 @@ main (int argc, char **argv) - } - } - -- if (!spec_list_string) -+ if (operating_mode == undefined_mode) - FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); - -- if (byte_mode) -- { -- if (delim_specified) -- FATAL_ERROR (_("an input delimiter may be specified only\ -+ if (delim_specified && operating_mode != field_mode) -+ FATAL_ERROR (_("an input delimiter may be specified only\ - when operating on fields")); - -- if (suppress_non_delimited) -- FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ -+ if (suppress_non_delimited && operating_mode != field_mode) -+ FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\ - \tonly when operating on fields")); -- } - - set_fields (spec_list_string, -- ((byte_mode ? SETFLD_ERRMSG_USE_POS : 0) -- | (complement ? SETFLD_COMPLEMENT : 0))); -+ ( (operating_mode == field_mode) ? 0 : SETFLD_ERRMSG_USE_POS) -+ | (complement ? SETFLD_COMPLEMENT : 0) ); - - if (!delim_specified) -- delim = '\t'; -+ { -+ delim = '\t'; -+#ifdef HAVE_MBRTOWC -+ wcdelim = L'\t'; -+ mbdelim[0] = '\t'; -+ mbdelim[1] = '\0'; -+ delimlen = 1; -+#endif -+ } - - if (output_delimiter_string == nullptr) - { -- output_delimiter_default[0] = delim; -- output_delimiter_string = output_delimiter_default; -- output_delimiter_length = 1; -+#ifdef HAVE_MBRTOWC -+ if (MB_CUR_MAX > 1 && !force_singlebyte_mode) -+ { -+ output_delimiter_string = xstrdup(mbdelim); -+ output_delimiter_length = delimlen; -+ } -+ -+ if (MB_CUR_MAX <= 1 || force_singlebyte_mode) -+#endif -+ { -+ static char dummy[2]; -+ dummy[0] = delim; -+ dummy[1] = '\0'; -+ output_delimiter_string = dummy; -+ output_delimiter_length = 1; -+ } - } - -- void (*cut_stream) (FILE *) = byte_mode ? cut_bytes : cut_fields; - if (optind == argc) -- ok = cut_file ("-", cut_stream); -+ ok = cut_file ("-"); - else - for (ok = true; optind < argc; optind++) -- ok &= cut_file (argv[optind], cut_stream); -+ ok &= cut_file (argv[optind]); - - - if (have_read_stdin && fclose (stdin) == EOF) -diff --git a/src/expand-common.c b/src/expand-common.c -index 14dd804..0d8eaaa 100644 ---- a/src/expand-common.c -+++ b/src/expand-common.c -@@ -19,6 +19,7 @@ - #include - #include + case 's': /* Break at word boundaries. */ +diff --git a/src/join.c b/src/join.c +index 98b461c..9990f38 100644 +--- a/src/join.c ++++ b/src/join.c +@@ -22,19 +22,33 @@ #include -+#include + #include + ++/* Get mbstate_t, mbrtowc(), mbrtowc(), wcwidth(). */ ++#if HAVE_WCHAR_H ++# include ++#endif ++ ++/* Get iswblank(), towupper. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++ #include "system.h" - #include "c-ctype.h" + #include "die.h" + #include "error.h" #include "fadvise.h" -@@ -132,6 +133,119 @@ set_increment_size (colno tabval) - return ok; + #include "hard-locale.h" + #include "linebuffer.h" +-#include "memcasecmp.h" + #include "quote.h" + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" + #include "argmatch.h" + ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "join" + +@@ -136,10 +150,12 @@ static struct outlist outlist_head; + /* Last element in 'outlist', where a new element can be added. */ + static struct outlist *outlist_end = &outlist_head; + +-/* Tab character separating fields. If negative, fields are separated +- by any nonempty string of blanks, otherwise by exactly one +- tab character whose value (when cast to unsigned char) equals TAB. */ +-static int tab = -1; ++/* Tab character separating fields. If NULL, fields are separated ++ by any nonempty string of blanks. */ ++static char *tab = NULL; ++ ++/* The number of bytes used for tab. */ ++static size_t tablen = 0; + + /* If nonzero, check that the input is correctly ordered. */ + static enum +@@ -276,13 +292,14 @@ xfields (struct line *line) + if (ptr == lim) + return; + +- if (0 <= tab && tab != '\n') ++ if (tab != NULL) + { ++ unsigned char t = tab[0]; + char *sep; +- for (; (sep = memchr (ptr, tab, lim - ptr)) != NULL; ptr = sep + 1) ++ for (; (sep = memchr (ptr, t, lim - ptr)) != NULL; ptr = sep + 1) + extract_field (line, ptr, sep - ptr); + } +- else if (tab < 0) ++ else + { + /* Skip leading blanks before the first field. */ + while (field_sep (*ptr)) +@@ -306,6 +323,147 @@ xfields (struct line *line) + extract_field (line, ptr, lim - ptr); } -+extern int -+set_utf_locale (void) ++#if HAVE_MBRTOWC ++static void ++xfields_multibyte (struct line *line) +{ -+ /*try using some predefined locale */ -+ const char* predef_locales[] = {"C.UTF8","en_US.UTF8","en_GB.UTF8"}; ++ char *ptr = line->buf.buffer; ++ char const *lim = ptr + line->buf.length - 1; ++ wchar_t wc = 0; ++ size_t mblength = 1; ++ mbstate_t state, state_bak; + -+ const int predef_locales_count=3; -+ for (int i=0;i= lim) ++ return; ++ ++ if (tab != NULL) ++ { ++ char *sep = ptr; ++ for (; ptr < lim; ptr = sep + mblength) ++ { ++ sep = ptr; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (mblength == tablen && !memcmp (sep, tab, mblength)) ++ break; ++ else ++ { ++ sep += mblength; ++ continue; ++ } ++ } ++ ++ if (sep >= lim) ++ break; ++ ++ extract_field (line, ptr, sep - ptr); ++ } ++ } ++ else ++ { ++ /* Skip leading blanks before the first field. */ ++ while(ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) + { ++ mblength = 1; ++ state = state_bak; + break; + } -+ else if (i==predef_locales_count-1) -+ { -+ return 1; -+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); -+ } -+ } -+ return 0; ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank(wc) && wc != '\n') ++ break; ++ ptr += mblength; ++ } ++ ++ do ++ { ++ char *sep; ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ sep = ptr + mblength; ++ while (sep < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (iswblank (wc) || wc == '\n') ++ break; ++ ++ sep += mblength; ++ } ++ ++ extract_field (line, ptr, sep - ptr); ++ if (sep >= lim) ++ return; ++ ++ state_bak = state; ++ mblength = mbrtowc (&wc, sep, lim - sep + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ ptr = sep + mblength; ++ while (ptr < lim) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, ptr, lim - ptr + 1, &state); ++ if (mblength == (size_t)-1 || mblength == (size_t)-2) ++ { ++ mblength = 1; ++ state = state_bak; ++ break; ++ } ++ mblength = (mblength < 1) ? 1 : mblength; ++ ++ if (!iswblank (wc) && wc != '\n') ++ break; ++ ++ ptr += mblength; ++ } ++ } ++ while (ptr < lim); ++ } ++ ++ extract_field (line, ptr, lim - ptr); +} ++#endif + -+extern bool -+check_utf_locale(void) -+{ -+ char* locale = setlocale (LC_CTYPE , NULL); -+ if (locale == NULL) -+ { -+ return false; -+ } -+ else if (strcasestr(locale, "utf8") == NULL && strcasestr(locale, "utf-8") == NULL) -+ { -+ return false; -+ } -+ return true; -+} -+ -+extern bool -+check_bom(FILE* fp, mb_file_t *mbf) -+{ -+ int c; -+ -+ -+ c=fgetc(fp); -+ -+ /*test BOM header of the first file */ -+ mbf->bufcount=0; -+ if (c == 0xEF) -+ { -+ c=fgetc(fp); -+ } -+ else -+ { -+ if (c != EOF) -+ { -+ ungetc(c,fp); -+ } -+ return false; -+ } -+ -+ if (c == 0xBB) -+ { -+ c=fgetc(fp); -+ } -+ else -+ { -+ if ( c!= EOF ) -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->bufcount=1; -+ ungetc(c,fp); -+ return false; -+ } -+ else -+ { -+ ungetc(0xEF,fp); -+ return false; -+ } -+ } -+ if (c == 0xBF) -+ { -+ mbf->bufcount=0; -+ return true; -+ } -+ else -+ { -+ if (c != EOF) -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->buf[1]=(unsigned char) 0xBB; -+ mbf->bufcount=2; -+ ungetc(c,fp); -+ return false; -+ } -+ else -+ { -+ mbf->buf[0]=(unsigned char) 0xEF; -+ mbf->bufcount=1; -+ ungetc(0xBB,fp); -+ return false; -+ } -+ } -+ return false; -+} -+ -+extern void -+print_bom(void) -+{ -+ putc (0xEF, stdout); -+ putc (0xBB, stdout); -+ putc (0xBF, stdout); -+} -+ - /* Add the comma or blank separated list of tab stops STOPS - to the list of tab stops. */ - extern void -diff --git a/src/expand-common.h b/src/expand-common.h -index 46ef4e3..e19469b 100644 ---- a/src/expand-common.h -+++ b/src/expand-common.h -@@ -29,6 +29,18 @@ extern idx_t max_column_width; - /* The desired exit status. */ - extern int exit_status; - -+extern int -+set_utf_locale (void); -+ -+extern bool -+check_utf_locale(void); -+ -+extern bool -+check_bom(FILE* fp, mb_file_t *mbf); -+ -+extern void -+print_bom(void); -+ - /* Add tab stop TABVAL to the end of 'tab_list'. */ - extern void - add_tab_stop (colno tabval); -diff --git a/src/expand.c b/src/expand.c -index 5ec7ce9..65ac315 100644 ---- a/src/expand.c -+++ b/src/expand.c -@@ -38,6 +38,9 @@ - #include - #include - #include -+ -+#include -+ - #include "system.h" - #include "expand-common.h" - -@@ -96,19 +99,41 @@ expand (void) + static void + freeline (struct line *line) { - /* Input stream. */ - FILE *fp = next_file (nullptr); -+ mb_file_t mbf; -+ mbf_char_t c; -+ /* True if the starting locale is utf8. */ -+ bool using_utf_locale; -+ -+ /* True if the first file contains BOM header. */ -+ bool found_bom; -+ using_utf_locale=check_utf_locale(); +@@ -327,56 +485,133 @@ keycmp (struct line const *line1, struct line const *line2, + size_t jf_1, size_t jf_2) + { + /* Start of field to compare in each file. */ +- char *beg1; +- char *beg2; +- +- size_t len1; +- size_t len2; /* Length of fields to compare. */ ++ char *beg[2]; ++ char *copy[2]; ++ size_t len[2]; /* Length of fields to compare. */ + int diff; ++ int i, j; ++ int mallocd = 0; - if (!fp) - return; -+ mbf_init (mbf, fp); -+ found_bom=check_bom(fp,&mbf); - -- while (true) -+ if (using_utf_locale == false && found_bom == true) -+ { -+ /*try using some predefined locale */ -+ -+ if (set_utf_locale () != 0) + if (jf_1 < line1->nfields) { -- /* Input character, or EOF. */ -- int c; -+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); -+ } -+ } -+ -+ -+ if (found_bom == true) -+ { -+ print_bom(); -+ } - -+ while (true) -+ { - /* If true, perform translations. */ - bool convert = true; - -- - /* The following variables have valid values only when CONVERT - is true: */ - -@@ -118,17 +143,48 @@ expand (void) - /* Index in TAB_LIST of next tab stop to examine. */ - idx_t tab_index = 0; - -- - /* Convert a line of text. */ - - do - { -- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -- continue; -+ while (true) { -+ mbf_getc (c, mbf); -+ if ((mb_iseof (c)) && (fp = next_file (fp))) -+ { -+ mbf_init (mbf, fp); -+ if (fp!=NULL) -+ { -+ if (check_bom(fp,&mbf)==true) -+ { -+ /*Not the first file - check BOM header*/ -+ if (using_utf_locale==false && found_bom==false) -+ { -+ /*BOM header in subsequent file but not in the first one. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ else -+ { -+ if(using_utf_locale==false && found_bom==true) -+ { -+ /*First file conatined BOM header - locale was switched to UTF -+ *all subsequent files should contain BOM. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ } -+ continue; -+ } -+ else -+ { -+ break; -+ } -+ } -+ - - if (convert) - { -- if (c == '\t') -+ if (mb_iseq (c, '\t')) - { - /* Column the next input tab stop is on. */ - bool last_tab; -@@ -139,31 +195,33 @@ expand (void) - if (putchar (' ') < 0) - write_error (); - -- c = ' '; -+ mb_setascii (&c, ' '); - } -- else if (c == '\b') -+ else if (mb_iseq (c, '\b')) - { - /* Go back one column, and force recalculation of the - next tab stop. */ - column -= !!column; - tab_index -= !!tab_index; - } -- else -+ /* A leading control character could make us trip over. */ -+ else if (!mb_iscntrl (c)) - { -- if (ckd_add (&column, column, 1)) -+ if (ckd_add (&column, column, mb_width (c))) - error (EXIT_FAILURE, 0, _("input line is too long")); - } - -- convert &= convert_entire_line || !! isblank (c); -+ convert &= convert_entire_line || !! mb_isblank (c); - } - -- if (c < 0) -+ if (mb_iseof (c)) - return; - -- if (putchar (c) < 0) -+ mb_putc (c, stdout); -+ if (ferror (stdout)) - write_error (); - } -- while (c != '\n'); -+ while (!mb_iseq (c, '\n')); +- beg1 = line1->fields[jf_1].beg; +- len1 = line1->fields[jf_1].len; ++ beg[0] = line1->fields[jf_1].beg; ++ len[0] = line1->fields[jf_1].len; } + else + { +- beg1 = NULL; +- len1 = 0; ++ beg[0] = NULL; ++ len[0] = 0; + } + + if (jf_2 < line2->nfields) + { +- beg2 = line2->fields[jf_2].beg; +- len2 = line2->fields[jf_2].len; ++ beg[1] = line2->fields[jf_2].beg; ++ len[1] = line2->fields[jf_2].len; + } + else + { +- beg2 = NULL; +- len2 = 0; ++ beg[1] = NULL; ++ len[1] = 0; + } + +- if (len1 == 0) +- return len2 == 0 ? 0 : -1; +- if (len2 == 0) ++ if (len[0] == 0) ++ return len[1] == 0 ? 0 : -1; ++ if (len[1] == 0) + return 1; + + if (ignore_case) + { +- /* FIXME: ignore_case does not work with NLS (in particular, +- with multibyte chars). */ +- diff = memcasecmp (beg1, beg2, MIN (len1, len2)); ++#ifdef HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state, state_bak; ++ ++ memset (&state, '\0', sizeof (mbstate_t)); ++ ++ for (i = 0; i < 2; i++) ++ { ++ mallocd = 1; ++ copy[i] = xmalloc (len[i] + 1); ++ memset (copy[i], '\0',len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]);) ++ { ++ state_bak = state; ++ mblength = mbrtowc (&wc, beg[i] + j, len[i] - j, &state); ++ ++ switch (mblength) ++ { ++ case (size_t) -1: ++ case (size_t) -2: ++ state = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ size_t mblen; ++ ++ memset (&state_wc, '\0', sizeof (mbstate_t)); ++ mblen = wcrtomb (copy[i] + j, uwc, &state_wc); ++ assert (mblen != (size_t)-1); ++ } ++ else ++ memcpy (copy[i] + j, beg[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ } ++ } ++ else ++#endif ++ { ++ for (i = 0; i < 2; i++) ++ { ++ mallocd = 1; ++ copy[i] = xmalloc (len[i] + 1); ++ ++ for (j = 0; j < MIN (len[0], len[1]); j++) ++ copy[i][j] = toupper (beg[i][j]); ++ ++ copy[i][j] = '\0'; ++ } ++ } + } + else + { +- if (hard_LC_COLLATE) +- return xmemcoll (beg1, len1, beg2, len2); +- diff = memcmp (beg1, beg2, MIN (len1, len2)); ++ copy[0] = beg[0]; ++ copy[1] = beg[1]; + } + ++ if (hard_LC_COLLATE) ++ { ++ diff = xmemcoll ((char *) copy[0], len[0], (char *) copy[1], len[1]); ++ ++ if (mallocd) ++ for (i = 0; i < 2; i++) ++ free (copy[i]); ++ ++ return diff; ++ } ++ diff = memcmp (copy[0], copy[1], MIN (len[0], len[1])); ++ ++ if (mallocd) ++ for (i = 0; i < 2; i++) ++ free (copy[i]); ++ ++ + if (diff) + return diff; +- return len1 < len2 ? -1 : len1 != len2; ++ return len[0] - len[1]; } -diff --git a/src/local.mk b/src/local.mk -index a8ad6b4..b0e61ec 100644 ---- a/src/local.mk -+++ b/src/local.mk -@@ -490,8 +490,8 @@ src_base32_CPPFLAGS = -DBASE_TYPE=32 $(AM_CPPFLAGS) - src_basenc_SOURCES = src/basenc.c - src_basenc_CPPFLAGS = -DBASE_TYPE=42 $(AM_CPPFLAGS) + /* Check that successive input lines PREV and CURRENT from input file +@@ -468,6 +703,11 @@ get_line (FILE *fp, struct line **linep, int which) + } + ++line_no[which - 1]; --src_expand_SOURCES = src/expand.c src/expand-common.c --src_unexpand_SOURCES = src/unexpand.c src/expand-common.c -+src_expand_SOURCES = src/expand.c src/expand-common.c lib/mbfile.c lib/mbchar.c -+src_unexpand_SOURCES = src/unexpand.c src/expand-common.c lib/mbfile.c lib/mbchar.c ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ xfields_multibyte (line); ++ else ++#endif + xfields (line); + + if (prevline[which - 1]) +@@ -567,21 +807,28 @@ prfield (size_t n, struct line const *line) + + /* Output all the fields in line, other than the join field. */ + ++#define PUT_TAB_CHAR \ ++ do \ ++ { \ ++ (tab != NULL) ? \ ++ fwrite(tab, sizeof(char), tablen, stdout) : putchar (' '); \ ++ } \ ++ while (0) ++ + static void + prfields (struct line const *line, size_t join_field, size_t autocount) + { + size_t i; + size_t nfields = autoformat ? autocount : line->nfields; +- char output_separator = tab < 0 ? ' ' : tab; + + for (i = 0; i < join_field && i < nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line); + } + for (i = join_field + 1; i < nfields; ++i) + { +- putchar (output_separator); ++ PUT_TAB_CHAR; + prfield (i, line); + } + } +@@ -592,7 +839,6 @@ static void + prjoin (struct line const *line1, struct line const *line2) + { + const struct outlist *outlist; +- char output_separator = tab < 0 ? ' ' : tab; + size_t field; + struct line const *line; + +@@ -626,7 +872,7 @@ prjoin (struct line const *line1, struct line const *line2) + o = o->next; + if (o == NULL) + break; +- putchar (output_separator); ++ PUT_TAB_CHAR; + } + putchar (eolchar); + } +@@ -1104,20 +1350,43 @@ main (int argc, char **argv) + + case 't': + { +- unsigned char newtab = optarg[0]; ++ char *newtab = NULL; ++ size_t newtablen; ++ newtab = xstrdup (optarg); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ mbstate_t state; ++ ++ memset (&state, 0, sizeof (mbstate_t)); ++ newtablen = mbrtowc (NULL, newtab, ++ strnlen (newtab, MB_LEN_MAX), ++ &state); ++ if (newtablen == (size_t) 0 ++ || newtablen == (size_t) -1 ++ || newtablen == (size_t) -2) ++ newtablen = 1; ++ } ++ else ++#endif ++ newtablen = 1; + if (! newtab) +- newtab = '\n'; /* '' => process the whole line. */ ++ newtab = (char*)"\n"; /* '' => process the whole line. */ + else if (optarg[1]) + { +- if (STREQ (optarg, "\\0")) +- newtab = '\0'; +- else +- die (EXIT_FAILURE, 0, _("multi-character tab %s"), +- quote (optarg)); ++ if (newtablen == 1 && newtab[1]) ++ { ++ if (STREQ (newtab, "\\0")) ++ newtab[0] = '\0'; ++ } ++ } ++ if (tab != NULL && strcmp (tab, newtab)) ++ { ++ free (newtab); ++ die (EXIT_FAILURE, 0, _("incompatible tabs")); + } +- if (0 <= tab && tab != newtab) +- die (EXIT_FAILURE, 0, _("incompatible tabs")); + tab = newtab; ++ tablen = newtablen; + } + break; - src_wc_SOURCES = src/wc.c - if USE_AVX512_WC_LINECOUNT diff --git a/src/pr.c b/src/pr.c -index 10b8c52..079c86c 100644 +index 26f221f..633f50e 100644 --- a/src/pr.c +++ b/src/pr.c -@@ -312,6 +312,24 @@ - #include +@@ -311,6 +311,24 @@ + #include #include + @@ -1443,10 +974,10 @@ index 10b8c52..079c86c 100644 +#endif + #include "system.h" - #include "c-ctype.h" - #include "fadvise.h" -@@ -325,6 +343,18 @@ - #include "xstrtol-error.h" + #include "die.h" + #include "error.h" +@@ -324,6 +342,18 @@ + #include "xstrtol.h" #include "xdectoint.h" +/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ @@ -1464,7 +995,7 @@ index 10b8c52..079c86c 100644 /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "pr" -@@ -417,7 +447,20 @@ struct COLUMN +@@ -416,7 +446,20 @@ struct COLUMN typedef struct COLUMN COLUMN; @@ -1486,9 +1017,9 @@ index 10b8c52..079c86c 100644 static bool read_line (COLUMN *p); static bool print_page (void); static bool print_stored (COLUMN *p); -@@ -428,6 +471,7 @@ static void pad_across_to (int position); - static void add_line_number (COLUMN *p); - static int getoptnum (char const *n_str, int min, char const *errfmt); +@@ -428,6 +471,7 @@ static void add_line_number (COLUMN *p); + static void getoptnum (const char *n_str, int min, int *num, + const char *errfmt); static void getoptarg (char *arg, char switch_char, char *character, + int *character_length, int *character_width, int *number); @@ -1501,7 +1032,7 @@ index 10b8c52..079c86c 100644 -static void print_char (char c); static void cleanup (void); static void print_sep_string (void); - static void separator_string (char const *optarg_S); + static void separator_string (const char *optarg_S); @@ -453,7 +496,7 @@ static COLUMN *column_vector; we store the leftmost columns contiguously in buff. To print a line from buff, get the index of the first character @@ -1555,7 +1086,7 @@ index 10b8c52..079c86c 100644 static char *column_separator = (char *) " "; static char *line_separator = (char *) "\t"; -@@ -852,6 +905,13 @@ separator_string (char const *optarg_S) +@@ -851,6 +904,13 @@ separator_string (const char *optarg_S) integer_overflow (); col_sep_length = len; col_sep_string = optarg_S; @@ -1569,7 +1100,7 @@ index 10b8c52..079c86c 100644 } int -@@ -876,6 +936,21 @@ main (int argc, char **argv) +@@ -875,6 +935,21 @@ main (int argc, char **argv) atexit (close_stdout); @@ -1591,7 +1122,7 @@ index 10b8c52..079c86c 100644 n_files = 0; file_names = (argc > 1 ? xnmalloc (argc - 1, sizeof (char *)) -@@ -952,8 +1027,12 @@ main (int argc, char **argv) +@@ -951,8 +1026,12 @@ main (int argc, char **argv) break; case 'e': if (optarg) @@ -1606,7 +1137,7 @@ index 10b8c52..079c86c 100644 /* Could check tab width > 0. */ untabify_input = true; break; -@@ -966,8 +1045,12 @@ main (int argc, char **argv) +@@ -965,8 +1044,12 @@ main (int argc, char **argv) break; case 'i': if (optarg) @@ -1621,7 +1152,7 @@ index 10b8c52..079c86c 100644 /* Could check tab width > 0. */ tabify_output = true; break; -@@ -986,8 +1069,8 @@ main (int argc, char **argv) +@@ -984,8 +1067,8 @@ main (int argc, char **argv) case 'n': numbered_lines = true; if (optarg) @@ -1632,7 +1163,7 @@ index 10b8c52..079c86c 100644 break; case 'N': skip_count = false; -@@ -1013,6 +1096,7 @@ main (int argc, char **argv) +@@ -1010,6 +1093,7 @@ main (int argc, char **argv) /* Reset an additional input of -s, -S dominates -s */ col_sep_string = ""; col_sep_length = 0; @@ -1640,7 +1171,7 @@ index 10b8c52..079c86c 100644 use_col_separator = true; if (optarg) separator_string (optarg); -@@ -1168,7 +1252,8 @@ getoptnum (char const *n_str, int min, char const *err) +@@ -1166,10 +1250,45 @@ getoptnum (const char *n_str, int min, int *num, const char *err) a number. */ static void @@ -1648,12 +1179,7 @@ index 10b8c52..079c86c 100644 +getoptarg (char *arg, char switch_char, char *character, int *character_length, + int *character_width, int *number) { - if (!*arg) - { -@@ -1177,7 +1262,41 @@ getoptarg (char *arg, char switch_char, char *character, int *number) - } - - if (!c_isdigit (*arg)) + if (!ISDIGIT (*arg)) - *character = *arg++; + { +#ifdef HAVE_MBRTOWC @@ -1693,7 +1219,7 @@ index 10b8c52..079c86c 100644 if (*arg) { long int tmp_long; -@@ -1206,6 +1325,11 @@ static void +@@ -1191,6 +1310,11 @@ static void init_parameters (int number_of_files) { int chars_used_by_number = 0; @@ -1705,7 +1231,7 @@ index 10b8c52..079c86c 100644 lines_per_body = lines_per_page - lines_per_header - lines_per_footer; if (lines_per_body <= 0) -@@ -1243,7 +1367,7 @@ init_parameters (int number_of_files) +@@ -1228,7 +1352,7 @@ init_parameters (int number_of_files) else col_sep_string = column_separator; @@ -1714,7 +1240,7 @@ index 10b8c52..079c86c 100644 use_col_separator = true; } /* It's rather pointless to define a TAB separator with column -@@ -1275,11 +1399,11 @@ init_parameters (int number_of_files) +@@ -1258,11 +1382,11 @@ init_parameters (int number_of_files) + TAB_WIDTH (chars_per_input_tab, chars_per_number); */ /* Estimate chars_per_text without any margin and keep it constant. */ @@ -1728,16 +1254,16 @@ index 10b8c52..079c86c 100644 /* The number is part of the column width unless we are printing files in parallel. */ -@@ -1288,7 +1412,7 @@ init_parameters (int number_of_files) +@@ -1271,7 +1395,7 @@ init_parameters (int number_of_files) } int sep_chars, useful_chars; -- if (ckd_mul (&sep_chars, columns - 1, col_sep_length)) -+ if (ckd_mul (&sep_chars, columns - 1, col_sep_width)) +- if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_length, &sep_chars)) ++ if (INT_MULTIPLY_WRAPV (columns - 1, col_sep_width, &sep_chars)) sep_chars = INT_MAX; - if (ckd_sub (&useful_chars, chars_per_line - chars_used_by_number, - sep_chars)) -@@ -1311,7 +1435,7 @@ init_parameters (int number_of_files) + if (INT_SUBTRACT_WRAPV (chars_per_line - chars_used_by_number, sep_chars, + &useful_chars)) +@@ -1294,7 +1418,7 @@ init_parameters (int number_of_files) We've to use 8 as the lower limit, if we use chars_per_default_tab = 8 to expand a tab which is not an input_tab-char. */ free (clump_buff); @@ -1746,7 +1272,7 @@ index 10b8c52..079c86c 100644 } /* Open the necessary files, -@@ -1417,7 +1541,7 @@ init_funcs (void) +@@ -1402,7 +1526,7 @@ init_funcs (void) /* Enlarge p->start_position of first column to use the same form of padding_not_printed with all columns. */ @@ -1755,7 +1281,7 @@ index 10b8c52..079c86c 100644 /* This loop takes care of all but the rightmost column. */ -@@ -1451,7 +1575,7 @@ init_funcs (void) +@@ -1436,7 +1560,7 @@ init_funcs (void) } else { @@ -1764,7 +1290,7 @@ index 10b8c52..079c86c 100644 h_next = h + chars_per_column; } } -@@ -1751,9 +1875,9 @@ static void +@@ -1727,9 +1851,9 @@ static void align_column (COLUMN *p) { padding_not_printed = p->start_position; @@ -1776,9 +1302,9 @@ index 10b8c52..079c86c 100644 padding_not_printed = ANYWHERE; } -@@ -2030,13 +2154,13 @@ store_char (char c) +@@ -2004,13 +2128,13 @@ store_char (char c) /* May be too generous. */ - buff = xpalloc (buff, &buff_allocated, 1, -1, sizeof *buff); + buff = X2REALLOC (buff, &buff_allocated); } - buff[buff_current++] = c; + buff[buff_current++] = (unsigned char) c; @@ -1792,7 +1318,7 @@ index 10b8c52..079c86c 100644 char *s; int num_width; -@@ -2053,22 +2177,24 @@ add_line_number (COLUMN *p) +@@ -2027,22 +2151,24 @@ add_line_number (COLUMN *p) /* Tabification is assumed for multiple columns, also for n-separators, but 'default n-separator = TAB' hasn't been given priority over equal column_width also specified by POSIX. */ @@ -1821,7 +1347,7 @@ index 10b8c52..079c86c 100644 output_position = POS_AFTER_TAB (chars_per_output_tab, output_position); } -@@ -2227,7 +2353,7 @@ print_white_space (void) +@@ -2203,7 +2329,7 @@ print_white_space (void) while (goal - h_old > 1 && (h_new = POS_AFTER_TAB (chars_per_output_tab, h_old)) <= goal) { @@ -1830,7 +1356,7 @@ index 10b8c52..079c86c 100644 h_old = h_new; } while (++h_old <= goal) -@@ -2247,6 +2373,7 @@ print_sep_string (void) +@@ -2223,6 +2349,7 @@ print_sep_string (void) { char const *s = col_sep_string; int l = col_sep_length; @@ -1838,7 +1364,7 @@ index 10b8c52..079c86c 100644 if (separators_not_printed <= 0) { -@@ -2258,6 +2385,7 @@ print_sep_string (void) +@@ -2234,6 +2361,7 @@ print_sep_string (void) { for (; separators_not_printed > 0; --separators_not_printed) { @@ -1846,7 +1372,7 @@ index 10b8c52..079c86c 100644 while (l-- > 0) { /* 3 types of sep_strings: spaces only, spaces and chars, -@@ -2271,12 +2399,15 @@ print_sep_string (void) +@@ -2247,12 +2375,15 @@ print_sep_string (void) } else { @@ -1863,7 +1389,7 @@ index 10b8c52..079c86c 100644 /* sep_string ends with some spaces */ if (spaces_not_printed > 0) print_white_space (); -@@ -2307,7 +2438,7 @@ print_clump (COLUMN *p, int n, char *clump) +@@ -2280,7 +2411,7 @@ print_clump (COLUMN *p, int n, char *clump) required number of tabs and spaces. */ static void @@ -1872,7 +1398,7 @@ index 10b8c52..079c86c 100644 { if (tabify_output) { -@@ -2331,6 +2462,74 @@ print_char (char c) +@@ -2304,6 +2435,74 @@ print_char (char c) putchar (c); } @@ -1947,7 +1473,7 @@ index 10b8c52..079c86c 100644 /* Skip to page PAGE before printing. PAGE may be larger than total number of pages. */ -@@ -2507,9 +2706,9 @@ read_line (COLUMN *p) +@@ -2483,9 +2682,9 @@ read_line (COLUMN *p) align_empty_cols = false; } @@ -1959,8 +1485,8 @@ index 10b8c52..079c86c 100644 padding_not_printed = ANYWHERE; } -@@ -2578,7 +2777,7 @@ print_stored (COLUMN *p) - COLUMN *q; +@@ -2555,7 +2754,7 @@ print_stored (COLUMN *p) + int i; int line = p->current_line++; - char *first = &buff[line_vector[line]]; @@ -1968,7 +1494,7 @@ index 10b8c52..079c86c 100644 /* FIXME UMR: Uninitialized memory read: * This is occurring while in: -@@ -2590,7 +2789,7 @@ print_stored (COLUMN *p) +@@ -2567,7 +2766,7 @@ print_stored (COLUMN *p) xmalloc [xmalloc.c:94] init_store_cols [pr.c:1648] */ @@ -1977,7 +1503,7 @@ index 10b8c52..079c86c 100644 pad_vertically = true; -@@ -2610,9 +2809,9 @@ print_stored (COLUMN *p) +@@ -2586,9 +2785,9 @@ print_stored (COLUMN *p) } } @@ -1989,7 +1515,7 @@ index 10b8c52..079c86c 100644 padding_not_printed = ANYWHERE; } -@@ -2625,8 +2824,8 @@ print_stored (COLUMN *p) +@@ -2601,8 +2800,8 @@ print_stored (COLUMN *p) if (spaces_not_printed == 0) { output_position = p->start_position + end_vector[line]; @@ -2000,7 +1526,7 @@ index 10b8c52..079c86c 100644 } return true; -@@ -2645,7 +2844,7 @@ print_stored (COLUMN *p) +@@ -2621,7 +2820,7 @@ print_stored (COLUMN *p) number of characters is 1.) */ static int @@ -2009,7 +1535,7 @@ index 10b8c52..079c86c 100644 { unsigned char uc = c; char *s = clump_buff; -@@ -2655,10 +2854,10 @@ char_to_clump (char c) +@@ -2631,10 +2830,10 @@ char_to_clump (char c) int chars; int chars_per_c = 8; @@ -2022,7 +1548,7 @@ index 10b8c52..079c86c 100644 { width = TAB_WIDTH (chars_per_c, input_position); -@@ -2739,6 +2938,164 @@ char_to_clump (char c) +@@ -2715,6 +2914,164 @@ char_to_clump (char c) return chars; } @@ -2188,14 +1714,13 @@ index 10b8c52..079c86c 100644 looking for more options and printing the next batch of files. diff --git a/src/sort.c b/src/sort.c -index 05d00cc..eb51f20 100644 +index 6d2eec5..f189a0d 100644 --- a/src/sort.c +++ b/src/sort.c -@@ -30,6 +30,15 @@ +@@ -29,6 +29,14 @@ #include #include - #include -+ + #include +#if HAVE_WCHAR_H +# include +#endif @@ -2206,10 +1731,10 @@ index 05d00cc..eb51f20 100644 + #include "system.h" #include "argmatch.h" - #include "assure.h" -@@ -160,14 +169,39 @@ static int thousands_sep; - /* We currently ignore multi-byte grouping chars. */ - static bool thousands_sep_ignored; + #include "die.h" +@@ -165,14 +173,39 @@ static int decimal_point; + /* Thousands separator; if -1, then there isn't one. */ + static int thousands_sep; +/* True if -f is specified. */ +static bool folding; @@ -2248,9 +1773,9 @@ index 05d00cc..eb51f20 100644 /* The kind of blanks for '-b' to skip in various options. */ enum blanktype { bl_start, bl_end, bl_both }; -@@ -344,13 +378,11 @@ static bool stable; - /* An int value outside char range. */ - enum { NON_CHAR = CHAR_MAX + 1 }; +@@ -346,13 +379,11 @@ static bool reverse; + they were read if all keys compare equal. */ + static bool stable; -/* If TAB has this value, blanks separate fields. */ -enum { TAB_DEFAULT = CHAR_MAX + 1 }; @@ -2265,9 +1790,9 @@ index 05d00cc..eb51f20 100644 /* Flag to remove consecutive duplicate lines from the output. Only the last of a sequence of equal lines will be output. */ -@@ -386,6 +418,46 @@ struct tempnode - static struct tempnode *volatile temphead; - static struct tempnode *volatile *temptail = &temphead; +@@ -811,6 +842,46 @@ reap_all (void) + reap (-1); + } +/* Function pointers. */ +static void @@ -2312,7 +1837,7 @@ index 05d00cc..eb51f20 100644 /* Clean up any remaining temporary files. */ static void -@@ -1343,7 +1415,7 @@ zaptemp (char const *name) +@@ -1255,7 +1326,7 @@ zaptemp (char const *name) free (node); } @@ -2321,7 +1846,7 @@ index 05d00cc..eb51f20 100644 static int struct_month_cmp (void const *m1, void const *m2) -@@ -1358,7 +1430,7 @@ struct_month_cmp (void const *m1, void const *m2) +@@ -1270,7 +1341,7 @@ struct_month_cmp (void const *m1, void const *m2) /* Initialize the character class tables. */ static void @@ -2330,7 +1855,7 @@ index 05d00cc..eb51f20 100644 { size_t i; -@@ -1370,7 +1442,7 @@ inittables (void) +@@ -1282,7 +1353,7 @@ inittables (void) fold_toupper[i] = toupper (i); } @@ -2339,7 +1864,7 @@ index 05d00cc..eb51f20 100644 /* If we're not in the "C" locale, read different names for months. */ if (hard_LC_TIME) { -@@ -1450,6 +1522,84 @@ specify_nmerge (int oi, char c, char const *s) +@@ -1364,6 +1435,84 @@ specify_nmerge (int oi, char c, char const *s) xstrtol_fatal (e, oi, c, long_options, s); } @@ -2424,7 +1949,7 @@ index 05d00cc..eb51f20 100644 /* Specify the amount of main memory to use when sorting. */ static void specify_sort_size (int oi, char c, char const *s) -@@ -1676,7 +1826,7 @@ buffer_linelim (struct buffer const *buf) +@@ -1597,7 +1746,7 @@ buffer_linelim (struct buffer const *buf) by KEY in LINE. */ static char * @@ -2433,7 +1958,7 @@ index 05d00cc..eb51f20 100644 { char *ptr = line->text, *lim = ptr + line->length - 1; size_t sword = key->sword; -@@ -1685,10 +1835,10 @@ begfield (struct line const *line, struct keyfield const *key) +@@ -1606,10 +1755,10 @@ begfield (struct line const *line, struct keyfield const *key) /* The leading field separator itself is included in a field when -t is absent. */ @@ -2446,7 +1971,7 @@ index 05d00cc..eb51f20 100644 ++ptr; if (ptr < lim) ++ptr; -@@ -1718,12 +1868,71 @@ begfield (struct line const *line, struct keyfield const *key) +@@ -1635,11 +1784,70 @@ begfield (struct line const *line, struct keyfield const *key) return ptr; } @@ -2512,14 +2037,13 @@ index 05d00cc..eb51f20 100644 /* Return the limit of (a pointer to the first character after) the field in LINE specified by KEY. */ - ATTRIBUTE_PURE static char * -limfield (struct line const *line, struct keyfield const *key) -+limfield_uni (struct line const *line, struct keyfield const *key) ++limfield_uni (const struct line *line, const struct keyfield *key) { char *ptr = line->text, *lim = ptr + line->length - 1; size_t eword = key->eword, echar = key->echar; -@@ -1738,10 +1947,10 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1654,10 +1862,10 @@ limfield (struct line const *line, struct keyfield const *key) 'beginning' is the first character following the delimiting TAB. Otherwise, leave PTR pointing at the first 'blank' character after the preceding field. */ @@ -2532,7 +2056,7 @@ index 05d00cc..eb51f20 100644 ++ptr; if (ptr < lim && (eword || echar)) ++ptr; -@@ -1787,10 +1996,10 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1703,10 +1911,10 @@ limfield (struct line const *line, struct keyfield const *key) */ /* Make LIM point to the end of (one byte past) the current field. */ @@ -2545,12 +2069,12 @@ index 05d00cc..eb51f20 100644 if (newlim) lim = newlim; } -@@ -1825,6 +2034,130 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1737,6 +1945,130 @@ limfield (struct line const *line, struct keyfield const *key) return ptr; } +#if HAVE_MBRTOWC -+static char * _GL_ATTRIBUTE_PURE ++static char * +limfield_mb (const struct line *line, const struct keyfield *key) +{ + char *ptr = line->text, *lim = ptr + line->length - 1; @@ -2676,7 +2200,7 @@ index 05d00cc..eb51f20 100644 /* Fill BUF reading from FP, moving buf->left bytes from the end of buf->buf to the beginning first. If EOF is reached and the file wasn't terminated by a newline, supply one. Set up BUF's line -@@ -1911,8 +2244,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file) +@@ -1823,8 +2155,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file) else { if (key->skipsblanks) @@ -2701,32 +2225,16 @@ index 05d00cc..eb51f20 100644 line->keybeg = line_start; } } -@@ -2050,12 +2397,10 @@ find_unit_order (char const *number) +@@ -1974,7 +2320,7 @@ human_numcompare (char const *a, char const *b) + hideously fast. */ - ATTRIBUTE_PURE - static int --human_numcompare (char const *a, char const *b) -+human_numcompare (char *a, char *b) - { -- while (blanks[to_uchar (*a)]) -- a++; -- while (blanks[to_uchar (*b)]) -- b++; -+ skipblanks(&a, a + strlen(a)); -+ skipblanks(&b, b + strlen(b)); - - int diff = find_unit_order (a) - find_unit_order (b); - return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); -@@ -2067,7 +2412,7 @@ human_numcompare (char const *a, char const *b) - - ATTRIBUTE_PURE static int -numcompare (char const *a, char const *b) +numcompare_uni (const char *a, const char *b) { while (blanks[to_uchar (*a)]) a++; -@@ -2077,6 +2422,25 @@ numcompare (char const *a, char const *b) +@@ -1984,6 +2330,25 @@ numcompare (char const *a, char const *b) return strnumcmp (a, b, decimal_point, thousands_sep); } @@ -2749,10 +2257,10 @@ index 05d00cc..eb51f20 100644 +} +#endif /* HAV_EMBRTOWC */ + - static int - nan_compare (long double a, long double b) - { -@@ -2118,7 +2482,7 @@ general_numcompare (char const *sa, char const *sb) + /* Work around a problem whereby the long double value returned by glibc's + strtold ("NaN", ...) contains uninitialized bits: clear all bytes of + A and B before calling strtold. FIXME: remove this function once +@@ -2034,7 +2399,7 @@ general_numcompare (char const *sa, char const *sb) Return 0 if the name in S is not recognized. */ static int @@ -2761,7 +2269,7 @@ index 05d00cc..eb51f20 100644 { size_t lo = 0; size_t hi = MONTHS_PER_YEAR; -@@ -2457,15 +2821,14 @@ debug_key (struct line const *line, struct keyfield const *key) +@@ -2310,15 +2675,14 @@ debug_key (struct line const *line, struct keyfield const *key) char saved = *lim; *lim = '\0'; @@ -2779,7 +2287,7 @@ index 05d00cc..eb51f20 100644 else if (key->general_numeric) ignore_value (strtold (beg, &tighter_lim)); else if (key->numeric || key->human_numeric) -@@ -2611,7 +2974,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2452,7 +2816,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) /* Warn about significant leading blanks. */ bool implicit_skip = key_numeric (key) || key->month; bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y */ @@ -2788,58 +2296,8 @@ index 05d00cc..eb51f20 100644 && ((!key->skipsblanks && !implicit_skip) || (!key->skipsblanks && key->schar) || (!key->skipeblanks && key->echar))) -@@ -2659,9 +3022,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - bool number_locale_warned = false; - if (basic_numeric_field_span) - { -- if (tab == TAB_DEFAULT -- ? thousands_sep != NON_CHAR && (isblank (to_uchar (thousands_sep))) -- : tab == thousands_sep) -+ if (tab_length -+ ? tab[0] == thousands_sep -+ : thousands_sep != NON_CHAR && (isblank (to_uchar (thousands_sep)))) - { - error (0, 0, - _("field separator %s is treated as a " -@@ -2672,9 +3035,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - } - if (basic_numeric_field_span || general_numeric_field_span) - { -- if (tab == TAB_DEFAULT -- ? thousands_sep != NON_CHAR && (isblank (to_uchar (decimal_point))) -- : tab == decimal_point) -+ if (tab_length -+ ? tab[0] == decimal_point -+ : thousands_sep != NON_CHAR && (isblank (to_uchar (decimal_point)))) - { - error (0, 0, - _("field separator %s is treated as a " -@@ -2682,19 +3045,19 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) - quote (((char []) {decimal_point, 0}))); - number_locale_warned = true; - } -- else if (tab == '-') -+ else if (tab_length && tab[0] == '-') - { - error (0, 0, - _("field separator %s is treated as a " - "minus sign in numbers"), -- quote (((char []) {tab, 0}))); -+ quote (((char []) {tab[0], 0}))); - } -- else if (general_numeric_field_span && tab == '+') -+ else if (general_numeric_field_span && tab_length && tab[0] == '+') - { - error (0, 0, - _("field separator %s is treated as a " - "plus sign in numbers"), -- quote (((char []) {tab, 0}))); -+ quote (((char []) {tab[0], 0}))); - } - } - -@@ -2746,11 +3109,87 @@ diff_reversed (int diff, bool reversed) - return reversed ? _GL_CMP (0, diff) : diff; +@@ -2510,11 +2874,87 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) + error (0, 0, _("option '-r' only applies to last-resort comparison")); } +#if HAVE_MBRTOWC @@ -2927,17 +2385,17 @@ index 05d00cc..eb51f20 100644 { struct keyfield *key = keylist; -@@ -2831,7 +3270,7 @@ keycompare (struct line const *a, struct line const *b) +@@ -2599,7 +3039,7 @@ keycompare (struct line const *a, struct line const *b) else if (key->human_numeric) diff = human_numcompare (ta, tb); else if (key->month) -- diff = getmonth (ta, nullptr) - getmonth (tb, nullptr); -+ diff = getmonth (ta, tlena, nullptr) - getmonth (tb, tlenb, nullptr); +- diff = getmonth (ta, NULL) - getmonth (tb, NULL); ++ diff = getmonth (ta, tlena, NULL) - getmonth (tb, tlenb, NULL); else if (key->random) diff = compare_random (ta, tlena, tb, tlenb); else if (key->version) -@@ -2941,6 +3380,211 @@ keycompare (struct line const *a, struct line const *b) - return diff_reversed (diff, key->reverse); +@@ -2715,6 +3155,211 @@ keycompare (struct line const *a, struct line const *b) + return key->reverse ? -diff : diff; } +#if HAVE_MBRTOWC @@ -3148,16 +2606,16 @@ index 05d00cc..eb51f20 100644 /* Compare two lines A and B, returning negative, zero, or positive depending on whether A compares less than, equal to, or greater than B. */ -@@ -2968,7 +3612,7 @@ compare (struct line const *a, struct line const *b) +@@ -2742,7 +3387,7 @@ compare (struct line const *a, struct line const *b) diff = - NONZERO (blen); else if (blen == 0) diff = 1; - else if (hard_LC_COLLATE) + else if (hard_LC_COLLATE && !folding) { - /* xmemcoll0 is a performance enhancement as + /* Note xmemcoll0 is a performance enhancement as it will not unconditionally write '\0' after the -@@ -4340,6 +4984,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype) +@@ -4139,6 +4784,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype) break; case 'f': key->translate = fold_toupper; @@ -3165,7 +2623,7 @@ index 05d00cc..eb51f20 100644 break; case 'g': key->general_numeric = true; -@@ -4419,7 +5064,7 @@ main (int argc, char **argv) +@@ -4218,7 +4864,7 @@ main (int argc, char **argv) initialize_exit_failure (SORT_FAILURE); hard_LC_COLLATE = hard_locale (LC_COLLATE); @@ -3174,8 +2632,8 @@ index 05d00cc..eb51f20 100644 hard_LC_TIME = hard_locale (LC_TIME); #endif -@@ -4442,6 +5087,29 @@ main (int argc, char **argv) - thousands_sep = NON_CHAR; +@@ -4239,6 +4885,29 @@ main (int argc, char **argv) + thousands_sep = -1; } +#if HAVE_MBRTOWC @@ -3204,7 +2662,7 @@ index 05d00cc..eb51f20 100644 have_read_stdin = false; inittables (); -@@ -4717,13 +5385,34 @@ main (int argc, char **argv) +@@ -4513,13 +5182,34 @@ main (int argc, char **argv) case 't': { @@ -3214,7 +2672,7 @@ index 05d00cc..eb51f20 100644 + size_t newtab_length = 1; + strncpy (newtab, optarg, MB_LEN_MAX); + if (! newtab[0]) - error (SORT_FAILURE, 0, _("empty tab")); + die (SORT_FAILURE, 0, _("empty tab")); - if (optarg[1]) +#if HAVE_MBRTOWC + if (MB_CUR_MAX > 1) @@ -3237,433 +2695,429 @@ index 05d00cc..eb51f20 100644 +#endif + if (newtab_length == 1 && optarg[1]) { - if (streq (optarg, "\\0")) + if (STREQ (optarg, "\\0")) - newtab = '\0'; + newtab[0] = '\0'; else { /* Provoke with 'sort -txx'. Complain about -@@ -4734,9 +5423,11 @@ main (int argc, char **argv) - quote (optarg)); +@@ -4530,9 +5220,11 @@ main (int argc, char **argv) + quote (optarg)); } } - if (tab != TAB_DEFAULT && tab != newtab) + if (tab_length && (tab_length != newtab_length + || memcmp (tab, newtab, tab_length) != 0)) - error (SORT_FAILURE, 0, _("incompatible tabs")); + die (SORT_FAILURE, 0, _("incompatible tabs")); - tab = newtab; + memcpy (tab, newtab, newtab_length); + tab_length = newtab_length; } break; -diff --git a/src/unexpand.c b/src/unexpand.c -index ff234d7..7c36ef6 100644 ---- a/src/unexpand.c -+++ b/src/unexpand.c -@@ -39,6 +39,9 @@ - #include +@@ -4770,12 +5462,10 @@ main (int argc, char **argv) + sort (files, nfiles, outfile, nthreads); + } + +-#ifdef lint + if (files_from) + readtokens0_free (&tok); + else + free (files); +-#endif + + if (have_read_stdin && fclose (stdin) == EOF) + sort_die (_("close failed"), "-"); +diff --git a/src/uniq.c b/src/uniq.c +index 87a0c93..9f755d9 100644 +--- a/src/uniq.c ++++ b/src/uniq.c +@@ -21,6 +21,17 @@ #include #include + ++/* Get mbstate_t, mbrtowc(). */ ++#if HAVE_WCHAR_H ++# include ++#endif + -+#include ++/* Get isw* functions. */ ++#if HAVE_WCTYPE_H ++# include ++#endif ++#include + #include "system.h" - #include "expand-common.h" + #include "argmatch.h" + #include "linebuffer.h" +@@ -32,9 +43,21 @@ + #include "stdio--.h" + #include "xmemcoll.h" + #include "xstrtol.h" +-#include "memcasecmp.h" ++#include "xmemcoll.h" + #include "quote.h" -@@ -105,24 +108,46 @@ unexpand (void) ++/* MB_LEN_MAX is incorrectly defined to be 1 in at least one GCC ++ installation; work around this configuration error. */ ++#if !defined MB_LEN_MAX || MB_LEN_MAX < 2 ++# define MB_LEN_MAX 16 ++#endif ++ ++/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ ++#if HAVE_MBRTOWC && defined mbstate_t ++# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0) ++#endif ++ ++ + /* The official name of this program (e.g., no 'g' prefix). */ + #define PROGRAM_NAME "uniq" + +@@ -144,6 +167,10 @@ enum + GROUP_OPTION = CHAR_MAX + 1 + }; + ++/* Function pointers. */ ++static char * ++(*find_field) (struct linebuffer *line); ++ + static struct option const longopts[] = { - /* Input stream. */ - FILE *fp = next_file (nullptr); -+ mb_file_t mbf; + {"count", no_argument, NULL, 'c'}, +@@ -260,7 +287,7 @@ size_opt (char const *opt, char const *msgid) + return a pointer to the beginning of the line's field to be compared. */ - /* The array of pending blanks. In non-POSIX locales, blanks can - include characters other than spaces, so the blanks must be - stored, not merely counted. */ -- char *pending_blank; -+ mbf_char_t *pending_blank; -+ /* True if the starting locale is utf8. */ -+ bool using_utf_locale; + static char * _GL_ATTRIBUTE_PURE +-find_field (struct linebuffer const *line) ++find_field_uni (struct linebuffer *line) + { + size_t count; + char const *lp = line->buffer; +@@ -280,6 +307,83 @@ find_field (struct linebuffer const *line) + return line->buffer + i; + } + ++#if HAVE_MBRTOWC + -+ /* True if the first file contains BOM header. */ -+ bool found_bom; -+ using_utf_locale=check_utf_locale(); - - if (!fp) - return; - -+ mbf_init (mbf, fp); -+ found_bom=check_bom(fp,&mbf); ++# define MBCHAR_TO_WCHAR(WC, MBLENGTH, LP, POS, SIZE, STATEP, CONVFAIL) \ ++ do \ ++ { \ ++ mbstate_t state_bak; \ ++ \ ++ CONVFAIL = 0; \ ++ state_bak = *STATEP; \ ++ \ ++ MBLENGTH = mbrtowc (&WC, LP + POS, SIZE - POS, STATEP); \ ++ \ ++ switch (MBLENGTH) \ ++ { \ ++ case (size_t)-2: \ ++ case (size_t)-1: \ ++ *STATEP = state_bak; \ ++ CONVFAIL++; \ ++ /* Fall through */ \ ++ case 0: \ ++ MBLENGTH = 1; \ ++ } \ ++ } \ ++ while (0) + -+ if (using_utf_locale == false && found_bom == true) ++static char * ++find_field_multi (struct linebuffer *line) ++{ ++ size_t count; ++ char *lp = line->buffer; ++ size_t size = line->length - 1; ++ size_t pos; ++ size_t mblength; ++ wchar_t wc; ++ mbstate_t *statep; ++ int convfail = 0; ++ ++ pos = 0; ++ statep = &(line->state); ++ ++ /* skip fields. */ ++ for (count = 0; count < skip_fields && pos < size; count++) + { -+ /* Try using some predefined locale */ -+ if (set_utf_locale () != 0) ++ while (pos < size) + { -+ error (EXIT_FAILURE, errno, _("cannot set UTF-8 locale")); ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (convfail || !(iswblank (wc) || wc == '\n')) ++ { ++ pos += mblength; ++ break; ++ } ++ pos += mblength; ++ } ++ ++ while (pos < size) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ ++ if (!convfail && (iswblank (wc) || wc == '\n')) ++ break; ++ ++ pos += mblength; + } + } + - /* The worst case is a non-blank character, then one blank, then a - tab stop, then MAX_COLUMN_WIDTH - 1 blanks, then a non-blank; so - allocate MAX_COLUMN_WIDTH bytes to store the blanks. */ -- pending_blank = ximalloc (max_column_width); -+ pending_blank = ximalloc (max_column_width * sizeof (mbf_char_t)); ++ /* skip fields. */ ++ for (count = 0; count < skip_chars && pos < size; count++) ++ { ++ MBCHAR_TO_WCHAR (wc, mblength, lp, pos, size, statep, convfail); ++ pos += mblength; ++ } + -+ if (found_bom == true) -+ print_bom(); ++ return lp + pos; ++} ++#endif ++ + /* Return false if two strings OLD and NEW match, true if not. + OLD and NEW point not to the beginnings of the lines + but rather to the beginnings of the fields to compare. +@@ -288,6 +392,8 @@ find_field (struct linebuffer const *line) + static bool + different (char *old, char *new, size_t oldlen, size_t newlen) + { ++ char *copy_old, *copy_new; ++ + if (check_chars < oldlen) + oldlen = check_chars; + if (check_chars < newlen) +@@ -295,15 +401,104 @@ different (char *old, char *new, size_t oldlen, size_t newlen) - while (true) + if (ignore_case) { - /* Input character, or EOF. */ -- int c; -+ mbf_char_t c; - - /* If true, perform translations. */ - bool convert = true; -@@ -156,12 +181,44 @@ unexpand (void) - - do - { -- while ((c = getc (fp)) < 0 && (fp = next_file (fp))) -- continue; -+ while (true) { -+ mbf_getc (c, mbf); -+ if ((mb_iseof (c)) && (fp = next_file (fp))) -+ { -+ mbf_init (mbf, fp); -+ if (fp!=NULL) -+ { -+ if (check_bom(fp,&mbf)==true) -+ { -+ /*Not the first file - check BOM header*/ -+ if (using_utf_locale==false && found_bom==false) -+ { -+ /*BOM header in subsequent file but not in the first one. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ else -+ { -+ if(using_utf_locale==false && found_bom==true) -+ { -+ /*First file conatined BOM header - locale was switched to UTF -+ *all subsequent files should contain BOM. */ -+ error (EXIT_FAILURE, errno, _("combination of files with and without BOM header")); -+ } -+ } -+ } -+ continue; -+ } -+ else -+ { -+ break; -+ } -+ } +- /* FIXME: This should invoke strcoll somehow. */ +- return oldlen != newlen || memcasecmp (old, new, oldlen); ++ size_t i; + - - if (convert) - { -- bool blank = !! isblank (c); -+ bool blank = mb_isblank (c); - - if (blank) - { -@@ -175,16 +232,16 @@ unexpand (void) - - if (convert) - { -- if (c == '\t') -+ if (mb_iseq (c, '\t')) - { - column = next_tab_column; - - if (pending) -- pending_blank[0] = '\t'; -+ mb_setascii (&pending_blank[0], '\t'); - } - else - { -- column++; -+ column += mb_width (c); - - if (! (prev_blank && column == next_tab_column)) - { -@@ -192,13 +249,14 @@ unexpand (void) - will be replaced by tabs. */ - if (column == next_tab_column) - one_blank_before_tab_stop = true; -- pending_blank[pending++] = c; -+ mb_copy (&pending_blank[pending++], &c); - prev_blank = true; - continue; - } - - /* Replace the pending blanks by a tab or two. */ -- pending_blank[0] = c = '\t'; -+ mb_setascii (&c, '\t'); -+ mb_setascii (&pending_blank[0], '\t'); - } - - /* Discard pending blanks, unless it was a single -@@ -206,7 +264,7 @@ unexpand (void) - pending = one_blank_before_tab_stop; - } - } -- else if (c == '\b') -+ else if (mb_iseq (c, '\b')) - { - /* Go back one column, and force recalculation of the - next tab stop. */ -@@ -216,16 +274,20 @@ unexpand (void) - } - else - { -- column++; -- if (!column) -+ const uintmax_t orig_column = column; -+ column += mb_width (c); -+ if (column < orig_column) - error (EXIT_FAILURE, 0, _("input line is too long")); - } - - if (pending) - { - if (pending > 1 && one_blank_before_tab_stop) -- pending_blank[0] = '\t'; -- if (fwrite (pending_blank, 1, pending, stdout) != pending) -+ mb_setascii (&pending_blank[0], '\t'); ++ copy_old = xmalloc (oldlen + 1); ++ copy_new = xmalloc (oldlen + 1); + -+ for (int n = 0; n < pending; ++n) -+ mb_putc (pending_blank[n], stdout); -+ if (ferror (stdout)) - write_error (); - pending = 0; - one_blank_before_tab_stop = false; -@@ -235,16 +297,17 @@ unexpand (void) - convert &= convert_entire_line || blank; - } - -- if (c < 0) -+ if (mb_iseof (c)) - { - free (pending_blank); - return; - } - -- if (putchar (c) < 0) -+ mb_putc (c, stdout); -+ if (ferror (stdout)) - write_error (); - } -- while (c != '\n'); -+ while (!mb_iseq (c, '\n')); ++ for (i = 0; i < oldlen; i++) ++ { ++ copy_old[i] = toupper (old[i]); ++ copy_new[i] = toupper (new[i]); ++ } ++ bool rc = xmemcoll (copy_old, oldlen, copy_new, newlen); ++ free (copy_old); ++ free (copy_new); ++ return rc; } +- else if (hard_LC_COLLATE) +- return xmemcoll (old, oldlen, new, newlen) != 0; + else +- return oldlen != newlen || memcmp (old, new, oldlen); ++ { ++ copy_old = (char *)old; ++ copy_new = (char *)new; ++ } ++ ++ return xmemcoll (copy_old, oldlen, copy_new, newlen); ++ } -diff --git a/tests/Coreutils.pm b/tests/Coreutils.pm -index b55fb9d..ac80f49 100644 ---- a/tests/Coreutils.pm -+++ b/tests/Coreutils.pm -@@ -269,6 +269,9 @@ sub run_tests ($$$$$) - # Yes, this is an arbitrary limit. If it causes trouble, - # consider removing it. - my $max = 30; -+ # The downstream i18n multi-byte tests have a "-mb" suffix. -+ # Therefore add 3 to the maximum test name length. -+ $max += 3; - if ($max < length $test_name) ++#if HAVE_MBRTOWC ++static int ++different_multi (const char *old, const char *new, size_t oldlen, size_t newlen, mbstate_t oldstate, mbstate_t newstate) ++{ ++ size_t i, j, chars; ++ const char *str[2]; ++ char *copy[2]; ++ size_t len[2]; ++ mbstate_t state[2]; ++ size_t mblength; ++ wchar_t wc, uwc; ++ mbstate_t state_bak; ++ ++ str[0] = old; ++ str[1] = new; ++ len[0] = oldlen; ++ len[1] = newlen; ++ state[0] = oldstate; ++ state[1] = newstate; ++ ++ for (i = 0; i < 2; i++) ++ { ++ copy[i] = xmalloc (len[i] + 1); ++ memset (copy[i], '\0', len[i] + 1); ++ ++ for (j = 0, chars = 0; j < len[i] && chars < check_chars; chars++) ++ { ++ state_bak = state[i]; ++ mblength = mbrtowc (&wc, str[i] + j, len[i] - j, &(state[i])); ++ ++ switch (mblength) ++ { ++ case (size_t)-1: ++ case (size_t)-2: ++ state[i] = state_bak; ++ /* Fall through */ ++ case 0: ++ mblength = 1; ++ break; ++ ++ default: ++ if (ignore_case) ++ { ++ uwc = towupper (wc); ++ ++ if (uwc != wc) ++ { ++ mbstate_t state_wc; ++ size_t mblen; ++ ++ memset (&state_wc, '\0', sizeof(mbstate_t)); ++ mblen = wcrtomb (copy[i] + j, uwc, &state_wc); ++ assert (mblen != (size_t)-1); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ else ++ memcpy (copy[i] + j, str[i] + j, mblength); ++ } ++ j += mblength; ++ } ++ copy[i][j] = '\0'; ++ len[i] = j; ++ } ++ int rc = xmemcoll (copy[0], len[0], copy[1], len[1]); ++ free (copy[0]); ++ free (copy[1]); ++ return rc; ++ ++} ++#endif ++ + /* Output the line in linebuffer LINE to standard output + provided that the switches say it should be output. + MATCH is true if the line matches the previous line. +@@ -367,19 +562,38 @@ check_file (const char *infile, const char *outfile, char delimiter) + char *prevfield IF_LINT ( = NULL); + size_t prevlen IF_LINT ( = 0); + bool first_group_printed = false; ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++ ++ memset (&prevstate, '\0', sizeof (mbstate_t)); ++#endif + + while (!feof (stdin)) { - warn "$program_name: $test_name: test name is too long (> $max)\n"; -diff --git a/tests/expand/mb.sh b/tests/expand/mb.sh -new file mode 100644 -index 0000000..dd6007c ---- /dev/null -+++ b/tests/expand/mb.sh -@@ -0,0 +1,183 @@ -+#!/bin/sh -+ -+# Copyright (C) 2012-2015 Free Software Foundation, Inc. -+ -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+ -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+ -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ expand -+ -+export LC_ALL=en_US.UTF-8 -+ -+#input containing multibyte characters -+cat <<\EOF > in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+cat <<\EOF > exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#multiple files as an input -+cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand ./in ./in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#test characters with display widths != 1 -+env printf '12345678 -+e\t|ascii(1) -+\u00E9\t|composed(1) -+e\u0301\t|decomposed(1) -+\u3000\t|ideo-space(2) -+\uFF0D\t|full-hypen(2) -+' > in || framework_failure_ -+ -+env printf '12345678 -+e |ascii(1) -+\u00E9 |composed(1) -+e\u0301 |decomposed(1) -+\u3000 |ideo-space(2) -+\uFF0D |full-hypen(2) -+' > exp || framework_failure_ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#shouldn't fail with "input line too long" -+#when a line starts with a control character -+env printf '\n' > in || framework_failure_ -+ -+expand < in > out || fail=1 -+compare in out > /dev/null 2>&1 || fail=1 -+ -+#non-Unicode characters interspersed between Unicode ones -+env printf '12345678 -+\t\xFF| -+\xFF\t| -+\t\xFFä| -+ä\xFF\t| -+\tä\xFF| -+\xFF\tä| -+äbcdef\xFF\t| -+' > in || framework_failure_ -+ -+env printf '12345678 -+ \xFF| -+\xFF | -+ \xFFä| -+ä\xFF | -+ ä\xFF| -+\xFF ä| -+äbcdef\xFF | -+' > exp || framework_failure_ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 + char *thisfield; + size_t thislen; + bool new_group; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate; ++#endif + + if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) + break; + + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ thisstate = thisline->state; + ++ new_group = (prevline->length == 0 ++ || different_multi (thisfield, prevfield, ++ thislen, prevlen, ++ thisstate, prevstate)); ++ } ++ else ++#endif + new_group = (prevline->length == 0 + || different (thisfield, prevfield, thislen, prevlen)); + +@@ -397,6 +611,10 @@ check_file (const char *infile, const char *outfile, char delimiter) + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ prevstate = thisstate; ++#endif + first_group_printed = true; + } + } +@@ -409,17 +627,26 @@ check_file (const char *infile, const char *outfile, char delimiter) + size_t prevlen; + uintmax_t match_count = 0; + bool first_delimiter = true; ++#if HAVE_MBRTOWC ++ mbstate_t prevstate; ++#endif + + if (readlinebuffer_delim (prevline, stdin, delimiter) == 0) + goto closefiles; + prevfield = find_field (prevline); + prevlen = prevline->length - 1 - (prevfield - prevline->buffer); ++#if HAVE_MBRTOWC ++ prevstate = prevline->state; ++#endif + + while (!feof (stdin)) + { + bool match; + char *thisfield; + size_t thislen; ++#if HAVE_MBRTOWC ++ mbstate_t thisstate = thisline->state; ++#endif + if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) + { + if (ferror (stdin)) +@@ -428,6 +655,14 @@ check_file (const char *infile, const char *outfile, char delimiter) + } + thisfield = find_field (thisline); + thislen = thisline->length - 1 - (thisfield - thisline->buffer); ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ match = !different_multi (thisfield, prevfield, ++ thislen, prevlen, thisstate, prevstate); ++ } ++ else ++#endif + match = !different (thisfield, prevfield, thislen, prevlen); + match_count += match; + +@@ -460,6 +695,9 @@ check_file (const char *infile, const char *outfile, char delimiter) + SWAP_LINES (prevline, thisline); + prevfield = thisfield; + prevlen = thislen; ++#if HAVE_MBRTOWC ++ prevstate = thisstate; ++#endif + if (!match) + match_count = 0; + } +@@ -506,6 +744,19 @@ main (int argc, char **argv) + + atexit (close_stdout); + ++#if HAVE_MBRTOWC ++ if (MB_CUR_MAX > 1) ++ { ++ find_field = find_field_multi; ++ } ++ else ++#endif ++ { ++ find_field = find_field_uni; ++ } + + + -+#BOM header test 1 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+ -+expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C expand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+printf '\xEF\xBB\xBF' > in1; cat <<\EOF >> in1 || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in1 || framework_failure_ -+ -+ -+printf '\xEF\xBB\xBF' > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C expand in1 in1 > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+exit $fail + skip_chars = 0; + skip_fields = 0; + check_chars = SIZE_MAX; diff --git a/tests/i18n/sort.sh b/tests/i18n/sort.sh new file mode 100644 index 0000000..26c95de @@ -3700,36 +3154,46 @@ index 0000000..26c95de + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk -index 53fc53e..0148422 100644 +index 568944e..192f776 100644 --- a/tests/local.mk +++ b/tests/local.mk -@@ -412,6 +412,8 @@ all_tests = \ - tests/sort/sort-field-limit.sh \ - tests/sort/sort-files0-from.pl \ - tests/sort/sort-float.sh \ +@@ -352,6 +352,8 @@ all_tests = \ + tests/misc/sort-discrim.sh \ + tests/misc/sort-files0-from.pl \ + tests/misc/sort-float.sh \ + tests/misc/sort-mb-tests.sh \ + tests/i18n/sort.sh \ - tests/sort/sort-h-thousands-sep.sh \ - tests/sort/sort-merge.pl \ - tests/sort/sort-merge-fdlimit.sh \ -@@ -618,6 +620,7 @@ all_tests = \ - tests/du/threshold.sh \ - tests/du/trailing-slash.sh \ - tests/du/two-args.sh \ -+ tests/expand/mb.sh \ - tests/id/gnu-zero-uids.sh \ - tests/id/no-context.sh \ - tests/id/context.sh \ -@@ -774,6 +777,7 @@ all_tests = \ - tests/touch/read-only.sh \ - tests/touch/relative.sh \ - tests/touch/trailing-slash.sh \ -+ tests/unexpand/mb.sh \ - $(all_root_tests) + tests/misc/sort-h-thousands-sep.sh \ + tests/misc/sort-merge.pl \ + tests/misc/sort-merge-fdlimit.sh \ +diff --git a/tests/misc/cut.pl b/tests/misc/cut.pl +index f6f8a56..b426a80 100755 +--- a/tests/misc/cut.pl ++++ b/tests/misc/cut.pl +@@ -23,9 +23,11 @@ use strict; + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; - # See tests/factor/create-test.sh. +-my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++my $mb_locale; ++# uncommented enable multibyte paths ++$mb_locale = $ENV{LOCALE_FR_UTF8}; + ! defined $mb_locale || $mb_locale eq 'none' +- and $mb_locale = 'C'; ++ and $mb_locale = 'C'; + + my $prog = 'cut'; + my $try = "Try '$prog --help' for more information.\n"; +@@ -240,6 +242,7 @@ if ($mb_locale ne 'C') + my @new_t = @$t; + my $test_name = shift @new_t; + ++ next if ($test_name =~ "newline-[12][0-9]"); + push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; + } + push @Tests, @new; diff --git a/tests/misc/expand.pl b/tests/misc/expand.pl -index 4b07210..68b9ea1 100755 +index 8a9cad1..9293e39 100755 --- a/tests/misc/expand.pl +++ b/tests/misc/expand.pl @@ -27,6 +27,15 @@ my $prog = 'expand'; @@ -3748,8 +3212,8 @@ index 4b07210..68b9ea1 100755 my @Tests = ( ['t1', '--tabs=3', {IN=>"a\tb"}, {OUT=>"a b"}], -@@ -168,6 +177,8 @@ my @Tests = - +@@ -152,6 +161,8 @@ my @Tests = + ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a b c"}], # Test errors + # FIXME: The following tests contain ‘quoting’ specific to LC_MESSAGES @@ -3757,7 +3221,7 @@ index 4b07210..68b9ea1 100755 ['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1}, {ERR => "$prog: tab size contains invalid character(s): 'a'\n"}], ['e2', "-t $UINTMAX_OFLOW", {IN=>''}, {OUT=>''}, {EXIT=>1}, -@@ -184,6 +195,37 @@ my @Tests = +@@ -168,6 +179,37 @@ my @Tests = {ERR => "$prog: '/' specifier not at start of number: '/'\n"}], ); @@ -3795,6 +3259,149 @@ index 4b07210..68b9ea1 100755 my $save_temps = $ENV{DEBUG}; my $verbose = $ENV{VERBOSE}; +diff --git a/tests/misc/fold.pl b/tests/misc/fold.pl +index 7b192b4..76f073f 100755 +--- a/tests/misc/fold.pl ++++ b/tests/misc/fold.pl +@@ -20,9 +20,18 @@ use strict; + + (my $program_name = $0) =~ s|.*/||; + ++my $prog = 'fold'; ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++# uncommented to enable multibyte paths ++my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ + my @Tests = + ( + ['s1', '-w2 -s', {IN=>"a\t"}, {OUT=>"a\n\t"}], +@@ -31,9 +40,48 @@ my @Tests = + ['s4', '-w4 -s', {IN=>"abc ef\n"}, {OUT=>"abc \nef\n"}], + ); + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether fold is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ ++@Tests = triple_test \@Tests; ++ ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +-my $prog = 'fold'; + my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose); + exit $fail; +diff --git a/tests/misc/join.pl b/tests/misc/join.pl +index 4d399d8..07f2823 100755 +--- a/tests/misc/join.pl ++++ b/tests/misc/join.pl +@@ -25,6 +25,15 @@ my $limits = getlimits (); + + my $prog = 'join'; + ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; ++ ++my $mb_locale; ++#Comment out next line to disable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; ++ + my $delim = chr 0247; + sub t_subst ($) + { +@@ -329,8 +338,49 @@ foreach my $t (@tv) + push @Tests, $new_ent; + } + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; ++ ++ # Depending on whether join is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ #Adjust the output some error messages including test_name for mb ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR}} ++ (@new_t)) ++ { ++ my $sub2 = {ERR_SUBST => "s/$test_name-mb/$test_name/"}; ++ push @new_t, $sub2; ++ push @$t, $sub2; ++ } ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } ++ + @Tests = triple_test \@Tests; + ++#skip invalid-j-mb test, it is failing because of the format ++@Tests = grep {$_->[0] ne 'invalid-j-mb'} @Tests; ++ + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + diff --git a/tests/misc/sort-mb-tests.sh b/tests/misc/sort-mb-tests.sh new file mode 100644 index 0000000..11836ba @@ -3846,136 +3453,10 @@ index 0000000..11836ba +compare exp out || { fail=1; cat out; } + +Exit $fail -diff --git a/tests/misc/unexpand.pl b/tests/misc/unexpand.pl -index bb7469c..c1dec95 100755 ---- a/tests/misc/unexpand.pl -+++ b/tests/misc/unexpand.pl -@@ -27,6 +27,14 @@ my $limits = getlimits (); - - my $prog = 'unexpand'; - -+# comment out next line to disable multibyte tests -+my $mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; -+ -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - my @Tests = - ( - ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}], -@@ -132,6 +140,37 @@ my @Tests = - ['ts2', '-t5,8', {IN=>"x\t \t y\n"}, {OUT=>"x\t\t y\n"}], - ); - -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether unexpand is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ next if ($test_name =~ 'b-1'); -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ -+@Tests = triple_test \@Tests; -+ - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; - -diff --git a/tests/pr/pr-tests.pl b/tests/pr/pr-tests.pl -index 60e6106..3c64a08 100755 ---- a/tests/pr/pr-tests.pl -+++ b/tests/pr/pr-tests.pl -@@ -24,6 +24,15 @@ use strict; - my $prog = 'pr'; - my $normalize_strerror = "s/': .*/'/"; - -+my $mb_locale; -+#Uncomment the following line to enable multibyte tests -+$mb_locale = $ENV{LOCALE_FR_UTF8}; -+! defined $mb_locale || $mb_locale eq 'none' -+ and $mb_locale = 'C'; -+ -+my $try = "Try \`$prog --help' for more information.\n"; -+my $inval = "$prog: invalid byte, character or field list\n$try"; -+ - my @tv = ( - - # -b option is no longer an official option. But it's still working to -@@ -515,8 +524,48 @@ push @Tests, - {IN=>"x\tx\tx\tx\tx\nx\tx\tx\tx\tx\n"}, - {OUT=>"x\tx\tx\tx\tx\tx\tx\tx\tx\tx\n"} ]; - -+# Add _POSIX2_VERSION=199209 to the environment of each test -+# that uses an old-style option like +1. -+if ($mb_locale ne 'C') -+ { -+ # Duplicate each test vector, appending "-mb" to the test name and -+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we -+ # provide coverage for the distro-added multi-byte code paths. -+ my @new; -+ foreach my $t (@Tests) -+ { -+ my @new_t = @$t; -+ my $test_name = shift @new_t; -+ -+ # Depending on whether pr is multi-byte-patched, -+ # it emits different diagnostics: -+ # non-MB: invalid byte or field list -+ # MB: invalid byte, character or field list -+ # Adjust the expected error output accordingly. -+ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} -+ (@new_t)) -+ { -+ my $sub = {ERR_SUBST => 's/, character//'}; -+ push @new_t, $sub; -+ push @$t, $sub; -+ } -+ #temporarily skip some failing tests -+ next if ($test_name =~ "col-0" or $test_name =~ "col-inval" or $test_name =~ "asan1"); -+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; -+ } -+ push @Tests, @new; -+ } -+ - @Tests = triple_test \@Tests; - -+# Remember that triple_test creates from each test with exactly one "IN" -+# file two more tests (.p and .r suffix on name) corresponding to reading -+# input from a file and from a pipe. The pipe-reading test would fail -+# due to a race condition about 1 in 20 times. -+# Remove the IN_PIPE version of the "output-is-input" test above. -+# The others aren't susceptible because they have three inputs each. -+@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; -+ - my $save_temps = $ENV{DEBUG}; - my $verbose = $ENV{VERBOSE}; - -diff --git a/tests/sort/sort-merge.pl b/tests/sort/sort-merge.pl -index a3204d3..40942a5 100755 ---- a/tests/sort/sort-merge.pl -+++ b/tests/sort/sort-merge.pl +diff --git a/tests/misc/sort-merge.pl b/tests/misc/sort-merge.pl +index 23f6ed2..402a987 100755 +--- a/tests/misc/sort-merge.pl ++++ b/tests/misc/sort-merge.pl @@ -26,6 +26,15 @@ my $prog = 'sort'; # Turn off localization of executable's output. @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; @@ -4032,10 +3513,10 @@ index a3204d3..40942a5 100755 my $save_temps = $ENV{DEBUG}; my $verbose = $ENV{VERBOSE}; -diff --git a/tests/sort/sort.pl b/tests/sort/sort.pl -index 5fa9d52..a66952a 100755 ---- a/tests/sort/sort.pl -+++ b/tests/sort/sort.pl +diff --git a/tests/misc/sort.pl b/tests/misc/sort.pl +index c3e7f8e..6ecd3ff 100755 +--- a/tests/misc/sort.pl ++++ b/tests/misc/sort.pl @@ -24,10 +24,15 @@ my $prog = 'sort'; # Turn off localization of executable's output. @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; @@ -4053,7 +3534,7 @@ index 5fa9d52..a66952a 100755 # Since each test is run with a file name and with redirected stdin, # the name in the diagnostic is either the file name or "-". # Normalize each diagnostic to use '-'. -@@ -428,6 +433,38 @@ foreach my $t (@Tests) +@@ -423,6 +428,38 @@ foreach my $t (@Tests) } } @@ -4092,7 +3573,7 @@ index 5fa9d52..a66952a 100755 @Tests = triple_test \@Tests; # Remember that triple_test creates from each test with exactly one "IN" -@@ -437,6 +474,7 @@ foreach my $t (@Tests) +@@ -432,6 +469,7 @@ foreach my $t (@Tests) # Remove the IN_PIPE version of the "output-is-input" test above. # The others aren't susceptible because they have three inputs each. @Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; @@ -4100,184 +3581,208 @@ index 5fa9d52..a66952a 100755 my $save_temps = $ENV{DEBUG}; my $verbose = $ENV{VERBOSE}; -diff --git a/tests/unexpand/mb.sh b/tests/unexpand/mb.sh -new file mode 100644 -index 0000000..8a82d74 ---- /dev/null -+++ b/tests/unexpand/mb.sh -@@ -0,0 +1,172 @@ -+#!/bin/sh +diff --git a/tests/misc/unexpand.pl b/tests/misc/unexpand.pl +index 6ba6d40..de86723 100755 +--- a/tests/misc/unexpand.pl ++++ b/tests/misc/unexpand.pl +@@ -27,6 +27,14 @@ my $limits = getlimits (); + + my $prog = 'unexpand'; + ++# comment out next line to disable multibyte tests ++my $mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; + -+# Copyright (C) 2012-2015 Free Software Foundation, Inc. ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; + -+# This program is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. + my @Tests = + ( + ['a1', {IN=> ' 'x 1 ."y\n"}, {OUT=> ' 'x 1 ."y\n"}], +@@ -128,6 +136,37 @@ my @Tests = + ['ts2', '-t5,8', {IN=>"x\t \t y\n"}, {OUT=>"x\t\t y\n"}], + ); + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; + -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. ++ # Depending on whether unexpand is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ next if ($test_name =~ 'b-1'); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } + -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . ++@Tests = triple_test \@Tests; + -+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src -+print_ver_ unexpand + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + +diff --git a/tests/misc/uniq.pl b/tests/misc/uniq.pl +index f028036..8eaf59a 100755 +--- a/tests/misc/uniq.pl ++++ b/tests/misc/uniq.pl +@@ -23,9 +23,17 @@ my $limits = getlimits (); + my $prog = 'uniq'; + my $try = "Try '$prog --help' for more information.\n"; + ++my $inval = "$prog: invalid byte, character or field list\n$try"; + -+export LC_ALL=en_US.UTF-8 + # Turn off localization of executable's output. + @ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; + ++my $mb_locale; ++#Comment out next line to disable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; + -+#input containing multibyte characters -+cat > in <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF + # When possible, create a "-z"-testing variant of each test. + sub add_z_variants($) + { +@@ -262,6 +270,53 @@ foreach my $t (@Tests) + and push @$t, {ENV=>'_POSIX2_VERSION=199209'}; + } + ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; + -+cat > exp <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF ++ # Depending on whether uniq is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ # In test #145, replace the each ‘...’ by '...'. ++ if ($test_name =~ "145") ++ { ++ my $sub = { ERR_SUBST => "s/‘([^’]+)’/'\$1'/g"}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ next if ( $test_name =~ "schar" ++ or $test_name =~ "^obs-plus" ++ or $test_name =~ "119"); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } + -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. + ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; + -+#multiple files as an input -+cat >> exp <<\EOF -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF + @Tests = add_z_variants \@Tests; + @Tests = triple_test \@Tests; + +diff --git a/tests/pr/pr-tests.pl b/tests/pr/pr-tests.pl +index ec3980a..136657d 100755 +--- a/tests/pr/pr-tests.pl ++++ b/tests/pr/pr-tests.pl +@@ -24,6 +24,15 @@ use strict; + my $prog = 'pr'; + my $normalize_strerror = "s/': .*/'/"; + ++my $mb_locale; ++#Uncomment the following line to enable multibyte tests ++$mb_locale = $ENV{LOCALE_FR_UTF8}; ++! defined $mb_locale || $mb_locale eq 'none' ++ and $mb_locale = 'C'; + ++my $try = "Try \`$prog --help' for more information.\n"; ++my $inval = "$prog: invalid byte, character or field list\n$try"; + -+unexpand -a ./in ./in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 + my @tv = ( + + # -b option is no longer an official option. But it's still working to +@@ -474,8 +483,48 @@ push @Tests, + {IN=>{2=>"a\n"}}, + {OUT=>"a\t\t\t\t \t\t\ta\n"} ]; + ++# Add _POSIX2_VERSION=199209 to the environment of each test ++# that uses an old-style option like +1. ++if ($mb_locale ne 'C') ++ { ++ # Duplicate each test vector, appending "-mb" to the test name and ++ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we ++ # provide coverage for the distro-added multi-byte code paths. ++ my @new; ++ foreach my $t (@Tests) ++ { ++ my @new_t = @$t; ++ my $test_name = shift @new_t; + -+#test characters with a display width larger than 1 ++ # Depending on whether pr is multi-byte-patched, ++ # it emits different diagnostics: ++ # non-MB: invalid byte or field list ++ # MB: invalid byte, character or field list ++ # Adjust the expected error output accordingly. ++ if (grep {ref $_ eq 'HASH' && exists $_->{ERR} && $_->{ERR} eq $inval} ++ (@new_t)) ++ { ++ my $sub = {ERR_SUBST => 's/, character//'}; ++ push @new_t, $sub; ++ push @$t, $sub; ++ } ++ #temporarily skip some failing tests ++ next if ($test_name =~ "col-0" or $test_name =~ "col-inval" or $test_name =~ "asan1"); ++ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}]; ++ } ++ push @Tests, @new; ++ } + -+env printf '12345678 -+e |ascii(1) -+\u00E9 |composed(1) -+e\u0301 |decomposed(1) -+\u3000 |ideo-space(2) -+\uFF0D |full-hypen(2) -+' > in || framework_failure_ + @Tests = triple_test \@Tests; + ++# Remember that triple_test creates from each test with exactly one "IN" ++# file two more tests (.p and .r suffix on name) corresponding to reading ++# input from a file and from a pipe. The pipe-reading test would fail ++# due to a race condition about 1 in 20 times. ++# Remove the IN_PIPE version of the "output-is-input" test above. ++# The others aren't susceptible because they have three inputs each. ++@Tests = grep {$_->[0] ne 'output-is-input.p'} @Tests; + -+env printf '12345678 -+e\t|ascii(1) -+\u00E9\t|composed(1) -+e\u0301\t|decomposed(1) -+\u3000\t|ideo-space(2) -+\uFF0D\t|full-hypen(2) -+' > exp || framework_failure_ -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#test input where a blank of width > 1 is not being substituted -+in="$(LC_ALL=en_US.UTF-8 printf ' \u3000 ö ü ß')" -+exp='   ö ü ß' -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#non-Unicode characters interspersed between Unicode ones -+env printf '12345678 -+ \xFF| -+\xFF | -+ \xFFä| -+ä\xFF | -+ ä\xFF| -+\xFF ä| -+äbcdef\xFF | -+' > in || framework_failure_ -+ -+env printf '12345678 -+\t\xFF| -+\xFF\t| -+\t\xFFä| -+ä\xFF\t| -+\tä\xFF| -+\xFF\tä| -+äbcdef\xFF\t| -+' > exp || framework_failure_ -+ -+unexpand -a < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+#BOM header test 1 -+printf "\xEF\xBB\xBF" > in; cat <<\EOF >> in || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+env printf ' äöü\t. öüä. \tä xx\n' >> in || framework_failure_ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C unexpand < in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+ -+printf "\xEF\xBB\xBF" > exp; cat <<\EOF >> exp || framework_failure_ -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+1234567812345678123456781 -+. . . . -+a b c d -+. . . . -+ä ö ü ß -+. . . . -+ äöü . öüä. ä xx -+EOF -+ -+ -+unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LANG=C unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 -+ -+LC_ALL=C unexpand in in > out || fail=1 -+compare exp out > /dev/null 2>&1 || fail=1 + my $save_temps = $ENV{DEBUG}; + my $verbose = $ENV{VERBOSE}; + -- -2.52.0 +2.7.4 diff --git a/coreutils-keyring.gpg b/coreutils-keyring.gpg deleted file mode 100644 index 003a885..0000000 --- a/coreutils-keyring.gpg +++ /dev/null @@ -1,312 +0,0 @@ -Release GPG keyring of coreutils group. - ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -ELphkzjc6eM3CaOZ73u4GVXotheeUabUHQ== -=drvb ------END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/coreutils-overflow.patch b/coreutils-overflow.patch new file mode 100644 index 0000000..d62b19a --- /dev/null +++ b/coreutils-overflow.patch @@ -0,0 +1,13 @@ +diff --git a/src/who.c b/src/who.c +index 55733b4..3ad4774 100644 +--- a/src/who.c ++++ b/src/who.c +@@ -81,7 +81,7 @@ + # define UT_TYPE_NEW_TIME(U) false + #endif + +-#define IDLESTR_LEN 6 ++#define IDLESTR_LEN 10 + + #if HAVE_STRUCT_XTMP_UT_PID + # define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \ diff --git a/coreutils-python3.patch b/coreutils-python3.patch deleted file mode 100644 index 447fdbc..0000000 --- a/coreutils-python3.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 8927d505ecb5334f09c48ef98ef1f464f581d0f7 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Tue, 2 Apr 2024 14:11:26 +0100 -Subject: [PATCH] coreutils-python3.patch - ---- - init.cfg | 4 ++-- - tests/d_type-check | 2 +- - tests/du/move-dir-while-traversing.sh | 6 +++--- - 3 files changed, 6 insertions(+), 6 deletions(-) - -diff --git a/init.cfg b/init.cfg -index ac05f7b..26d9516 100644 ---- a/init.cfg -+++ b/init.cfg -@@ -601,10 +601,10 @@ seek_data_capable_() - # Skip the current test if "." lacks d_type support. - require_dirent_d_type_() - { -- python < /dev/null \ -+ python3 < /dev/null \ - || skip_ python missing: assuming no d_type support - -- python "$abs_srcdir"/tests/d_type-check \ -+ python3 "$abs_srcdir"/tests/d_type-check \ - || skip_ requires d_type support - } - -diff --git a/tests/d_type-check b/tests/d_type-check -index 1a2f76f..42d3924 100644 ---- a/tests/d_type-check -+++ b/tests/d_type-check -@@ -1,4 +1,4 @@ --#!/usr/bin/python -+#!/usr/bin/python3 - # Exit 0 if "." and "./tempfile" have useful d_type information, else 1. - # Intended to exit 0 only on Linux/GNU systems. - import os -diff --git a/tests/du/move-dir-while-traversing.sh b/tests/du/move-dir-while-traversing.sh -index adf482b..cf9214a 100755 ---- a/tests/du/move-dir-while-traversing.sh -+++ b/tests/du/move-dir-while-traversing.sh -@@ -21,8 +21,8 @@ print_ver_ du - require_trap_signame_ - - # We use a python-inotify script, so... --python -m pyinotify -h > /dev/null \ -- || skip_ 'python inotify package not installed' -+python3 -m pyinotify -h > /dev/null \ -+ || skip_ 'python3 inotify package not installed' - - # Move a directory "up" while du is processing its sub-directories. - # While du is processing a hierarchy .../B/C/D/... this script -@@ -33,7 +33,7 @@ python -m pyinotify -h > /dev/null \ - # rename syscall before du finishes processing the subtree under D/. - - cat <<'EOF' > inotify-watch-for-dir-access.py --#!/usr/bin/env python -+#!/usr/bin/env python3 - import pyinotify as pn - import os,sys - --- -2.51.0 - diff --git a/coreutils-selinux.patch b/coreutils-selinux.patch new file mode 100644 index 0000000..8274a23 --- /dev/null +++ b/coreutils-selinux.patch @@ -0,0 +1,120 @@ +diff --git a/man/chcon.x b/man/chcon.x +index 8c1ff6f..c84fb96 100644 +--- a/man/chcon.x ++++ b/man/chcon.x +@@ -1,4 +1,4 @@ + [NAME] +-chcon \- change file security context ++chcon \- change file SELinux security context + [DESCRIPTION] + .\" Add any additional description here +diff --git a/man/runcon.x b/man/runcon.x +index d2df13e..5c5f5d8 100644 +--- a/man/runcon.x ++++ b/man/runcon.x +@@ -1,5 +1,5 @@ + [NAME] +-runcon \- run command with specified security context ++runcon \- run command with specified SELinux security context + [DESCRIPTION] + Run COMMAND with completely-specified CONTEXT, or with current or + transitioned security context modified by one or more of LEVEL, +diff --git a/src/cp.c b/src/cp.c +index 1b528c6..25dbb88 100644 +--- a/src/cp.c ++++ b/src/cp.c +@@ -203,6 +203,9 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\ + all\n\ + "), stdout); + fputs (_("\ ++ -c deprecated, same as --preserve=context\n\ ++"), stdout); ++ fputs (_("\ + --no-preserve=ATTR_LIST don't preserve the specified attributes\n\ + --parents use full source file name under DIRECTORY\n\ + "), stdout); +@@ -929,7 +932,7 @@ main (int argc, char **argv) + selinux_enabled = (0 < is_selinux_enabled ()); + cp_option_init (&x); + +- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ", ++ while ((c = getopt_long (argc, argv, "abcdfHilLnprst:uvxPRS:TZ", + long_opts, NULL)) + != -1) + { +@@ -977,6 +980,17 @@ main (int argc, char **argv) + copy_contents = true; + break; + ++ case 'c': ++ fprintf (stderr, "%s: warning: option '-c' is deprecated, please use '--preserve=context' instead\n", argv[0]); ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } ++ else if (selinux_enabled) { ++ x.preserve_security_context = true; ++ x.require_preserve_context = true; ++ } ++ break; + case 'd': + x.preserve_links = true; + x.dereference = DEREF_NEVER; +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 47e4480..cff2ead 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -8083,6 +8083,11 @@ done + exit $fail + @end example + ++@item -c ++@cindex SELinux security context information, preserving ++Preserve SELinux security context of the original files if possible. ++Some file systems don't support storing of SELinux security context. ++ + @item --copy-contents + @cindex directories, copying recursively + @cindex copying directories recursively +diff --git a/src/install.c b/src/install.c +index d79d597..437889a 100644 +--- a/src/install.c ++++ b/src/install.c +@@ -673,7 +673,7 @@ In the 4th form, create all components of the given DIRECTORY(ies).\n\ + -v, --verbose print the name of each directory as it is created\n\ + "), stdout); + fputs (_("\ +- --preserve-context preserve SELinux security context\n\ ++ -P, --preserve-context preserve SELinux security context (-P deprecated)\n\ + -Z set SELinux security context of destination\n\ + file and each created directory to default type\n\ + --context[=CTX] like -Z, or if CTX is specified then set the\n\ +@@ -824,7 +824,7 @@ main (int argc, char **argv) + dir_arg = false; + umask (0); + +- while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options, ++ while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pPt:TvS:Z", long_options, + NULL)) != -1) + { + switch (optc) +@@ -885,6 +885,8 @@ main (int argc, char **argv) + no_target_directory = true; + break; + ++ case 'P': ++ fprintf (stderr, "%s: warning: option '-P' is deprecated, please use '--preserve-context' instead\n", argv[0]); + case PRESERVE_CONTEXT_OPTION: + if (! selinux_enabled) + { +@@ -892,6 +894,10 @@ main (int argc, char **argv) + "this kernel is not SELinux-enabled")); + break; + } ++ if ( x.set_security_context ) { ++ (void) fprintf(stderr, "%s: cannot force target context and preserve it\n", argv[0]); ++ exit( 1 ); ++ } + x.preserve_security_context = true; + use_default_selinux_context = false; + break; diff --git a/coreutils.spec b/coreutils.spec index 6712263..3a9945d 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,102 +1,153 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils -Version: 9.9 -Release: 2%{?dist} -# some used parts of gnulib are under various variants of LGPL -License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later +Version: 8.27 +Release: 7%{?dist} +License: GPLv3+ +Group: System Environment/Base Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz -Source1: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz.sig -# From https://savannah.gnu.org/project/release-gpgkeys.php?group=coreutils&download=1 -# which is linked as project keyring on https://savannah.gnu.org/projects/coreutils -Source2: coreutils-keyring.gpg Source50: supported_utils Source105: coreutils-colorls.sh Source106: coreutils-colorls.csh -# do not make coreutils-single depend on /usr/bin/coreutils -%global __requires_exclude ^%{_bindir}/coreutils$ +# Provide our own custom requires for coreutils-single package +Source10: coreutils-find-requires.sh +%global _use_internal_dependency_generator 0 +%global __find_provides %{_rpmconfigdir}/find-provides +%global __find_requires %{SOURCE10} %{_rpmconfigdir}/find-requires + +# upstream patches +Patch1: coreutils-8.27-date-debug-test.patch + +# date, touch: fix out-of-bounds write via large TZ variable (CVE-2017-7476) +Patch2: coreutils-8.27-CVE-2017-7476.patch + +# tail: revert to polling if a followed directory is replaced (#1283760) +Patch3: coreutils-8.27-tail-inotify-recreate.patch + +# doc: mention `setpriv --no-new-privs` feature in runcon info (#1360903) +Patch4: coreutils-8.27-runcon-doc.patch + +# ptx: fix a possible crash caused by integer overflow (#1482445) +Patch5: coreutils-8.27-ptx-int-overflow.patch + +# df: do not call stat() on file system unless it is necessary (#1511951) +Patch6: coreutils-8.27-df-stat.patch # disable the test-lock gnulib test prone to deadlock Patch100: coreutils-8.26-test-lock.patch -# require_selinux_(): use selinuxenabled(8) if available -Patch101: coreutils-8.26-selinuxenable.patch - +#add note about no difference between binary/text mode on Linux - md5sum manpage +Patch101: coreutils-6.10-manpages.patch # downstream changes to default DIR_COLORS -Patch102: coreutils-8.32-DIR_COLORS.patch - -# use python3 in tests -Patch103: coreutils-python3.patch - -# df --direct +Patch102: coreutils-8.25-DIR_COLORS.patch +#do display processor type for uname -p/-i based on uname(2) syscall +Patch103: coreutils-8.2-uname-processortype.patch +#df --direct Patch104: coreutils-df-direct.patch +#add note about mkdir --mode behaviour into info documentation(#610559) +Patch107: coreutils-8.4-mkdir-modenote.patch -# gnulib C23 support -# https://github.com/coreutils/gnulib/commit/df17f4f37ed3ca373d23ad42eae51122bdb96626 -Patch105: coreutils-9.9-gnulib-c23.patch - -# fix cut test failure on aarch64 rawhide (rhbz#2424302) -# https://github.com/coreutils/coreutils/commit/95044cb5eaea83d02f768feb5ab79fcf5e6ad782 -Patch106: coreutils-9.9-fix-cut-test-aarch64.patch +# sh-utils +#add info about TZ envvar to date manpage +Patch703: sh-utils-2.0.11-dateman.patch +Patch713: coreutils-4.5.3-langinfo.patch # (sb) lin18nux/lsb compliance - multibyte functionality patch Patch800: coreutils-i18n.patch +# (sb) lin18nux/lsb compliance - expand/unexpand +Patch801: coreutils-i18n-expand-unexpand.patch +# i18n patch for cut - old version - used +Patch804: coreutils-i18n-cut-old.patch +# The unexpand patch above is not correct. Sent to the patch authors +Patch803: coreutils-i18n-fix-unexpand.patch +#(un)expand - allow multiple files on input - broken by patch 801 +Patch805: coreutils-i18n-fix2-expand-unexpand.patch +#(un)expand - test BOM headers +Patch806: coreutils-i18n-un-expand-BOM.patch +# make 'sort -h' work for arbitrary column even when using UTF-8 locales +Patch807: coreutils-i18n-sort-human.patch +# fold: preserve new-lines in mutlibyte text (#1418505) +Patch808: coreutils-i18n-fold-newline.patch + +#getgrouplist() patch from Ulrich Drepper. +Patch908: coreutils-getgrouplist.patch +#Prevent buffer overflow in who(1) (bug #158405). +Patch912: coreutils-overflow.patch + +#SELINUX Patch - implements Redhat changes +#(upstream did some SELinux implementation unlike with RedHat patch) +Patch950: coreutils-selinux.patch Conflicts: filesystem < 3 - # To avoid clobbering installs Conflicts: coreutils-single +Provides: /bin/basename +Provides: /bin/cat +Provides: /bin/chgrp +Provides: /bin/chmod +Provides: /bin/chown +Provides: /bin/cp +Provides: /bin/cut +Provides: /bin/date +Provides: /bin/dd +Provides: /bin/df +Provides: /bin/echo +Provides: /bin/env +Provides: /bin/false +Provides: /bin/ln +Provides: /bin/ls +Provides: /bin/mkdir +Provides: /bin/mknod +Provides: /bin/mktemp +Provides: /bin/mv +Provides: /bin/nice +Provides: /bin/pwd +Provides: /bin/readlink +Provides: /bin/rm +Provides: /bin/rmdir +Provides: /bin/sleep +Provides: /bin/sort +Provides: /bin/stty +Provides: /bin/sync +Provides: /bin/touch +Provides: /bin/true +Provides: /bin/uname BuildRequires: attr BuildRequires: autoconf BuildRequires: automake -BuildRequires: gcc +BuildRequires: bison BuildRequires: gettext-devel BuildRequires: gmp-devel -BuildRequires: hostname BuildRequires: libacl-devel BuildRequires: libattr-devel BuildRequires: libcap-devel BuildRequires: libselinux-devel -BuildRequires: libselinux-utils -BuildRequires: make BuildRequires: openssl-devel BuildRequires: strace -BuildRequires: systemd-devel BuildRequires: texinfo -# For gpg verification of source tarball -BuildRequires: gnupg2 - -# test-only dependencies -BuildRequires: acl -BuildRequires: gdb -BuildRequires: perl-interpreter -BuildRequires: perl(FileHandle) -BuildRequires: python3 -BuildRequires: tzdata -%ifarch %valgrind_arches -BuildRequires: valgrind -%endif - -%if 0%{?fedora} -BuildRequires: perl(Expect) -BuildRequires: python3-inotify -%endif - %if 23 < 0%{?fedora} || 7 < 0%{?rhel} # needed by i18n test-cases BuildRequires: glibc-langpack-en -BuildRequires: glibc-langpack-fr -BuildRequires: glibc-langpack-ko -BuildRequires: glibc-langpack-sv %endif Requires: %{name}-common = %{version}-%{release} +Requires: ncurses -Provides: coreutils-full = %{version}-%{release} +Provides: fileutils = %{version}-%{release} +Provides: sh-utils = %{version}-%{release} +Provides: stat = %{version}-%{release} +Provides: textutils = %{version}-%{release} +#old mktemp package had epoch 3, so we have to use 4 for coreutils +Provides: mktemp = 4:%{version}-%{release} Provides: bundled(gnulib) +Obsoletes: mktemp < 4:%{version}-%{release} +Obsoletes: fileutils <= 4.1.9 +Obsoletes: sh-utils <= 2.0.12 +Obsoletes: stat <= 3.3 +Obsoletes: textutils <= 2.0.21 Obsoletes: %{name} < 8.24-100 %description @@ -107,8 +158,6 @@ the old GNU fileutils, sh-utils, and textutils packages. Summary: coreutils multicall binary Suggests: coreutils-common Provides: coreutils = %{version}-%{release} -Provides: coreutils%{?_isa} = %{version}-%{release} -Provides: bundled(gnulib) # To avoid clobbering installs Conflicts: coreutils < 8.24-100 # Note RPM doesn't support separate buildroots for %files @@ -124,35 +173,19 @@ packaged as a single multicall binary. # yum obsoleting rules explained at: # https://bugzilla.redhat.com/show_bug.cgi?id=1107973#c7 Obsoletes: %{name} < 8.24-100 - -# Gnulib translations are maintained seprately since coreutils 9.6 (#2393892) -Requires: gnulib-l10n - -# info doc refers to "Specifying the Time Zone" from glibc-doc (#959597) -Suggests: glibc-doc - +Requires(preun): /sbin/install-info +Requires(post): /sbin/install-info Summary: coreutils common optional components %description common Optional though recommended components, including documentation and translations. %prep -%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %autosetup -N -# will be regenerated in the build directories -rm -f src/fs.h - -# will be further modified by coreutils-8.32-DIR_COLORS.patch -sed src/dircolors.hin \ - -e 's| 00;36$| 01;36|' \ - > DIR_COLORS -sed src/dircolors.hin \ - -e 's| 01;31$| 00;31|' \ - -e 's| 01;35$| 00;35|' \ - > DIR_COLORS.lightbgcolor - -# git add DIR_COLORS{,.lightbgcolor} +# will be modified by coreutils-8.25-DIR_COLORS.patch +tee DIR_COLORS{,.256color,.lightbgcolor} /dev/null +# git add DIR_COLORS{,.256color,.lightbgcolor} # git commit -m "clone DIR_COLORS before patching" # apply all patches @@ -162,36 +195,23 @@ sed src/dircolors.hin \ find tests -name '*.sh' -perm 0644 -print -exec chmod 0755 '{}' '+' (echo "<<< done") 2>/dev/null -# FIXME: Force a newer gettext version to workaround `autoreconf -i` errors -# with coreutils 9.6 and bundled gettext 0.19.2 from gettext-common-devel. -sed -i "s/0.19.2/$(rpm -q --queryformat '%%{VERSION}\n' gettext-devel)/" bootstrap.conf configure.ac +#fix typos/mistakes in localized documentation(#439410, #440056) +find ./po/ -name "*.p*" | xargs \ + sed -i \ + -e 's/-dpR/-cdpR/' autoreconf -fiv %build export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing -fpic" - -# Upstream suggests to build with -Dlint for static analyzers: -# https://lists.gnu.org/archive/html/coreutils/2018-06/msg00110.html -# ... and even for production binary RPMs: -# https://lists.gnu.org/archive/html/bug-gnulib/2020-05/msg00130.html -# There is currently no measurable performance drop or other known downside. -CFLAGS="$CFLAGS -Dlint" - -# make mknod work again in chroot without /proc being mounted (#1811038) -export ac_cv_func_lchmod="no" - -# needed for out-of-tree build -%global _configure ../configure - %{expand:%%global optflags %{optflags} -D_GNU_SOURCE=1} for type in separate single; do - mkdir -p $type && \ - (cd $type || exit $? + mkdir $type && \ + (cd $type && ln -s ../configure || exit 1 if test $type = 'single'; then config_single='--enable-single-binary' config_single="$config_single --without-openssl" # smaller/slower sha*sum - config_single="$config_single --without-libgmp" # expr/factor machine ints + config_single="$config_single --without-gmp" # expr/factor machine ints else config_single='--with-openssl' # faster sha*sum fi @@ -199,14 +219,9 @@ for type in separate single; do --cache-file=../config.cache \ --enable-install-program=arch \ --enable-no-install-program=kill,uptime \ - --enable-systemd \ --with-tty-group \ DEFAULT_POSIX2_VERSION=200112 alternative=199209 || : - %make_build all V=1 - - # make sure that parse-datetime.{c,y} ends up in debuginfo (#1555079) - ln -fv ../lib/parse-datetime.{c,y} . - ) + make all %{?_smp_mflags}) done # Get the list of supported utilities @@ -226,20 +241,14 @@ for type in separate single; do fi (cd $type && make DESTDIR=$RPM_BUILD_ROOT/$subdir $install) -%if "%{_sbindir}" != "%{_bindir}" # chroot was in /usr/sbin : - mkdir -p $RPM_BUILD_ROOT/$subdir/%_sbindir + mkdir -p $RPM_BUILD_ROOT/$subdir/{%{_bindir},%{_sbindir}} mv $RPM_BUILD_ROOT/$subdir/{%_bindir,%_sbindir}/chroot -%endif # Move multicall variants to *.single. # RemovePathPostfixes will strip that later. if test $type = 'single'; then - for dir in %{_bindir} \ -%if "%{_sbindir}" != "%{_bindir}" -%{_sbindir} \ -%endif -%{_libexecdir}/%{name}; do + for dir in %{_bindir} %{_sbindir} %{_libexecdir}/%{name}; do for bin in $RPM_BUILD_ROOT/%{_libexecdir}/%{name}/$dir/*; do basebin=$(basename $bin) mv $bin $RPM_BUILD_ROOT/$dir/$basebin.single @@ -249,34 +258,55 @@ for type in separate single; do done mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/profile.d -install -p -c -m644 DIR_COLORS{,.lightbgcolor} $RPM_BUILD_ROOT%{_sysconfdir} +install -p -c -m644 DIR_COLORS{,.256color,.lightbgcolor} \ + $RPM_BUILD_ROOT%{_sysconfdir} install -p -c -m644 %SOURCE105 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.sh install -p -c -m644 %SOURCE106 $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/colorls.csh +# Use hard links instead of symbolic links for LC_TIME files (bug #246729). +find %{buildroot}%{_datadir}/locale -type l | \ +(while read link + do + target=$(readlink "$link") + rm -f "$link" + ln "$(dirname "$link")/$target" "$link" + done) + %find_lang %name -# Add the %%lang(xyz) ownership for the LC_TIME dirs as well... +#Add the %lang(xyz) ownership for the LC_TIME dirs as well... grep LC_TIME %name.lang | cut -d'/' -f1-6 | sed -e 's/) /) %%dir /g' >>%name.lang # (sb) Deal with Installed (but unpackaged) file(s) found rm -f $RPM_BUILD_ROOT%{_infodir}/dir +%preun common +if [ $1 = 0 ]; then + if [ -f %{_infodir}/%{name}.info.gz ]; then + /sbin/install-info --delete %{_infodir}/%{name}.info.gz %{_infodir}/dir || : + fi +fi + +%post common +if [ -f %{_infodir}/%{name}.info.gz ]; then + /sbin/install-info %{_infodir}/%{name}.info.gz %{_infodir}/dir || : +fi + %files -f supported_utils +%defattr(-,root,root,-) %exclude %{_bindir}/*.single -%dir %{_libexecdir}/coreutils %{_libexecdir}/coreutils/*.so %files single +%defattr(-,root,root,-) %{_bindir}/*.single -%if "%{_sbindir}" != "%{_bindir}" %{_sbindir}/chroot.single -%endif -%dir %{_libexecdir}/coreutils %{_libexecdir}/coreutils/*.so.single # duplicate the license because coreutils-common does not need to be installed %{!?_licensedir:%global license %%doc} %license COPYING %files common -f %{name}.lang +%defattr(-,root,root,-) %config(noreplace) %{_sysconfdir}/DIR_COLORS* %config(noreplace) %{_sysconfdir}/profile.d/* %{_infodir}/coreutils* @@ -286,407 +316,12 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog -* Tue Jan 13 2026 Lukáš Zaoral - 9.9-2 -- fix cut test failure on aarch64 rawhide (rhbz#2424302) +* Fri Nov 10 2017 Kamil Dudka - 8.27-7 +- df: do not call stat() on file system unless it is necessary (#1511951) -* Wed Nov 26 2025 Lukáš Zaoral - 9.9-1 -- rebase to latest upstream release (rhbz#2413803) - -* Mon Sep 29 2025 Lukáš Zaoral - 9.8-3 -- require gnulib-l10n for translations of gnulib messages (rhbz#2393892) - -* Thu Sep 25 2025 Lukáš Zaoral - 9.8-2 -- tail: fix tailing larger number of lines in regular files (rhbz#2398008) - -* Wed Sep 24 2025 Lukáš Zaoral - 9.8-1 -- rebase to latest upstream release (rhbz#2397467) -- remove downstream patch for selinux options deprecated since 2009 - -* Wed Jul 23 2025 Fedora Release Engineering - 9.7-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Mon Jun 30 2025 Lukáš Zaoral - 9.7-4 -- stty: add support for arbitrary baud rates (rhbz#2375439) - -* Wed May 28 2025 Lukáš Zaoral - 9.7-3 -- sort: fix buffer under-read (CVE-2025-5278) - -* Mon May 19 2025 Lukáš Zaoral - 9.7-2 -- cp/mv: do not fail when copying of trivial NFSv4 ACLs fails (rhbz#2363149) - -* Wed Apr 09 2025 Lukáš Zaoral - 9.7-1 -- rebase to latest upstream release (rhbz#2358624) - -* Tue Feb 25 2025 Lukáš Zaoral - 9.6-2 -- fix 'who -m' with guessed tty names (rhbz#2343998) - -* Mon Jan 20 2025 Lukáš Zaoral - 9.6-1 -- rebase to latest upstream version (rhbz#2338620) -- sync i18n patch with SUSE (Kudos to Berny Völker!) - -* Thu Jan 16 2025 Fedora Release Engineering - 9.5-13 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Sun Jan 12 2025 Zbigniew Jędrzejewski-Szmek - 9.5-12 -- Rebuilt for the bin-sbin merge (2nd attempt) - -* Wed Nov 13 2024 Florian Weimer - 9.5-11 -- Affinity mask handling in nproc for large CPU counts (rhbz#2325167) - -* Fri Sep 27 2024 Lukáš Zaoral - 9.5-10 -- fix fold -b with UTF8 locale (RHEL-60295) - -* Tue Aug 27 2024 Lukáš Zaoral - 9.5-9 -- show web sessions in who output (rhbz#2307847) - -* Wed Aug 21 2024 Lukáš Zaoral - 9.5-8 -- add missing systemd-devel buildrequires - -* Wed Jul 17 2024 Fedora Release Engineering - 9.5-7 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Mon Jul 15 2024 Lukáš Zaoral - 9.5-6 -- Rebuilt for the bin-sbin merge - -* Mon Jul 15 2024 Sohum Mendon - 9.5-5 -- fix incorrect exit status when fold is called with a non-existent file - -* Tue Jul 09 2024 Zbigniew Jędrzejewski-Szmek - 9.5-4 -- Rebuilt for the bin-sbin merge - -* Thu Jul 04 2024 Lukáš Zaoral - 9.5-3 -- do not buildrequire perl(Expect) on ELN - -* Tue Jun 04 2024 Lukáš Zaoral - 9.5-2 -- enable LTO on ppc64le - -* Tue Apr 02 2024 Lukáš Zaoral - 9.5-1 -- rebase to latest upstream version (rhbz#2272063) -- sync i18n patch with SUSE (Kudos to Berny Völker!) -- add some test dependencies to execute additional part of the upstream test-suite - -* Mon Jan 29 2024 Lukáš Zaoral - 9.4-6 -- fix tail on kernels with 64k page sizes (RHEL-22866) - -* Wed Jan 24 2024 Fedora Release Engineering - 9.4-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Fri Jan 19 2024 Fedora Release Engineering - 9.4-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Thu Jan 18 2024 Lukáš Zaoral - 9.4-3 -- fix compilation on i686 - -* Thu Jan 18 2024 Lukáš Zaoral - 9.4-2 -- fix buffer overflow in split (CVE-2024-0684) - -* Fri Sep 15 2023 Lukáš Zaoral - 9.4-1 -- new upstream release 9.4 (#2235759) -- enable integration with systemd -- fix the license field - -* Wed Jul 19 2023 Fedora Release Engineering - 9.3-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Tue Apr 18 2023 Kamil Dudka - 9.3-1 -- remove obsolete Provides for absolute paths -- new upstream release 9.3 - -* Tue Apr 11 2023 Lukáš Zaoral - 9.2-4 -- migrate to SPDX license format - -* Fri Mar 24 2023 Kamil Dudka - 9.2-3 -- copy: fix --reflink=auto to fallback in more cases (#2180056) -- cksum: fix reporting of failed checks (#2180056) - -* Wed Mar 22 2023 Kamil Dudka - 9.2-2 -- coreutils-getgrouplist.patch: drop a patch no longer needed - -* Wed Mar 22 2023 Kamil Dudka - 9.2-1 -- new upstream release 9.2 - -* Thu Jan 19 2023 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Mon Jan 02 2023 Kamil Dudka - 9.1-10 -- drop obsolete downstream-only extension of date(1) man page -- undocument downstream SELinux options deprecated since 2009 - -* Mon Jan 02 2023 Kamil Dudka - 9.1-9 -- basic support for checking NFSv4 ACLs (#2137866) - -* Mon Sep 19 2022 Kamil Dudka - 9.1-8 -- remove obsolete extension of mkdir(1) info documentation - -* Tue Aug 23 2022 Kamil Dudka - 9.1-7 -- remove non-upstream patch for uname -i/-p (#548834) - -* Mon Aug 08 2022 Kamil Dudka - 9.1-6 -- improve wording of a comment in /etc/DIR_COLORS (#2112593) - -* Mon Aug 08 2022 Kamil Dudka - 9.1-5 -- improve handling of control characters in unexpand (#2112870) - -* Mon Aug 01 2022 Kamil Dudka - 9.1-4 -- prevent unexpand from failing on control characters (#2112870) - -* Wed Jul 20 2022 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Sat Apr 23 2022 Pádraig Brady - 9.1-2 -- make simple backups in correct dir; broken in 9.1 - -* Tue Apr 19 2022 Kamil Dudka - 9.1-1 -- new upstream release 9.1 - -* Mon Mar 21 2022 Kamil Dudka - 9.0-5 -- ls, stat: avoid triggering automounts (#2044981) - -* Tue Mar 01 2022 Kamil Dudka - 9.0-4 -- make `df --direct` work again (#2058686) - -* Wed Jan 19 2022 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Mon Oct 04 2021 Kamil Dudka - 9.0-2 -- chmod: fix exit status when ignoring symlinks - -* Sun Sep 26 2021 Kamil Dudka - 9.0-1 -- new upstream release 9.0 - -* Tue Sep 14 2021 Sahana Prasad -- Rebuilt with OpenSSL 3.0.0 - -* Wed Jul 21 2021 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Wed Jul 07 2021 Kamil Dudka - 8.32-30 -- df: fix duplicated remote entries due to bind mounts (#1979814) - -* Thu Jul 01 2021 Kamil Dudka - 8.32-28 -- tail: fix stack out-of-bounds write with --follow - -* Tue Jun 08 2021 Kamil Dudka - 8.32-27 -- mountlist: recognize fuse.portal as dummy file system (#1913358) - -* Mon May 17 2021 Kamil Dudka - 8.32-26 -- cp: pick additional copy_file_range()-related fixes from upstream - -* Mon May 03 2021 Kamil Dudka - 8.32-24 -- copy: ensure we enforce --reflink=never (#1956080) - -* Tue Apr 27 2021 Kamil Dudka - 8.32-23 -- copy: do not refuse to copy a swap file - -* Fri Apr 09 2021 Kamil Dudka - 8.32-22 -- weaken the dependency on glibc-doc to reduce minimal installations -- drop the last use of ncurses no longer needed (#1830318) -- utimens: fix confusing arg type in internal func - -* Fri Mar 26 2021 Kamil Dudka - 8.32-21 -- hostname,ln: fix memory leaks detected by Coverity - -* Wed Mar 24 2021 Kamil Dudka - 8.32-20 -- cp: use copy_file_range if available - -* Thu Feb 18 2021 Kamil Dudka - 8.32-19 -- stat: add support for the exfat file system (#1921427) - -* Wed Feb 03 2021 Kamil Dudka - 8.32-18 -- make coreutils-common recommend glibc-doc for info doc refs (#959597) - -* Tue Feb 02 2021 Kamil Dudka - 8.32-17 -- ls: fix crash printing SELinux context for unstatable files (#1921249) -- split: fix --number=K/N to output correct part of file (#1921246) -- expr: fix invalid read with unmatched \(...\) (#1919775) - -* Tue Jan 26 2021 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild - -* Tue Dec 08 2020 Kamil Dudka - 8.32-15 -- rm: do not skip files upon failure to remove an empty dir (#1905481) - -* Tue Nov 03 2020 Kamil Dudka - 8.32-14 -- df,stat,tail: recognize more file system types - -* Wed Oct 14 2020 Kamil Dudka - 8.32-13 -- make the %%build section idempotent - -* Mon Aug 17 2020 Kamil Dudka - 8.32-12 -- do not install /etc/DIR_COLORS.256color (#1830318) - -* Thu Jul 30 2020 Kamil Dudka - 8.32-11 -- cp: default to --reflink=auto (#1861108) - -* Mon Jul 27 2020 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Fri Jul 24 2020 Kamil Dudka - 8.32-9 -- disable -flto on ppc64le to make test-float pass (#1789115) - -* Mon Jul 13 2020 Tom Stellard - 8.32-8 -- Use make macros -- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro - -* Fri Jun 26 2020 James Cassell - 8.32-7 -- move ncurses to -common package since it's needed for colorls.sh -- make ncurses optional - -* Fri May 15 2020 Kamil Dudka - 8.32-6 -- compile with -Dlint to enable optional initialization and cleanup code - -* Thu Apr 23 2020 Kamil Dudka - 8.32-5 -- du: simplify leaf optimization for XFS (#1823247) - -* Fri Apr 17 2020 Tom Stellard - 8.32-4 -- Fix missing inline function definition - -* Wed Mar 11 2020 Kamil Dudka - 8.32-3 -- uniq: remove collation handling as required by newer POSIX - -* Mon Mar 09 2020 Kamil Dudka - 8.32-2 -- make mknod work again in chroot without /proc being mounted (#1811038) -- ls: restore 8.31 behavior on removed directories - -* Thu Mar 05 2020 Kamil Dudka - 8.32-1 -- new upstream release 8.32 - -* Tue Feb 11 2020 Kamil Dudka - 8.31-10 -- make upstream test-suite work with root privileges (#1800597) - -* Wed Feb 05 2020 Kamil Dudka - 8.31-9 -- use upstream fix the cp/proc-short-read test - -* Thu Jan 30 2020 Kamil Dudka - 8.31-8 -- skip a test that relies on /proc/kallsyms having immutable content - -* Tue Jan 28 2020 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Thu Oct 17 2019 Kamil Dudka - 8.31-6 -- temporarily disable the use of statx (#1760300) - -* Fri Oct 11 2019 Kamil Dudka - 8.31-5 -- use statx instead of stat when available (#1760300) - -* Wed Jul 24 2019 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - -* Tue Jul 16 2019 Kamil Dudka - 8.31-3 -- disable flashing in ls colors for broken symbolic links (#1728986) - -* Mon Mar 18 2019 Kamil Dudka - 8.31-2 -- fix formatting of sha512sum(1) man page (#1688740) - -* Mon Mar 11 2019 Kamil Dudka - 8.31-1 -- new upstream release 8.31 - -* Thu Jan 31 2019 Fedora Release Engineering -- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild - -* Wed Nov 07 2018 Kamil Dudka - 8.30-8 -- sync: fix open() fallback bug -- fix implicit declaration warning in coreutils-getgrouplist.patch - -* Sat Nov 03 2018 Kevin Fenzi - 8.30-7 -- Also remove Requires pre/post used by info scriptlets. - -* Sat Nov 03 2018 Kevin Fenzi - 8.30-6 -- Remove no longer needed info scriptlets - -* Thu Oct 11 2018 Kamil Dudka - 8.30-5 -- fix heap-based buffer overflow in vasnprintf() (CVE-2018-17942) - -* Thu Jul 12 2018 Fedora Release Engineering - 8.30-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild - -* Tue Jul 10 2018 Kamil Dudka - 8.30-3 -- rename gnulib's renameat2 to renameatu to avoid clash with glibc (#1598518) - -* Wed Jul 04 2018 Kamil Dudka - 8.30-2 -- sync i18n patches with Suse (patch by Bernhard Voelker) - -* Mon Jul 02 2018 Kamil Dudka - 8.30-1 -- new upstream release 8.30 - -* Wed May 30 2018 Kamil Dudka - 8.29-12 -- add provides to coreutils-single to make it a drop-in replacement - -* Mon May 28 2018 Kamil Dudka - 8.29-11 -- ls: increase the allowed abmon width from 5 to 12 (#1577872) -- date, ls: pick strftime fixes from glibc to improve locale support (#1577872) - -* Fri Apr 20 2018 Kamil Dudka - 8.29-10 -- fix crash caused by mistakenly enabled leaf optimization (#1558249) - -* Fri Mar 23 2018 Kamil Dudka - 8.29-9 -- make it possible to install the latest available Adobe Reader RPM for Linux - -* Mon Mar 19 2018 Kamil Dudka - 8.29-8 -- drop BR for bison, which is not used during the build - -* Fri Mar 16 2018 Kamil Dudka - 8.29-7 -- make sure that parse-datetime.{c,y} ends up in debuginfo (#1555079) - -* Tue Mar 06 2018 Kamil Dudka - 8.29-6 -- fix build failure with glibc-2.28 - -* Mon Feb 26 2018 Igor Gnatenko - 8.29-5 -- Remove /bin/* Provides - -* Mon Feb 19 2018 Kamil Dudka - 8.29-4 -- add explicit BR for the gcc compiler - -* Wed Feb 07 2018 Fedora Release Engineering - 8.29-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild - -* Tue Jan 23 2018 Kamil Dudka - 8.29-2 -- doc: warn about following symlinks recursively in chown/chgrp (CVE-2017-18018) -- mv -n: do not overwrite the destination - -* Tue Jan 02 2018 Kamil Dudka - 8.29-1 -- new upstream release 8.29 - -* Tue Nov 07 2017 Igor Gnatenko - 8.28-2 -- Remove very old Provides (mktemp, sh-utils, textwrap, fileutils, stat) - -* Mon Sep 04 2017 Kamil Dudka - 8.28-1 -- new upstream release 8.28 - -* Tue Aug 22 2017 Ville Skyttä - 8.27-16 -- Own the %%{_libexecdir}/coreutils dir - -* Fri Aug 18 2017 Kamil Dudka - 8.27-15 +* Fri Aug 18 2017 Kamil Dudka - 8.27-6 - ptx: fix a possible crash caused by integer overflow (#1482445) - -* Wed Aug 02 2017 Fedora Release Engineering - 8.27-14 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild - -* Fri Jul 28 2017 Igor Gnatenko - 8.27-13 -- Enable separate debuginfo back - -* Wed Jul 26 2017 Kamil Dudka - 8.27-12 -- avoid build failure caused broken RPM code that produces debuginfo packages - -* Wed Jul 26 2017 Fedora Release Engineering - 8.27-11 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild - -* Tue May 30 2017 Sebastian Kisela - 8.27-10 -- doc: mention `setpriv --no-new-privs` feature in runcon info - -* Tue May 16 2017 Kamil Dudka - 8.27-9 -- add coreutils-full provides for coreutils to make it explicitly installable - -* Wed May 03 2017 Kamil Dudka - 8.27-8 -- drop coreutils-overflow.patch no longer needed (#158405) - -* Wed May 03 2017 Kamil Dudka - 8.27-7 -- drop workaround for already fixed rpm-build bug (#1306559) - -* Wed May 03 2017 Kamil Dudka - 8.27-6 -- do not mention a deprecated option in localized man pages -- drop workaround no longer needed for 10 years old rpm-build bug (#246729) -- drop unnecessary uses of %%defattr +- doc: mention `setpriv --no-new-privs` feature in runcon info (#1360903) * Fri Apr 28 2017 Sebastian Kisela - 8.27-5 - tail: revert to polling if a followed directory is replaced (#1283760) diff --git a/rh_i18n_wip.tar.gz b/rh_i18n_wip.tar.gz new file mode 100644 index 0000000..24b7cdc Binary files /dev/null and b/rh_i18n_wip.tar.gz differ diff --git a/sh-utils-2.0.11-dateman.patch b/sh-utils-2.0.11-dateman.patch new file mode 100644 index 0000000..60cdaa6 --- /dev/null +++ b/sh-utils-2.0.11-dateman.patch @@ -0,0 +1,12 @@ +diff -urNp coreutils-5.97-orig/man/date.x coreutils-5.97/man/date.x +--- coreutils-5.97-orig/man/date.x 1999-11-02 15:07:36.000000000 +0100 ++++ coreutils-5.97/man/date.x 2008-10-15 10:13:31.000000000 +0200 +@@ -11,3 +11,8 @@ calendar date, time of day, time zone, day of week, relative time, + relative date, and numbers. An empty string indicates the beginning + of the day. The date string format is more complex than is easily + documented here but is fully described in the info documentation. ++[ENVIRONMENT] ++.TP ++TZ ++Specifies the timezone, unless overridden by command line parameters. ++If neither is specified, the setting from /etc/localtime is used. diff --git a/sources b/sources index 0952ab1..2566cf4 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -SHA512 (coreutils-9.9.tar.xz.sig) = 0a3dfdfa6b4234e2e1d42142269f959bdf3cf8f6605a50270a27eff84dd22588f182121f7dd3eeb04be45f5109d02690215065b3d3b43882874d0e165a1435d0 -SHA512 (coreutils-9.9.tar.xz) = e7b0e59f7732d2c098ea4934014f470248bd5c4764210e9200a698010a8e3b95bbb26e543f0cd73ed5a4b8e1f8cda932c73f39954d68175e4deaa47526610c65 +SHA512 (coreutils-8.27.tar.xz) = abf3280aaa54e9bd5851df0eda2af1de1017ca174633e52d1e592455d46ea0e99812dda46d2f320e979553cef271485d8818c595bba6ed31264511a511c93679 diff --git a/supported_utils b/supported_utils index 6db4fb5..8105ccf 100644 --- a/supported_utils +++ b/supported_utils @@ -1,7 +1,6 @@ %{_bindir}/arch %{_bindir}/b2sum %{_bindir}/basename -%{_bindir}/basenc %{_bindir}/cat %{_bindir}/chgrp %{_bindir}/chmod diff --git a/upstream-key.gpg b/upstream-key.gpg new file mode 100644 index 0000000..dc6dc1d --- /dev/null +++ b/upstream-key.gpg @@ -0,0 +1,123 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.6 (GNU/Linux) + +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 +Ke4= +=zRdO +-----END PGP PUBLIC KEY BLOCK-----